Compare commits

...

54 Commits

Author SHA1 Message Date
Chris Lalancette
700e3c47bf 6.2.0 2021-01-08 19:12:56 +00:00
Chris Lalancette
069b20b7af Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-08 19:12:42 +00:00
Nikolai Morin
bcceecb24b Better documentation for the QoS class (#1508)
* Better documentation for the QoS class

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* PR Review suggestions

Co-authored-by: William Woodall <william+github@osrfoundation.org>
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Shorter brief

Signed-off-by: nnmm <nnmmgit@gmail.com>

Co-authored-by: William Woodall <william+github@osrfoundation.org>
2021-01-07 15:30:38 -08:00
hsgwa
7ed61e52fe Modify excluding callback duration from topic statistics (#1492)
Signed-off-by: hsgwa <hasegawa@isp.co.jp>
2021-01-07 15:04:18 -03:00
Chris Lalancette
85c32a94a5 Make the test of graph users more robust. (#1504)
In particular, we don't know for sure that the graph will only
have 1 user; we just know that it should have *at least* one
user.  So change that check to be more robust.  This also
lets us get rid of the slightly strange call to 'notify_graph_change'
that was being used to cleanup graph users.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-06 10:30:24 -05:00
Chris Lalancette
5821361dcb Make sure to wait for graph change events in test_node_graph. (#1503)
* Make sure to wait for graph change events in test_node_graph.

While debugging something else, I came across this fairly rare
flake in the test_node_graph tests.  Essentially, it may take
some time for node changes to propagate into the graph.  If
the NodeGraph client asks for data before the changes are
in the graph, they may get something they don't expect.  The
fix is to wait for an event on the NodeGraph to happen, and
then look for the data you are interested in.

Before this change, I could get the flake to happen on a loaded
aarch64 system fairly regularly.  After this change, I can no
longer make the flake happen on a loaded system.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-06 08:41:31 -05:00
Josh Langsfeld
b9ef1fedfa Use std compliant non-method std::filesystem::exists function (#1502)
Signed-off-by: Josh Langsfeld <josh.langsfeld@gmail.com>
2021-01-05 11:18:46 -05:00
tomoya
adebda52c5 add timeout to SyncParametersClient methods (#1493)
* add timeout to SyncParametersClient methods

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* update parameter client test with timeout.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* use template thin interface to keep the implementations in library.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* test duration should be long enough not to detect unnecessary timeout

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-12-22 13:13:37 -08:00
Ivan Santiago Paunovic
715b0e9008 Fix wrong test expectations (#1497)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-21 19:33:54 -03:00
Ivan Santiago Paunovic
6257103e76 Goal response callback compatibility shim with deprecation of old signature (#1495)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-21 14:54:02 -03:00
Audrow Nash
543a3c39c1 [rclcpp_action] Add warnings (#1405)
* Add warnings

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Simplify for loop in test_client.cpp

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix conversion warning in test_client static cast to size_t

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix new warnings after rebasing on master

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix shadowing in the benchmark action server

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Static cast goal order to size_t

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Remove unnecessary include

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>
2020-12-18 21:59:34 -08:00
Ivan Santiago Paunovic
62c958be30 Update create_publisher/subscription documentation, clarifying when a parameters interface is required (#1494)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-18 12:05:33 -08:00
Audrow Nash
febe86e6b5 Fix string literal warnings (#1442)
* Add warnings

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix nonliteral string warnings

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix compile error from new logging functions in rclcpp_components

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Use "%s" to make log string evaluation secure

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix logging warnings in rclcpp

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix coding style to pass linter

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Get the c_str of streams

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Remove test to check string logging

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Add in stream logging tests

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>
2020-12-18 09:44:59 -08:00
tomoya
504b082d8b support describe_parameters methods to parameter client. (#1453)
* support describe_parameters methods to parameter client.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-12-14 12:30:54 -05:00
Chris Lalancette
9c62c1c946 6.1.0 2020-12-10 17:13:45 +00:00
Chris Lalancette
5b6e0af339 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-12-10 17:13:33 +00:00
Ivan Santiago Paunovic
c64ba72bbd Add getters to rclcpp::qos and rclcpp::*Policy enum classes (#1467)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-10 12:05:07 -03:00
Chris Lalancette
eddb938aec Change nullptr checks to use ASSERT_TRUE. (#1486)
* Change nullptr checks to use ASSERT_TRUE.

clang static analysis gets a bit confused going through the
gtest macros, so switch from ASSERT_NE to ASSERT_TRUE as
we've done elsewhere.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-12-08 09:06:16 -05:00
tomoya
0dc782aca8 add LifecycleNode::get_transition_graph to match services. (#1472)
* add LifecycleNode::get_transition_graph along with service.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add concrete test cases for get_available_transitions with each primary state.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-12-02 11:25:01 -08:00
Stephen Brawner
ea0ee50318 Adjust logic around finding and erasing guard_condition (#1474)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-30 10:30:26 -08:00
Stephen Brawner
35c73aa61e Update QDs to QL 1 (#1477)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-25 16:34:19 -08:00
Scott K Logan
08963df926 Add benchmarks for components (#1476)
Signed-off-by: Scott K Logan <logans@cottsay.net>
2020-11-25 14:51:59 -08:00
Scott K Logan
f5e35bda86 Add performance tests for parameter transport (#1463)
Note that these tests are written without using
performance_test_fixture. Because the parameter server is running in the
same process, any allocations happening in the spin thread for the
server get picked up by the allocation statistics even though those
functions aren't invoked in the tests.

If we can find a way to turn off the memory tracking on a per-thread
basis, we can enable memory tracking. Until then, leaving the memory
statistics enabled could be misleading.

Signed-off-by: Scott K Logan <logans@cottsay.net>
2020-11-18 20:39:57 -08:00
brawner
a7db1dcca2 Benchmark lifecycle features (#1462)
* Benchmark lifecycle features

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Cleanup

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-18 18:41:29 -08:00
Ivan Santiago Paunovic
ba1056fe63 6.0.0 2020-11-18 21:51:48 +00:00
Ivan Santiago Paunovic
048d9b57c0 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-18 18:50:39 -03:00
brawner
de353f9e45 Reserve vector capacities and use emplace_back for constructing vectors (#1464)
* Reserve vector capacities and use emplace_back for constructing vectors

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Use resize instead of reserve

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Remove push_back

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-17 13:06:58 -08:00
brawner
cba6f20988 Move ownership of shutdown_guard_condition to executors/graph_listener (#1404)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-17 17:40:55 -03:00
Ivan Santiago Paunovic
71a58d40f1 Qos configurability (take 2) (#1465)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-17 17:12:30 -03:00
brawner
add6d61231 [rclcpp_lifecycle] Change uint8_t iterator variables to size_t (#1461)
* Change uint8_t iterator variables to size_t

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Change to unsigned int

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-17 11:22:39 -08:00
Audrow Nash
8c8c268aad Add take_data to Waitable and data to AnyExecutable (#1241)
Signed-off-by: Audrow <audrow.nash@gmail.com>
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-17 11:42:03 -03:00
Ivan Santiago Paunovic
27d1b11647 Revert "Qos configurability (#1408)" (#1459)
This reverts commit 4c5986aa2d.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-16 19:59:27 -03:00
Ivan Santiago Paunovic
4c5986aa2d Qos configurability (#1408)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-16 13:58:45 -03:00
Scott K Logan
dd0f97f179 Add benchmarks for node parameters interface (#1444)
Signed-off-by: Scott K Logan <logans@cottsay.net>
2020-11-12 14:40:43 -08:00
brawner
7d257177e0 Remove allocation from executor::remove_node() (#1448)
* Remove allocation from remove_node

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix uncrustify

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-12 13:21:51 -08:00
Chris Lalancette
a95efa452e Fix test crashes on CentOS 7 (#1449)
* Refactor graph listener tests to work on CentOS.

inject_on_return doesn't work on CentOS.  To fix this, we
do two separate things:

1.  Where applicable, replace calls to inject_on_return with
patch_and_return (which does work).
2.  We were sort of abusing inject_on_return to do partial
initialization for us for some of the tests.  Instead, make
the class under test (GraphListener) have a protected method
that we can call to do initialization.  With this in place,
we can now get rid of the problematic inject_on_return.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-11-11 07:54:41 -05:00
Louise Poubel
06465ba827 Bump rclcpp packages to Quality Level 2 (#1445)
Signed-off-by: Louise Poubel <louise@openrobotics.org>
2020-11-09 17:12:24 -08:00
brawner
5fe6840ad1 Add rclcpp_action action_server benchmarks (#1433)
* Add rclcpp_action action_server benchmarks

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address cancel bug

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix errors

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix clang error

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-05 12:09:11 -08:00
Alejandro Hernández Cordero
361be5e4c0 Added executor benchmark tests (#1413)
* Added executor benchmark tests

Signed-off-by: ahcorde <ahcorde@gmail.com>

* make linters happy

Signed-off-by: ahcorde <ahcorde@gmail.com>

* initialize callback_count

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added feddback

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added add_node and remove_node benchmark tests

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Add/remove node in static_single_thread_executor

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Make linters happy

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added StaticSingleThreadedExecutor add/remove node tests

Signed-off-by: ahcorde <ahcorde@gmail.com>

* make linters happy

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-11-05 13:18:52 +01:00
Chris Lalancette
58bd8d6c21 Add fully-qualified namespace to WeakCallbackGroupsToNodesMap (#1435)
Older versions of MSVC 2019 can't figure out the correct namespace.
Just to keep them happy, add a fully-qualified namespace.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-11-03 12:00:07 -05:00
Ivan Santiago Paunovic
3b04b056e3 5.1.0 2020-11-02 20:10:50 +00:00
Ivan Santiago Paunovic
0aa416e17f Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-02 20:10:28 +00:00
Ivan Santiago Paunovic
79403119e4 rclcpp::Duration constructors might be confusing to users migrating from ROS 1 (#1432)
* Deprecate Duration(rcl_duration_value_t) in favor of static Duration::from_nanoseconds(rcl_duration_value_t)

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-02 16:54:43 -03:00
Chen Lihui
3ae5170b52 Avoid parsing arguments twice (#1415)
Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>
2020-11-02 12:12:07 -03:00
brawner
2309811814 Benchmark rclcpp_action action_client (#1429)
* Benchmark rclcpp_action action_client

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Bump timeout

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-30 10:40:06 -07:00
brawner
aa159a5e8f Add service and client benchmarks (#1425)
* Add service and client benchmarks

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Style

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Uncrustify

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-28 17:53:19 -07:00
brawner
8a8e46d7e9 Set CMakeLists to only use default rmw for benchmarks (#1427)
* Set CMakeLists to only use default rmw for benchmarks

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Add comment

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-28 12:49:53 -07:00
Christophe Bedard
1ddc8c815c Update tracetools' QL in rclcpp's QD (#1428)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2020-10-28 11:24:34 -07:00
Chris Lalancette
579e9d01d6 Add missing locking to the rclcpp_action::ServerBase. (#1421)
This patch actually does 4 related things:

1.  Renames the recursive mutex in the ServerBaseImpl class
to action_server_reentrant_mutex_, which makes it a lot
clearer what it is meant to lock.
2.  Adds some additional error checking where checks were missed.
3.  Adds a lock to publish_status so that the action_server
structure is protected.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-10-26 20:45:03 -04:00
brawner
371074523a Address #1423 by moving rosidl_generate_interfaces call (#1424)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-23 11:36:19 -07:00
brawner
eb7c46ea43 Initial benchmark tests for rclcpp::init/shutdown create/destroy node (#1411)
* Initial benchmark tests for rclcpp::init/shutdown create/destroy node

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Pr feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fixes to cmakelists

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Remove quotes

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Move find_package calls

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Skip create/destroy node for rmw_connext_cpp

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* SKIP TEST in cmakelists

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Add warmup loops

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* remove for loop

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* reset_heap_counters

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Change to make_shared

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-22 15:04:13 -07:00
brawner
0810140e18 Refactor test CMakeLists in prep for benchmarks (#1422)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-22 13:54:12 -07:00
Ivan Santiago Paunovic
5d9db5de74 Add methods in topic and service interface to resolve a name (#1410)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-10-21 18:30:55 -03:00
Audrow Nash
8e5ddb1f81 Update deprecated gtest macros (#1370)
Signed-off-by: Audrow Nash <audrow.nash@gmail.com>
2020-10-20 11:26:45 -07:00
130 changed files with 6996 additions and 1549 deletions

View File

@@ -2,6 +2,107 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6.2.0 (2021-01-08)
------------------
* Better documentation for the QoS class (`#1508 <https://github.com/ros2/rclcpp/issues/1508>`_)
* Modify excluding callback duration from topic statistics (`#1492 <https://github.com/ros2/rclcpp/issues/1492>`_)
* Make the test of graph users more robust. (`#1504 <https://github.com/ros2/rclcpp/issues/1504>`_)
* Make sure to wait for graph change events in test_node_graph. (`#1503 <https://github.com/ros2/rclcpp/issues/1503>`_)
* add timeout to SyncParametersClient methods (`#1493 <https://github.com/ros2/rclcpp/issues/1493>`_)
* Fix wrong test expectations (`#1497 <https://github.com/ros2/rclcpp/issues/1497>`_)
* Update create_publisher/subscription documentation, clarifying when a parameters interface is required (`#1494 <https://github.com/ros2/rclcpp/issues/1494>`_)
* Fix string literal warnings (`#1442 <https://github.com/ros2/rclcpp/issues/1442>`_)
* support describe_parameters methods to parameter client. (`#1453 <https://github.com/ros2/rclcpp/issues/1453>`_)
* Contributors: Audrow Nash, Chris Lalancette, Ivan Santiago Paunovic, Nikolai Morin, hsgwa, tomoya
6.1.0 (2020-12-10)
------------------
* Add getters to rclcpp::qos and rclcpp::Policy enum classes (`#1467 <https://github.com/ros2/rclcpp/issues/1467>`_)
* Change nullptr checks to use ASSERT_TRUE. (`#1486 <https://github.com/ros2/rclcpp/issues/1486>`_)
* Adjust logic around finding and erasing guard_condition (`#1474 <https://github.com/ros2/rclcpp/issues/1474>`_)
* Update QDs to QL 1 (`#1477 <https://github.com/ros2/rclcpp/issues/1477>`_)
* Add performance tests for parameter transport (`#1463 <https://github.com/ros2/rclcpp/issues/1463>`_)
* Contributors: Chris Lalancette, Ivan Santiago Paunovic, Scott K Logan, Stephen Brawner
6.0.0 (2020-11-18)
------------------
* Move ownership of shutdown_guard_condition to executors/graph_listener (`#1404 <https://github.com/ros2/rclcpp/issues/1404>`_)
* Add options to automatically declare qos parameters when creating a publisher/subscription (`#1465 <https://github.com/ros2/rclcpp/issues/1465>`_)
* Add `take_data` to `Waitable` and `data` to `AnyExecutable` (`#1241 <https://github.com/ros2/rclcpp/issues/1241>`_)
* Add benchmarks for node parameters interface (`#1444 <https://github.com/ros2/rclcpp/issues/1444>`_)
* Remove allocation from executor::remove_node() (`#1448 <https://github.com/ros2/rclcpp/issues/1448>`_)
* Fix test crashes on CentOS 7 (`#1449 <https://github.com/ros2/rclcpp/issues/1449>`_)
* Bump rclcpp packages to Quality Level 2 (`#1445 <https://github.com/ros2/rclcpp/issues/1445>`_)
* Added executor benchmark tests (`#1413 <https://github.com/ros2/rclcpp/issues/1413>`_)
* Add fully-qualified namespace to WeakCallbackGroupsToNodesMap (`#1435 <https://github.com/ros2/rclcpp/issues/1435>`_)
* Contributors: Alejandro Hernández Cordero, Audrow Nash, Chris Lalancette, Ivan Santiago Paunovic, Louise Poubel, Scott K Logan, brawner
5.1.0 (2020-11-02)
------------------
* Deprecate Duration(rcl_duration_value_t) in favor of static Duration::from_nanoseconds(rcl_duration_value_t) (`#1432 <https://github.com/ros2/rclcpp/issues/1432>`_)
* Avoid parsing arguments twice in `rclcpp::init_and_remove_ros_arguments` (`#1415 <https://github.com/ros2/rclcpp/issues/1415>`_)
* Add service and client benchmarks (`#1425 <https://github.com/ros2/rclcpp/issues/1425>`_)
* Set CMakeLists to only use default rmw for benchmarks (`#1427 <https://github.com/ros2/rclcpp/issues/1427>`_)
* Update tracetools' QL in rclcpp's QD (`#1428 <https://github.com/ros2/rclcpp/issues/1428>`_)
* Add missing locking to the rclcpp_action::ServerBase. (`#1421 <https://github.com/ros2/rclcpp/issues/1421>`_)
* Initial benchmark tests for rclcpp::init/shutdown create/destroy node (`#1411 <https://github.com/ros2/rclcpp/issues/1411>`_)
* Refactor test CMakeLists in prep for benchmarks (`#1422 <https://github.com/ros2/rclcpp/issues/1422>`_)
* Add methods in topic and service interface to resolve a name (`#1410 <https://github.com/ros2/rclcpp/issues/1410>`_)
* Update deprecated gtest macros (`#1370 <https://github.com/ros2/rclcpp/issues/1370>`_)
* Clear members for StaticExecutorEntitiesCollector to avoid shared_ptr dependency (`#1303 <https://github.com/ros2/rclcpp/issues/1303>`_)
* Increase test timeouts of slow running tests with rmw_connext_cpp (`#1400 <https://github.com/ros2/rclcpp/issues/1400>`_)
* Avoid self dependency that not destoryed (`#1301 <https://github.com/ros2/rclcpp/issues/1301>`_)
* Update maintainers (`#1384 <https://github.com/ros2/rclcpp/issues/1384>`_)
* Add clock qos to node options (`#1375 <https://github.com/ros2/rclcpp/issues/1375>`_)
* Fix NodeOptions copy constructor (`#1376 <https://github.com/ros2/rclcpp/issues/1376>`_)
* Make sure to clean the external client/service handle. (`#1296 <https://github.com/ros2/rclcpp/issues/1296>`_)
* Increase coverage of WaitSetTemplate (`#1368 <https://github.com/ros2/rclcpp/issues/1368>`_)
* Increase coverage of guard_condition.cpp to 100% (`#1369 <https://github.com/ros2/rclcpp/issues/1369>`_)
* Add coverage statement (`#1367 <https://github.com/ros2/rclcpp/issues/1367>`_)
* Tests for LoanedMessage with mocked loaned message publisher (`#1366 <https://github.com/ros2/rclcpp/issues/1366>`_)
* Add unit tests for qos and qos_event files (`#1352 <https://github.com/ros2/rclcpp/issues/1352>`_)
* Finish coverage of publisher API (`#1365 <https://github.com/ros2/rclcpp/issues/1365>`_)
* Finish API coverage on executors. (`#1364 <https://github.com/ros2/rclcpp/issues/1364>`_)
* Add test for ParameterService (`#1355 <https://github.com/ros2/rclcpp/issues/1355>`_)
* Add time API coverage tests (`#1347 <https://github.com/ros2/rclcpp/issues/1347>`_)
* Add timer coverage tests (`#1363 <https://github.com/ros2/rclcpp/issues/1363>`_)
* Add in additional tests for parameter_client.cpp coverage.
* Minor fixes to the parameter_service.cpp file.
* reset rcl_context shared_ptr after calling rcl_init sucessfully (`#1357 <https://github.com/ros2/rclcpp/issues/1357>`_)
* Improved test publisher - zero qos history depth value exception (`#1360 <https://github.com/ros2/rclcpp/issues/1360>`_)
* Covered resolve_use_intra_process (`#1359 <https://github.com/ros2/rclcpp/issues/1359>`_)
* Improve test_subscription_options (`#1358 <https://github.com/ros2/rclcpp/issues/1358>`_)
* Add in more tests for init_options coverage. (`#1353 <https://github.com/ros2/rclcpp/issues/1353>`_)
* Test the remaining node public API (`#1342 <https://github.com/ros2/rclcpp/issues/1342>`_)
* Complete coverage of Parameter and ParameterValue API (`#1344 <https://github.com/ros2/rclcpp/issues/1344>`_)
* Add in more tests for the utilities. (`#1349 <https://github.com/ros2/rclcpp/issues/1349>`_)
* Add in two more tests for expand_topic_or_service_name. (`#1350 <https://github.com/ros2/rclcpp/issues/1350>`_)
* Add tests for node_options API (`#1343 <https://github.com/ros2/rclcpp/issues/1343>`_)
* Add in more coverage for expand_topic_or_service_name. (`#1346 <https://github.com/ros2/rclcpp/issues/1346>`_)
* Test exception in spin_until_future_complete. (`#1345 <https://github.com/ros2/rclcpp/issues/1345>`_)
* Add coverage tests graph_listener (`#1330 <https://github.com/ros2/rclcpp/issues/1330>`_)
* Add in unit tests for the Executor class.
* Allow mimick patching of methods with up to 9 arguments.
* Improve the error messages in the Executor class.
* Add coverage for client API (`#1329 <https://github.com/ros2/rclcpp/issues/1329>`_)
* Increase service coverage (`#1332 <https://github.com/ros2/rclcpp/issues/1332>`_)
* Make more of the static entity collector API private.
* Const-ify more of the static executor.
* Add more tests for the static single threaded executor.
* Many more tests for the static_executor_entities_collector.
* Get one more line of code coverage in memory_strategy.cpp
* Bugfix when adding callback group.
* Fix typos in comments.
* Remove deprecated executor::FutureReturnCode APIs. (`#1327 <https://github.com/ros2/rclcpp/issues/1327>`_)
* Increase coverage of publisher/subscription API (`#1325 <https://github.com/ros2/rclcpp/issues/1325>`_)
* Not finalize guard condition while destructing SubscriptionIntraProcess (`#1307 <https://github.com/ros2/rclcpp/issues/1307>`_)
* Expose qos setting for /rosout (`#1247 <https://github.com/ros2/rclcpp/issues/1247>`_)
* Add coverage for missing API (except executors) (`#1326 <https://github.com/ros2/rclcpp/issues/1326>`_)
* Include topic name in QoS mismatch warning messages (`#1286 <https://github.com/ros2/rclcpp/issues/1286>`_)
* Add coverage tests context functions (`#1321 <https://github.com/ros2/rclcpp/issues/1321>`_)
* Increase coverage of node_interfaces, including with mocking rcl errors (`#1322 <https://github.com/ros2/rclcpp/issues/1322>`_)
* Contributors: Ada-King, Alejandro Hernández Cordero, Audrow Nash, Barry Xu, Chen Lihui, Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, Jorge Perez, Morgan Quigley, brawner
5.0.0 (2020-09-18)
------------------
* Make node_graph::count_graph_users() const (`#1320 <https://github.com/ros2/rclcpp/issues/1320>`_)

View File

@@ -85,6 +85,7 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
src/rclcpp/qos_overriding_options.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp
src/rclcpp/service.cpp

View File

@@ -2,7 +2,7 @@ This document is a declaration of software quality for the `rclcpp` package, bas
# rclcpp Quality Declaration
The package `rclcpp` claims to be in the **Quality Level 3** category.
The package `rclcpp` claims to be in the **Quality Level 1** category when it is used with a **Quality Level 1** middleware.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -82,13 +82,13 @@ The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.
The license for `rclcpp` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Rpr/job/Rpr__rclcpp__ubuntu_focal_amd64/lastCompletedBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Rpr/job/Rpr__rclcpp__ubuntu_focal_amd64/lastCompletedBuild/testReport/rclcpp/copyright/).
## Testing [4]
@@ -121,13 +121,21 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
`rclcpp` has a line coverage `>= 95%`, which is calculated over all directories within `rclcpp` with the exception of the `experimental` directory.
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
`rclcpp` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
The performance tests of `rclcpp` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp/test/benchmark).
System level performance benchmarks that cover features of `rclcpp` can be found at:
* [Benchmarks](http://build.ros2.org/view/Rci/job/Rci__benchmark_ubuntu_focal_amd64/BenchmarkTable/)
* [Performance](http://build.ros2.org/view/Rci/job/Rci__nightly-performance_ubuntu_focal_amd64/lastCompletedBuild/)
Changes that introduce regressions in performance must be adequately justified in order to be accepted and merged.
### Linters and Static Analysis [4.v]
@@ -155,49 +163,49 @@ It also has several test dependencies, which do not affect the resulting quality
The `libstatistics_collector` package provides lightweight aggregation utilities to collect statistics and measure message metrics.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
#### `rcl`
`rcl` a library to support implementation of language specific ROS 2 Client Libraries.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
#### `rcl_yaml_param_parser`
The `rcl_yaml_param_parser` package provides an API that is used to parse YAML configuration files which may be used to configure ROS and specific nodes.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
#### `rcpputils`
The `rcpputils` package provides an API which contains common utilities and data structures useful when programming in C++.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
#### `rcutils`
The `rcutils` package provides an API which contains common utilities and data structures useful when programming in C.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
#### `rmw`
`rmw` is the ROS 2 middleware library.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
#### `statistics_msgs`
The `statistics_msgs` package contains ROS 2 message definitions for reporting statistics for topics and system resources.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
#### `tracetools`
The `tracetools` package provides utilities for instrumenting the code in `rclcpp` so that it may be traced for debugging and performance analysis.
It is **Quality Level 2**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://gitlab.com/ros-tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

@@ -6,4 +6,4 @@ Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) fo
## Quality Declaration
This package claims to be in the **Quality Level 3** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.
This package claims to be in the **Quality Level 1** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

View File

@@ -47,6 +47,7 @@ struct AnyExecutable
// These are used to keep the scope on the containing items
rclcpp::CallbackGroup::SharedPtr callback_group;
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base;
std::shared_ptr<void> data;
};
namespace executor

View File

@@ -248,67 +248,6 @@ public:
void
interrupt_all_sleep_for();
/// Get a handle to the guard condition which is triggered when interrupted.
/**
* This guard condition is triggered any time interrupt_all_wait_sets() is
* called, which may be called by the user, or shutdown().
* And in turn, shutdown() may be called by the user, the destructor of this
* context, or the signal handler if installed and shutdown_on_sigint is true
* for this context.
*
* The first time that this function is called for a given wait set a new guard
* condition will be created and returned; thereafter the same guard condition
* will be returned for the same wait set.
* This mechanism is designed to ensure that the same guard condition is not
* reused across wait sets (e.g., when using multiple executors in the same
* process).
* This method will throw an exception if initialization of the guard
* condition fails.
*
* The returned guard condition needs to be released with the
* release_interrupt_guard_condition() method in order to reclaim resources.
*
* \param[in] wait_set Pointer to the rcl_wait_set_t that will be using the
* resulting guard condition.
* \return Pointer to the guard condition.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
RCLCPP_PUBLIC
rcl_guard_condition_t *
get_interrupt_guard_condition(rcl_wait_set_t * wait_set);
/// Release the previously allocated guard condition which is triggered when interrupted.
/**
* If you previously called get_interrupt_guard_condition() for a given wait
* set to get a interrupt guard condition, then you should call
* release_interrupt_guard_condition() when you're done, to free that
* condition.
* Will throw an exception if get_interrupt_guard_condition() wasn't
* previously called for the given wait set.
*
* After calling this, the pointer returned by get_interrupt_guard_condition()
* for the given wait_set is invalid.
*
* \param[in] wait_set Pointer to the rcl_wait_set_t that was using the
* resulting guard condition.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
* \throws std::runtime_error if a nonexistent wait set is trying to release sigint guard condition.
*/
RCLCPP_PUBLIC
void
release_interrupt_guard_condition(rcl_wait_set_t * wait_set);
/// Nothrow version of release_interrupt_guard_condition(), logs to RCLCPP_ERROR instead.
RCLCPP_PUBLIC
void
release_interrupt_guard_condition(rcl_wait_set_t * wait_set, const std::nothrow_t &) noexcept;
/// Interrupt any blocking executors, or wait sets associated with this context.
RCLCPP_PUBLIC
virtual
void
interrupt_all_wait_sets();
/// Return a singleton instance for the SubContext type, constructing one if necessary.
template<typename SubContext, typename ... Args>
std::shared_ptr<SubContext>
@@ -368,11 +307,6 @@ private:
/// Mutex for protecting the global condition variable.
std::mutex interrupt_mutex_;
/// Mutex to protect sigint_guard_cond_handles_.
std::mutex interrupt_guard_cond_handles_mutex_;
/// Guard conditions for interrupting of associated wait sets on interrupt_all_wait_sets().
std::unordered_map<rcl_wait_set_t *, rcl_guard_condition_t> interrupt_guard_cond_handles_;
/// Keep shared ownership of global vector of weak contexts
std::shared_ptr<WeakContextsWrapper> weak_contexts_;
};

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
@@ -24,15 +25,65 @@
#include "rclcpp/publisher_factory.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rclcpp/detail/qos_parameters.hpp"
#include "rmw/qos_profiles.h"
namespace rclcpp
{
namespace detail
{
/// Create and return a publisher of the given MessageT type.
template<
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>,
typename NodeParametersT,
typename NodeTopicsT>
std::shared_ptr<PublisherT>
create_publisher(
NodeParametersT & node_parameters,
NodeTopicsT & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
{
auto node_topics_interface = rclcpp::node_interfaces::get_node_topics_interface(node_topics);
const rclcpp::QoS & actual_qos = options.qos_overriding_options.get_policy_kinds().size() ?
rclcpp::detail::declare_qos_parameters(
options.qos_overriding_options, node_parameters,
node_topics_interface->resolve_topic_name(topic_name),
qos, rclcpp::detail::PublisherQosParametersTraits{}) :
qos;
// Create the publisher.
auto pub = node_topics_interface->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(options),
actual_qos
);
// Add the publisher to the node topics interface.
node_topics_interface->add_publisher(pub, options.callback_group);
return std::dynamic_pointer_cast<PublisherT>(pub);
}
} // namespace detail
/// Create and return a publisher of the given MessageT type.
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface.
*
* In case `options.qos_overriding_options` is enabling qos parameter overrides,
* NodeT must also have a method called get_node_parameters_interface()
* which returns a shared_ptr to a NodeParametersInterface.
*/
template<
typename MessageT,
@@ -49,21 +100,28 @@ create_publisher(
)
)
{
// Extract the NodeTopicsInterface from the NodeT.
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(node);
return detail::create_publisher<MessageT, AllocatorT, PublisherT>(
node, node, topic_name, qos, options);
}
// Create the publisher.
auto pub = node_topics->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(options),
qos
);
// Add the publisher to the node topics interface.
node_topics->add_publisher(pub, options.callback_group);
return std::dynamic_pointer_cast<PublisherT>(pub);
/// Create and return a publisher of the given MessageT type.
template<
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>>
std::shared_ptr<PublisherT>
create_publisher(
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & node_parameters,
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
{
return detail::create_publisher<MessageT, AllocatorT, PublisherT>(
node_parameters, node_topics, topic_name, qos, options);
}
} // namespace rclcpp

View File

@@ -41,12 +41,115 @@
namespace rclcpp
{
namespace detail
{
template<
typename MessageT,
typename CallbackT,
typename AllocatorT,
typename CallbackMessageT,
typename SubscriptionT,
typename MessageMemoryStrategyT,
typename NodeParametersT,
typename NodeTopicsT>
typename std::shared_ptr<SubscriptionT>
create_subscription(
NodeParametersT & node_parameters,
NodeTopicsT & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
),
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
MessageMemoryStrategyT::create_default()
)
)
{
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics_interface = get_node_topics_interface(node_topics);
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
options,
*node_topics_interface->get_node_base_interface()))
{
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>>
publisher = rclcpp::detail::create_publisher<statistics_msgs::msg::MetricsMessage>(
node_parameters,
node_topics_interface,
options.topic_stats_options.publish_topic,
qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
std::weak_ptr<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
> weak_subscription_topic_stats(subscription_topic_stats);
auto sub_call_back = [weak_subscription_topic_stats]() {
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
if (subscription_topic_stats) {
subscription_topic_stats->publish_message();
}
};
auto node_timer_interface = node_topics_interface->get_node_timers_interface();
auto timer = create_wall_timer(
std::chrono::duration_cast<std::chrono::nanoseconds>(
options.topic_stats_options.publish_period),
sub_call_back,
options.callback_group,
node_topics_interface->get_node_base_interface(),
node_timer_interface
);
subscription_topic_stats->set_publisher_timer(timer);
}
auto factory = rclcpp::create_subscription_factory<MessageT>(
std::forward<CallbackT>(callback),
options,
msg_mem_strat,
subscription_topic_stats
);
const rclcpp::QoS & actual_qos = options.qos_overriding_options.get_policy_kinds().size() ?
rclcpp::detail::declare_qos_parameters(
options.qos_overriding_options, node_parameters,
node_topics_interface->resolve_topic_name(topic_name),
qos, rclcpp::detail::SubscriptionQosParametersTraits{}) :
qos;
auto sub = node_topics_interface->create_subscription(topic_name, factory, actual_qos);
node_topics_interface->add_subscription(sub, options.callback_group);
return std::dynamic_pointer_cast<SubscriptionT>(sub);
}
} // namespace detail
/// Create and return a subscription of the given MessageT type.
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*
* In case `options.qos_overriding_options` is enabling qos parameter overrides,
* NodeT must also have a method called get_node_parameters_interface()
* which returns a shared_ptr to a NodeParametersInterface.
*
* \tparam MessageT
* \tparam CallbackT
* \tparam AllocatorT
@@ -78,7 +181,7 @@ template<
typename NodeT>
typename std::shared_ptr<SubscriptionT>
create_subscription(
NodeT && node,
NodeT & node,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
@@ -90,68 +193,45 @@ create_subscription(
)
)
{
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(std::forward<NodeT>(node));
return rclcpp::detail::create_subscription<
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
node, node, topic_name, qos, std::forward<CallbackT>(callback), options, msg_mem_strat);
}
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
options,
*node_topics->get_node_base_interface()))
{
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>> publisher =
create_publisher<statistics_msgs::msg::MetricsMessage>(
node,
options.topic_stats_options.publish_topic,
qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
>(node_topics->get_node_base_interface()->get_name(), publisher);
std::weak_ptr<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
> weak_subscription_topic_stats(subscription_topic_stats);
auto sub_call_back = [weak_subscription_topic_stats]() {
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
if (subscription_topic_stats) {
subscription_topic_stats->publish_message();
}
};
auto node_timer_interface = node_topics->get_node_timers_interface();
auto timer = create_wall_timer(
std::chrono::duration_cast<std::chrono::nanoseconds>(
options.topic_stats_options.publish_period),
sub_call_back,
options.callback_group,
node_topics->get_node_base_interface(),
node_timer_interface
);
subscription_topic_stats->set_publisher_timer(timer);
}
auto factory = rclcpp::create_subscription_factory<MessageT>(
std::forward<CallbackT>(callback),
options,
msg_mem_strat,
subscription_topic_stats
);
auto sub = node_topics->create_subscription(topic_name, factory, qos);
node_topics->add_subscription(sub, options.callback_group);
return std::dynamic_pointer_cast<SubscriptionT>(sub);
/// Create and return a subscription of the given MessageT type.
/**
* See \ref create_subscription().
*/
template<
typename MessageT,
typename CallbackT,
typename AllocatorT = std::allocator<void>,
typename CallbackMessageT =
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
CallbackMessageT,
AllocatorT
>>
typename std::shared_ptr<SubscriptionT>
create_subscription(
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & node_parameters,
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
),
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
MessageMemoryStrategyT::create_default()
)
)
{
return rclcpp::detail::create_subscription<
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
node_parameters, node_topics, topic_name, qos,
std::forward<CallbackT>(callback), options, msg_mem_strat);
}
} // namespace rclcpp

View File

@@ -0,0 +1,326 @@
// Copyright 2020 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 RCLCPP__DETAIL__QOS_PARAMETERS_HPP_
#define RCLCPP__DETAIL__QOS_PARAMETERS_HPP_
#include <algorithm>
#include <array>
#include <functional>
#include <initializer_list>
#include <map>
#include <string>
#include <type_traits>
#include <vector>
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcpputils/pointer_traits.hpp"
#include "rmw/qos_string_conversions.h"
#include "rclcpp/duration.hpp"
#include "rclcpp/node_interfaces/get_node_parameters_interface.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
#include "rclcpp/qos_overriding_options.hpp"
namespace rclcpp
{
namespace detail
{
/// \internal Trait used to specialize `declare_qos_parameters()` for publishers.
struct PublisherQosParametersTraits
{
static constexpr const char * entity_type() {return "publisher";}
static constexpr auto allowed_policies()
{
return std::array<::rclcpp::QosPolicyKind, 9> {
QosPolicyKind::AvoidRosNamespaceConventions,
QosPolicyKind::Deadline,
QosPolicyKind::Durability,
QosPolicyKind::History,
QosPolicyKind::Depth,
QosPolicyKind::Lifespan,
QosPolicyKind::Liveliness,
QosPolicyKind::LivelinessLeaseDuration,
QosPolicyKind::Reliability,
};
}
};
/// \internal Trait used to specialize `declare_qos_parameters()` for subscriptions.
struct SubscriptionQosParametersTraits
{
static constexpr const char * entity_type() {return "subscription";}
static constexpr auto allowed_policies()
{
return std::array<::rclcpp::QosPolicyKind, 8> {
QosPolicyKind::AvoidRosNamespaceConventions,
QosPolicyKind::Deadline,
QosPolicyKind::Durability,
QosPolicyKind::History,
QosPolicyKind::Depth,
QosPolicyKind::Liveliness,
QosPolicyKind::LivelinessLeaseDuration,
QosPolicyKind::Reliability,
};
}
};
/// \internal Returns the given `policy` of the profile `qos` converted to a parameter value.
inline
::rclcpp::ParameterValue
get_default_qos_param_value(rclcpp::QosPolicyKind policy, const rclcpp::QoS & qos);
/// \internal Modify the given `policy` in `qos` to be `value`.
inline
void
apply_qos_override(
rclcpp::QosPolicyKind policy, rclcpp::ParameterValue value, rclcpp::QoS & qos);
inline
rclcpp::ParameterValue
declare_parameter_or_get(
rclcpp::node_interfaces::NodeParametersInterface & parameters_interface,
const std::string & param_name,
rclcpp::ParameterValue param_value,
rcl_interfaces::msg::ParameterDescriptor descriptor)
{
try {
return parameters_interface.declare_parameter(
param_name, param_value, descriptor);
} catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) {
return parameters_interface.get_parameter(param_name).get_parameter_value();
}
}
/// \internal Declare QoS parameters for the given entity.
/**
* \tparam NodeT Node pointer or reference type.
* \tparam EntityQosParametersTraits A class with two static methods: `entity_type()` and
* `allowed_policies()`. See `PublisherQosParametersTraits` and `SubscriptionQosParametersTraits`.
* \param options User provided options that indicate if QoS parameter overrides should be
* declared or not, which policy can have overrides, and optionally a callback to validate the profile.
* \param node Parameters will be declared using this node.
* \param topic_name Name of the topic of the entity.
* \param default_qos User provided qos. It will be used as a default for the parameters declared.
* \return qos profile based on the user provided parameter overrides.
*/
template<typename NodeT, typename EntityQosParametersTraits>
std::enable_if_t<
rclcpp::node_interfaces::has_node_parameters_interface<
decltype(std::declval<typename rcpputils::remove_pointer<NodeT>::type>())>::value ||
std::is_same<typename std::decay_t<NodeT>,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value,
rclcpp::QoS>
declare_qos_parameters(
const ::rclcpp::QosOverridingOptions & options,
NodeT & node,
const std::string & topic_name,
const ::rclcpp::QoS & default_qos,
EntityQosParametersTraits)
{
auto & parameters_interface = *rclcpp::node_interfaces::get_node_parameters_interface(node);
std::string param_prefix;
const auto & id = options.get_id();
{
std::ostringstream oss{"qos_overrides.", std::ios::ate};
oss << topic_name << "." << EntityQosParametersTraits::entity_type();
if (!id.empty()) {
oss << "_" << id;
}
oss << ".";
param_prefix = oss.str();
}
std::string param_description_suffix;
{
std::ostringstream oss{"} for ", std::ios::ate};
oss << EntityQosParametersTraits::entity_type() << " {" << topic_name << "}";
if (!id.empty()) {
oss << " with id {" << id << "}";
}
param_description_suffix = oss.str();
}
rclcpp::QoS qos = default_qos;
for (auto policy : EntityQosParametersTraits::allowed_policies()) {
if (
std::count(options.get_policy_kinds().begin(), options.get_policy_kinds().end(), policy))
{
std::ostringstream param_name{param_prefix, std::ios::ate};
param_name << qos_policy_kind_to_cstr(policy);
std::ostringstream param_desciption{"qos policy {", std::ios::ate};
param_desciption << qos_policy_kind_to_cstr(policy) << param_description_suffix;
rcl_interfaces::msg::ParameterDescriptor descriptor{};
descriptor.description = param_desciption.str();
descriptor.read_only = true;
auto value = declare_parameter_or_get(
parameters_interface, param_name.str(),
get_default_qos_param_value(policy, qos), descriptor);
::rclcpp::detail::apply_qos_override(policy, value, qos);
}
}
const auto & validation_callback = options.get_validation_callback();
if (validation_callback) {
auto result = validation_callback(qos);
if (!result.successful) {
throw rclcpp::exceptions::InvalidQosOverridesException{
"validation callback failed: " + result.reason};
}
}
return qos;
}
// TODO(ivanpauno): This overload cannot declare the QoS parameters, as a node parameters interface
// was not provided.
template<typename NodeT, typename EntityQosParametersTraits>
std::enable_if_t<
!(rclcpp::node_interfaces::has_node_parameters_interface<
decltype(std::declval<typename rcpputils::remove_pointer<NodeT>::type>())>::value ||
std::is_same<typename std::decay_t<NodeT>,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value),
rclcpp::QoS>
declare_qos_parameters(
const ::rclcpp::QosOverridingOptions & options,
NodeT &,
const std::string &,
const ::rclcpp::QoS & default_qos,
EntityQosParametersTraits)
{
if (options.get_policy_kinds().size()) {
std::runtime_error exc{
"passed non-default qos overriding options without providing a parameters interface"};
throw exc;
}
return default_qos;
}
/// \internal Helper function to get a rmw qos policy value from a string.
#define RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING( \
kind_lower, kind_upper, parameter_value, rclcpp_qos) \
do { \
auto policy_string = (parameter_value).get<std::string>(); \
auto policy_value = rmw_qos_ ## kind_lower ## _policy_from_str(policy_string.c_str()); \
if (RMW_QOS_POLICY_ ## kind_upper ## _UNKNOWN == policy_value) { \
throw std::invalid_argument{"unknown QoS policy " #kind_lower " value: " + policy_string}; \
} \
((rclcpp_qos).kind_lower)(policy_value); \
} while (0)
inline
void
apply_qos_override(
rclcpp::QosPolicyKind policy, rclcpp::ParameterValue value, rclcpp::QoS & qos)
{
switch (policy) {
case QosPolicyKind::AvoidRosNamespaceConventions:
qos.avoid_ros_namespace_conventions(value.get<bool>());
break;
case QosPolicyKind::Deadline:
qos.deadline(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
break;
case QosPolicyKind::Durability:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
durability, DURABILITY, value, qos);
break;
case QosPolicyKind::History:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
history, HISTORY, value, qos);
break;
case QosPolicyKind::Depth:
qos.get_rmw_qos_profile().depth = static_cast<size_t>(value.get<int64_t>());
break;
case QosPolicyKind::Lifespan:
qos.lifespan(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
break;
case QosPolicyKind::Liveliness:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
liveliness, LIVELINESS, value, qos);
break;
case QosPolicyKind::LivelinessLeaseDuration:
qos.liveliness_lease_duration(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
break;
case QosPolicyKind::Reliability:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
reliability, RELIABILITY, value, qos);
break;
default:
throw std::invalid_argument{"unknown QosPolicyKind"};
}
}
/// Convert `rmw_time_t` to `int64_t` that can be used as a parameter value.
inline
int64_t
rmw_duration_to_int64_t(rmw_time_t rmw_duration)
{
return ::rclcpp::Duration(
static_cast<int32_t>(rmw_duration.sec),
static_cast<uint32_t>(rmw_duration.nsec)
).nanoseconds();
}
/// \internal Throw an exception if `policy_value_stringified` is NULL.
inline
const char *
check_if_stringified_policy_is_null(const char * policy_value_stringified, QosPolicyKind kind)
{
if (!policy_value_stringified) {
std::ostringstream oss{"unknown value for policy kind {", std::ios::ate};
oss << kind << "}";
throw std::invalid_argument{oss.str()};
}
return policy_value_stringified;
}
inline
::rclcpp::ParameterValue
get_default_qos_param_value(rclcpp::QosPolicyKind kind, const rclcpp::QoS & qos)
{
using ParameterValue = ::rclcpp::ParameterValue;
const auto & rmw_qos = qos.get_rmw_qos_profile();
switch (kind) {
case QosPolicyKind::AvoidRosNamespaceConventions:
return ParameterValue(rmw_qos.avoid_ros_namespace_conventions);
case QosPolicyKind::Deadline:
return ParameterValue(rmw_duration_to_int64_t(rmw_qos.deadline));
case QosPolicyKind::Durability:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_durability_policy_to_str(rmw_qos.durability), kind));
case QosPolicyKind::History:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_history_policy_to_str(rmw_qos.history), kind));
case QosPolicyKind::Depth:
return ParameterValue(static_cast<int64_t>(rmw_qos.depth));
case QosPolicyKind::Lifespan:
return ParameterValue(rmw_duration_to_int64_t(rmw_qos.lifespan));
case QosPolicyKind::Liveliness:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_liveliness_policy_to_str(rmw_qos.liveliness), kind));
case QosPolicyKind::LivelinessLeaseDuration:
return ParameterValue(rmw_duration_to_int64_t(rmw_qos.liveliness_lease_duration));
case QosPolicyKind::Reliability:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_reliability_policy_to_str(rmw_qos.reliability), kind));
default:
throw std::invalid_argument{"unknown QoS policy kind"};
}
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__QOS_PARAMETERS_HPP_

View File

@@ -38,10 +38,14 @@ public:
*/
Duration(int32_t seconds, uint32_t nanoseconds);
// This constructor matches any numeric value - ints or floats.
/// Construct duration from the specified nanoseconds.
[[deprecated(
"Use Duration::from_nanoseconds instead or std::chrono_literals. For example:"
"rclcpp::Duration::from_nanoseconds(int64_variable);"
"rclcpp::Duration(0ns);")]]
explicit Duration(rcl_duration_value_t nanoseconds);
// This constructor matches std::chrono::nanoseconds.
/// Construct duration from the specified std::chrono::nanoseconds.
explicit Duration(std::chrono::nanoseconds nanoseconds);
// This constructor matches any std::chrono value other than nanoseconds
@@ -129,6 +133,13 @@ public:
static Duration
from_seconds(double seconds);
/// Create a duration object from an integer number representing nanoseconds
static Duration
from_nanoseconds(rcl_duration_value_t nanoseconds);
static Duration
from_rmw_time(rmw_time_t duration);
/// Convert Duration into a std::chrono::Duration.
template<class DurationT>
DurationT
@@ -143,6 +154,8 @@ public:
private:
rcl_duration_t rcl_duration_;
Duration() = default;
};
} // namespace rclcpp

View File

@@ -282,6 +282,13 @@ class ParameterModifiedInCallbackException : public std::runtime_error
using std::runtime_error::runtime_error;
};
/// Thrown if the QoS overrides provided aren't valid.
class InvalidQosOverridesException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
} // namespace exceptions
} // namespace rclcpp

View File

@@ -31,6 +31,7 @@
#include "rcl/wait.h"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/executor_options.hpp"
#include "rclcpp/future_return_code.hpp"
#include "rclcpp/memory_strategies.hpp"
@@ -525,6 +526,8 @@ protected:
/// Guard condition for signaling the rmw layer to wake up for special events.
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
std::shared_ptr<rclcpp::GuardCondition> shutdown_guard_condition_;
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();

View File

@@ -72,9 +72,19 @@ public:
void
fini();
/// Execute the waitable.
RCLCPP_PUBLIC
void
execute() override;
execute(std::shared_ptr<void> & data) override;
/// Take the data so that it can be consumed with `execute`.
/**
* For `StaticExecutorEntitiesCollector`, this always return `nullptr`.
* \sa rclcpp::Waitable::take_data()
*/
RCLCPP_PUBLIC
std::shared_ptr<void>
take_data() override;
/// Function to add_handles_to_wait_set and wait for work and
/**

View File

@@ -207,7 +207,7 @@ public:
sub_ids.take_shared_subscriptions.size() <= 1)
{
// There is at maximum 1 buffer that does not require ownership.
// So we this case is equivalent to all the buffers requiring ownership
// So this case is equivalent to all the buffers requiring ownership
// Merge the two vector of ids into a unique one
std::vector<uint64_t> concatenated_vector(sub_ids.take_shared_subscriptions);

View File

@@ -18,7 +18,9 @@
#include <rmw/rmw.h>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
@@ -115,13 +117,31 @@ public:
bool
is_ready(rcl_wait_set_t * wait_set)
{
(void)wait_set;
(void) wait_set;
return buffer_->has_data();
}
void execute()
std::shared_ptr<void>
take_data()
{
execute_impl<CallbackMessageT>();
ConstMessageSharedPtr shared_msg;
MessageUniquePtr unique_msg;
if (any_callback_.use_take_shared_method()) {
shared_msg = buffer_->consume_shared();
} else {
unique_msg = buffer_->consume_unique();
}
return std::static_pointer_cast<void>(
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
std::pair<ConstMessageSharedPtr, MessageUniquePtr>(
shared_msg, std::move(unique_msg)))
);
}
void execute(std::shared_ptr<void> & data)
{
execute_impl<CallbackMessageT>(data);
}
void
@@ -154,26 +174,35 @@ private:
template<typename T>
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl()
execute_impl(std::shared_ptr<void> & data)
{
(void)data;
throw std::runtime_error("Subscription intra-process can't handle serialized messages");
}
template<class T>
typename std::enable_if<!std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl()
execute_impl(std::shared_ptr<void> & data)
{
if (!data) {
throw std::runtime_error("'data' is empty");
}
rmw_message_info_t msg_info;
msg_info.publisher_gid = {0, {0}};
msg_info.from_intra_process = true;
auto shared_ptr = std::static_pointer_cast<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
data);
if (any_callback_.use_take_shared_method()) {
ConstMessageSharedPtr msg = buffer_->consume_shared();
any_callback_.dispatch_intra_process(msg, msg_info);
ConstMessageSharedPtr shared_msg = shared_ptr->first;
any_callback_.dispatch_intra_process(shared_msg, msg_info);
} else {
MessageUniquePtr msg = buffer_->consume_unique();
any_callback_.dispatch_intra_process(std::move(msg), msg_info);
MessageUniquePtr unique_msg = std::move(shared_ptr->second);
any_callback_.dispatch_intra_process(std::move(unique_msg), msg_info);
}
shared_ptr.reset();
}
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;

View File

@@ -56,8 +56,12 @@ public:
virtual bool
is_ready(rcl_wait_set_t * wait_set) = 0;
virtual
std::shared_ptr<void>
take_data() = 0;
virtual void
execute() = 0;
execute(std::shared_ptr<void> & data) = 0;
virtual bool
use_take_shared_method() const = 0;

View File

@@ -63,7 +63,7 @@ class GraphListener : public std::enable_shared_from_this<GraphListener>
{
public:
RCLCPP_PUBLIC
explicit GraphListener(std::shared_ptr<rclcpp::Context> parent_context);
explicit GraphListener(const rclcpp::Context::SharedPtr & parent_context);
RCLCPP_PUBLIC
virtual ~GraphListener();
@@ -160,14 +160,23 @@ protected:
void
run_loop();
RCLCPP_PUBLIC
void
init_wait_set();
RCLCPP_PUBLIC
void
cleanup_wait_set();
private:
RCLCPP_DISABLE_COPY(GraphListener)
/** \internal */
void
__shutdown(bool);
__shutdown();
rclcpp::Context::WeakPtr parent_context_;
std::weak_ptr<rclcpp::Context> weak_parent_context_;
std::shared_ptr<rcl_context_t> rcl_parent_context_;
std::thread listener_thread_;
bool is_started_;
@@ -179,7 +188,6 @@ private:
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> node_graph_interfaces_;
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
rcl_guard_condition_t * shutdown_guard_condition_;
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
};

View File

@@ -118,6 +118,10 @@ public:
bool
get_enable_topic_statistics_default() const override;
std::string
resolve_topic_or_service_name(
const std::string & name, bool is_service, bool only_expand = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeBase)

View File

@@ -163,6 +163,13 @@ public:
virtual
bool
get_enable_topic_statistics_default() const = 0;
/// Expand and remap a given topic or service name.
RCLCPP_PUBLIC
virtual
std::string
resolve_topic_or_service_name(
const std::string & name, bool is_service, bool only_expand = false) const = 0;
};
} // namespace node_interfaces

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
#include <string>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/macros.hpp"
@@ -53,6 +55,10 @@ public:
rclcpp::ServiceBase::SharedPtr service_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) override;
RCLCPP_PUBLIC
std::string
resolve_service_name(const std::string & name, bool only_expand = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeServices)

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
#include <string>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/macros.hpp"
@@ -49,6 +51,12 @@ public:
add_service(
rclcpp::ServiceBase::SharedPtr service_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) = 0;
/// Get the remapped and expanded service name given a input name.
RCLCPP_PUBLIC
virtual
std::string
resolve_service_name(const std::string & name, bool only_expand = false) const = 0;
};
} // namespace node_interfaces

View File

@@ -81,6 +81,10 @@ public:
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface() const override;
RCLCPP_PUBLIC
std::string
resolve_topic_name(const std::string & name, bool only_expand = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeTopics)

View File

@@ -86,6 +86,12 @@ public:
virtual
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface() const = 0;
/// Get a remapped and expanded topic name given an input name.
RCLCPP_PUBLIC
virtual
std::string
resolve_topic_name(const std::string & name, bool only_expand = false) const = 0;
};
} // namespace node_interfaces

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__PARAMETER_CLIENT_HPP_
#define RCLCPP__PARAMETER_CLIENT_HPP_
#include <functional>
#include <future>
#include <memory>
#include <string>
#include <utility>
@@ -120,6 +122,14 @@ public:
void(std::shared_future<std::vector<rclcpp::Parameter>>)
> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>
describe_parameters(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>)
> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rclcpp::ParameterType>>
get_parameter_types(
@@ -332,9 +342,17 @@ public:
qos_profile);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rclcpp::Parameter>
get_parameters(const std::vector<std::string> & parameter_names);
get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return get_parameters(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
bool
@@ -378,23 +396,67 @@ public:
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return describe_parameters(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rclcpp::ParameterType>
get_parameter_types(const std::vector<std::string> & parameter_names);
get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return get_parameter_types(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(const std::vector<rclcpp::Parameter> & parameters);
set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return set_parameters(
parameters,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return set_parameters_atomically(
parameters,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
rcl_interfaces::msg::ListParametersResult
list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth);
uint64_t depth,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return list_parameters(
parameter_prefixes,
depth,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
template<typename CallbackT>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
@@ -437,6 +499,44 @@ public:
return async_parameters_client_->wait_for_service(timeout);
}
protected:
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rclcpp::ParameterType>
get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth,
std::chrono::nanoseconds timeout);
private:
rclcpp::Executor::SharedPtr executor_;
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_;

View File

@@ -26,6 +26,7 @@
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/qos_overriding_options.hpp"
namespace rclcpp
{
@@ -50,6 +51,8 @@ struct PublisherOptionsBase
/// Optional RMW implementation specific payload to be used during creation of the publisher.
std::shared_ptr<rclcpp::detail::RMWImplementationSpecificPublisherPayload>
rmw_implementation_payload = nullptr;
QosOverridingOptions qos_overriding_options;
};
/// Structure containing optional configuration for Publishers.

View File

@@ -30,6 +30,38 @@ namespace rclcpp
RCLCPP_PUBLIC
std::string qos_policy_name_from_kind(rmw_qos_policy_kind_t policy_kind);
enum class HistoryPolicy
{
KeepLast = RMW_QOS_POLICY_HISTORY_KEEP_LAST,
KeepAll = RMW_QOS_POLICY_HISTORY_KEEP_ALL,
SystemDefault = RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_HISTORY_UNKNOWN,
};
enum class ReliabilityPolicy
{
BestEffort = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
Reliable = RMW_QOS_POLICY_RELIABILITY_RELIABLE,
SystemDefault = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_RELIABILITY_UNKNOWN,
};
enum class DurabilityPolicy
{
Volatile = RMW_QOS_POLICY_DURABILITY_VOLATILE,
TransientLocal = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
SystemDefault = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_DURABILITY_UNKNOWN,
};
enum class LivelinessPolicy
{
Automatic = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
ManualByTopic = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
SystemDefault = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_LIVELINESS_UNKNOWN,
};
/// QoS initialization values, cannot be created directly, use KeepAll or KeepLast instead.
struct RCLCPP_PUBLIC QoSInitialization
{
@@ -58,10 +90,32 @@ struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
};
/// Encapsulation of Quality of Service settings.
/**
* Quality of Service settings control the behavior of publishers, subscriptions,
* and other entities, and includes things like how data is sent or resent,
* how data is buffered on the publishing and subscribing side, and other things.
* See:
* <a href="https://index.ros.org/doc/ros2/Concepts/About-Quality-of-Service-Settings">
* https://index.ros.org/doc/ros2/Concepts/About-Quality-of-Service-Settings
* </a>
*/
class RCLCPP_PUBLIC QoS
{
public:
/// Constructor which allows you to construct a QoS by giving the only required settings.
/// Create a QoS by specifying only the history policy and history depth.
/**
* When using the default initial profile, the defaults will include:
*
* - \link rclcpp::ReliabilityPolicy::Reliable ReliabilityPolicy::Reliable\endlink
* - \link rclcpp::DurabilityPolicy::Volatile DurabilityPolicy::Volatile\endlink
*
* See rmw_qos_profile_default for a full list of default settings.
* If some other rmw_qos_profile_t is passed to initial_profile, then the defaults will derive from
* that profile instead.
*
* \param[in] qos_initialization Specifies history policy and history depth.
* \param[in] initial_profile The rmw_qos_profile_t instance on which to base the default settings.
*/
explicit
QoS(
const QoSInitialization & qos_initialization,
@@ -69,7 +123,11 @@ public:
/// Conversion constructor to ease construction in the common case of just specifying depth.
/**
* Convenience constructor, equivalent to QoS(KeepLast(history_depth)).
* This is a convenience constructor that calls QoS(KeepLast(history_depth)).
*
* \param[in] history_depth How many messages can be queued when publishing
* with a Publisher, or how many messages can be queued before being replaced
* by a Subscription.
*/
// cppcheck-suppress noExplicitConstructor
QoS(size_t history_depth); // NOLINT(runtime/explicit): conversion constructor
@@ -82,6 +140,10 @@ public:
const rmw_qos_profile_t &
get_rmw_qos_profile() const;
/// Set the history policy.
QoS &
history(HistoryPolicy history);
/// Set the history policy.
QoS &
history(rmw_qos_history_policy_t history);
@@ -98,6 +160,10 @@ public:
QoS &
reliability(rmw_qos_reliability_policy_t reliability);
/// Set the reliability setting.
QoS &
reliability(ReliabilityPolicy reliability);
/// Set the reliability setting to reliable.
QoS &
reliable();
@@ -110,6 +176,10 @@ public:
QoS &
durability(rmw_qos_durability_policy_t durability);
/// Set the durability setting.
QoS &
durability(DurabilityPolicy durability);
/// Set the durability setting to volatile.
/**
* Note that this cannot be named `volatile` because it is a C++ keyword.
@@ -141,6 +211,10 @@ public:
QoS &
liveliness(rmw_qos_liveliness_policy_t liveliness);
/// Set the liveliness setting.
QoS &
liveliness(LivelinessPolicy liveliness);
/// Set the liveliness_lease_duration setting.
QoS &
liveliness_lease_duration(rmw_time_t liveliness_lease_duration);
@@ -153,6 +227,42 @@ public:
QoS &
avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions);
/// Get the history qos policy.
HistoryPolicy
history() const;
/// Get the history depth.
size_t
depth() const;
/// Get the reliability policy.
ReliabilityPolicy
reliability() const;
/// Get the durability policy.
DurabilityPolicy
durability() const;
/// Get the deadline duration setting.
rclcpp::Duration
deadline() const;
/// Get the lifespan duration setting.
rclcpp::Duration
lifespan() const;
/// Get the liveliness policy.
LivelinessPolicy
liveliness() const;
/// Get the liveliness lease duration setting.
rclcpp::Duration
liveliness_lease_duration() const;
/// Get the `avoid ros namespace convention` setting.
bool
avoid_ros_namespace_conventions() const;
private:
rmw_qos_profile_t rmw_qos_profile_;
};

View File

@@ -16,6 +16,8 @@
#define RCLCPP__QOS_EVENT_HPP_
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>
#include "rcl/error_handling.h"
@@ -131,21 +133,31 @@ public:
}
}
/// Execute any entities of the Waitable that are ready.
void
execute() override
/// Take data so that the callback cannot be scheduled again
std::shared_ptr<void>
take_data() override
{
EventCallbackInfoT callback_info;
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't take event info: %s", rcl_get_error_string().str);
return;
return nullptr;
}
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
}
event_callback_(callback_info);
/// Execute any entities of the Waitable that are ready.
void
execute(std::shared_ptr<void> & data) override
{
if (!data) {
throw std::runtime_error("'data' is empty");
}
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
event_callback_(*callback_ptr);
callback_ptr.reset();
}
private:

View File

@@ -0,0 +1,154 @@
// Copyright 2020 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 RCLCPP__QOS_OVERRIDING_OPTIONS_HPP_
#define RCLCPP__QOS_OVERRIDING_OPTIONS_HPP_
#include <functional>
#include <initializer_list>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "rclcpp/qos.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rmw/qos_policy_kind.h"
namespace rclcpp
{
enum class RCLCPP_PUBLIC_TYPE QosPolicyKind
{
AvoidRosNamespaceConventions = RMW_QOS_POLICY_AVOID_ROS_NAMESPACE_CONVENTIONS,
Deadline = RMW_QOS_POLICY_DEADLINE,
Depth = RMW_QOS_POLICY_DEPTH,
Durability = RMW_QOS_POLICY_DURABILITY,
History = RMW_QOS_POLICY_HISTORY,
Lifespan = RMW_QOS_POLICY_LIFESPAN,
Liveliness = RMW_QOS_POLICY_LIVELINESS,
LivelinessLeaseDuration = RMW_QOS_POLICY_LIVELINESS_LEASE_DURATION,
Reliability = RMW_QOS_POLICY_RELIABILITY,
Invalid = RMW_QOS_POLICY_INVALID,
};
RCLCPP_PUBLIC
const char *
qos_policy_kind_to_cstr(const QosPolicyKind & qpk);
RCLCPP_PUBLIC
std::ostream &
operator<<(std::ostream & os, const QosPolicyKind & qpk);
using QosCallbackResult = rcl_interfaces::msg::SetParametersResult;
using QosCallback = std::function<QosCallbackResult(const rclcpp::QoS &)>;
namespace detail
{
// forward declare
template<typename T>
class QosParameters;
}
/// Options that are passed in subscription/publisher constructor to specify QoSConfigurability.
/**
* This options struct allows configuring:
* - Which policy kinds will have declared parameters.
* - An optional callback, that will be called to validate the final qos profile.
* - An optional id. In the case that different qos are desired for two publishers/subscriptions in
* the same topic, this id will allow disambiguating them.
*
* Example parameter file:
*
* ```yaml
* my_node_name:
* ros__parameters:
* qos_overrides:
* /my/topic/name:
* publisher: # publisher without provided id
* reliability: reliable
* depth: 100
* publisher_my_id: # publisher with `id="my_id"
* reliability: reliable
* depth: 10
* ```
*/
class QosOverridingOptions
{
public:
/// Default constructor, no overrides allowed.
RCLCPP_PUBLIC
QosOverridingOptions() = default;
/// Construct passing a list of QoS policies and a verification callback.
/**
* This constructor is implicit, e.g.:
* ```cpp
* node->create_publisher(
* "topic_name",
* default_qos_profile,
* {
* {QosPolicyKind::Reliability},
* [] (auto && qos) {return check_qos_validity(qos)},
* "my_id"
* });
* ```
* \param policy_kinds list of policy kinds that will be reconfigurable.
* \param validation_callback callbak that will be called to validate the validity of
* the qos profile set by the user.
* \param id id of the entity.
*/
RCLCPP_PUBLIC
QosOverridingOptions(
std::initializer_list<QosPolicyKind> policy_kinds,
QosCallback validation_callback = nullptr,
std::string id = {});
RCLCPP_PUBLIC
const std::string &
get_id() const;
RCLCPP_PUBLIC
const std::vector<QosPolicyKind> &
get_policy_kinds() const;
RCLCPP_PUBLIC
const QosCallback &
get_validation_callback() const;
/// Construct passing a list of QoS policies and a verification callback.
/**
* Same as `QosOverridingOptions` constructor, but only declares the default policies:
*
* History, Depth, Reliability.
*/
RCLCPP_PUBLIC
static
QosOverridingOptions
with_default_policies(QosCallback validation_callback = nullptr, std::string id = {});
private:
/// \internal Id of the entity requesting to create parameters.
std::string id_;
/// \internal Policy kinds that are allowed to be reconfigured.
std::vector<QosPolicyKind> policy_kinds_;
/// \internal Validation callback that will be called to verify the profile.
QosCallback validation_callback_;
};
} // namespace rclcpp
#endif // RCLCPP__QOS_OVERRIDING_OPTIONS_HPP_

View File

@@ -277,11 +277,18 @@ public:
return;
}
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
std::chrono::time_point<std::chrono::system_clock> now;
if (subscription_topic_statistics_) {
// get current time before executing callback to
// exclude callback duration from topic statistics result.
now = std::chrono::system_clock::now();
}
any_callback_.dispatch(typed_message, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now());
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
}

View File

@@ -26,6 +26,7 @@
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rclcpp/topic_statistics_state.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -72,6 +73,8 @@ struct SubscriptionOptionsBase
};
TopicStatisticsOptions topic_stats_options;
QosOverridingOptions qos_overriding_options;
};
/// Structure containing optional configuration for Subscriptions.

View File

@@ -16,6 +16,7 @@
#define RCLCPP__WAITABLE_HPP_
#include <atomic>
#include <memory>
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -125,8 +126,17 @@ public:
bool
is_ready(rcl_wait_set_t * wait_set) = 0;
/// Execute any entities of the Waitable that are ready.
/// Take the data so that it can be consumed with `execute`.
/**
* NOTE: take_data is a partial fix to a larger design issue with the
* multithreaded executor. This method is likely to be removed when
* a more permanent fix is implemented. A longterm fix is currently
* being discussed here: https://github.com/ros2/rclcpp/pull/1276
*
* This method takes the data from the underlying data structure and
* writes it to the void shared pointer `data` that is passed into the
* method. The `data` can then be executed with the `execute` method.
*
* Before calling this method, the Waitable should be added to a wait set,
* waited on, and then updated.
*
@@ -143,13 +153,41 @@ public:
* // Update the Waitable
* waitable.update(wait_set);
* // Execute any entities of the Waitable that may be ready
* waitable.execute();
* std::shared_ptr<void> data = waitable.take_data();
* ```
*/
RCLCPP_PUBLIC
virtual
std::shared_ptr<void>
take_data() = 0;
/// Execute data that is passed in.
/**
* Before calling this method, the Waitable should be added to a wait set,
* waited on, and then updated - and the `take_data` method should be
* called.
*
* Example usage:
*
* ```cpp
* // ... create a wait set and a Waitable
* // Add the Waitable to the wait set
* bool add_ret = waitable.add_to_wait_set(wait_set);
* // ... error handling
* // Wait
* rcl_ret_t wait_ret = rcl_wait(wait_set);
* // ... error handling
* // Update the Waitable
* waitable.update(wait_set);
* // Execute any entities of the Waitable that may be ready
* std::shared_ptr<void> data = waitable.take_data();
* waitable.execute(data);
* ```
*/
RCLCPP_PUBLIC
virtual
void
execute() = 0;
execute(std::shared_ptr<void> & data) = 0;
/// Exchange the "in use by wait set" state for this timer.
/**

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>5.0.0</version>
<version>6.2.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
@@ -39,6 +39,7 @@
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>mimick_vendor</test_depend>
<test_depend>performance_test_fixture</test_depend>
<test_depend>rmw</test_depend>
<test_depend>rmw_implementation_cmake</test_depend>
<test_depend>rosidl_default_generators</test_depend>

View File

@@ -151,10 +151,9 @@ def get_rclcpp_suffix_from_features(features):
@[ end if]@
logger.get_name(), \
@[ if 'stream' not in feature_combination]@
rclcpp::get_c_string(RCLCPP_FIRST_ARG(__VA_ARGS__, "")), \
RCLCPP_ALL_BUT_FIRST_ARGS(__VA_ARGS__,"")); \
__VA_ARGS__); \
@[ else]@
"%s", rclcpp::get_c_string(ss.str())); \
"%s", ss.str().c_str()); \
@[ end if]@
} while (0)

View File

@@ -320,7 +320,6 @@ Context::shutdown(const std::string & reason)
}
// interrupt all blocking sleep_for() and all blocking executors or wait sets
this->interrupt_all_sleep_for();
this->interrupt_all_wait_sets();
// remove self from the global contexts
weak_contexts_->remove_context(this);
// shutdown logger
@@ -391,75 +390,6 @@ Context::interrupt_all_sleep_for()
interrupt_condition_variable_.notify_all();
}
rcl_guard_condition_t *
Context::get_interrupt_guard_condition(rcl_wait_set_t * wait_set)
{
std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
auto kv = interrupt_guard_cond_handles_.find(wait_set);
if (kv != interrupt_guard_cond_handles_.end()) {
return &kv->second;
} else {
rcl_guard_condition_t handle = rcl_get_zero_initialized_guard_condition();
rcl_guard_condition_options_t options = rcl_guard_condition_get_default_options();
auto ret = rcl_guard_condition_init(&handle, this->get_rcl_context().get(), options);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize guard condition");
}
interrupt_guard_cond_handles_.emplace(wait_set, handle);
return &interrupt_guard_cond_handles_[wait_set];
}
}
void
Context::release_interrupt_guard_condition(rcl_wait_set_t * wait_set)
{
std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
auto kv = interrupt_guard_cond_handles_.find(wait_set);
if (kv != interrupt_guard_cond_handles_.end()) {
rcl_ret_t ret = rcl_guard_condition_fini(&kv->second);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to destroy sigint guard condition");
}
interrupt_guard_cond_handles_.erase(kv);
} else {
throw std::runtime_error("Tried to release sigint guard condition for nonexistent wait set");
}
}
void
Context::release_interrupt_guard_condition(
rcl_wait_set_t * wait_set,
const std::nothrow_t &) noexcept
{
try {
this->release_interrupt_guard_condition(wait_set);
} catch (const std::exception & exc) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"caught %s exception when releasing interrupt guard condition: %s",
rmw::impl::cpp::demangle(exc).c_str(), exc.what());
} catch (...) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"caught unknown exception when releasing interrupt guard condition");
}
}
void
Context::interrupt_all_wait_sets()
{
std::lock_guard<std::mutex> lock(interrupt_guard_cond_handles_mutex_);
for (auto & kv : interrupt_guard_cond_handles_) {
rcl_ret_t status = rcl_trigger_guard_condition(&(kv.second));
if (status != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to trigger guard condition in Context::interrupt_all_wait_sets(): %s",
rcl_get_error_string().str);
}
}
}
void
Context::clean_up()
{

View File

@@ -37,7 +37,7 @@ Duration::Duration(int32_t seconds, uint32_t nanoseconds)
rcl_duration_.nanoseconds += nanoseconds;
}
Duration::Duration(int64_t nanoseconds)
Duration::Duration(rcl_duration_value_t nanoseconds)
{
rcl_duration_.nanoseconds = nanoseconds;
}
@@ -148,7 +148,7 @@ Duration::operator+(const rclcpp::Duration & rhs) const
this->rcl_duration_.nanoseconds,
rhs.rcl_duration_.nanoseconds,
std::numeric_limits<rcl_duration_value_t>::max());
return Duration(
return Duration::from_nanoseconds(
rcl_duration_.nanoseconds + rhs.rcl_duration_.nanoseconds);
}
@@ -177,7 +177,7 @@ Duration::operator-(const rclcpp::Duration & rhs) const
rhs.rcl_duration_.nanoseconds,
std::numeric_limits<rcl_duration_value_t>::max());
return Duration(
return Duration::from_nanoseconds(
rcl_duration_.nanoseconds - rhs.rcl_duration_.nanoseconds);
}
@@ -208,7 +208,7 @@ Duration::operator*(double scale) const
scale,
std::numeric_limits<rcl_duration_value_t>::max());
long double scale_ld = static_cast<long double>(scale);
return Duration(
return Duration::from_nanoseconds(
static_cast<rcl_duration_value_t>(
static_cast<long double>(rcl_duration_.nanoseconds) * scale_ld));
}
@@ -246,10 +246,41 @@ Duration::to_rmw_time() const
return result;
}
Duration
Duration::from_rmw_time(rmw_time_t duration)
{
Duration ret;
constexpr rcl_duration_value_t limit_ns = std::numeric_limits<rcl_duration_value_t>::max();
constexpr rcl_duration_value_t limit_sec = RCL_NS_TO_S(limit_ns);
if (duration.sec > limit_sec || duration.nsec > limit_ns) {
// saturate if will overflow
ret.rcl_duration_.nanoseconds = limit_ns;
return ret;
}
uint64_t total_ns = RCL_S_TO_NS(duration.sec) + duration.nsec;
if (total_ns > limit_ns) {
// saturate if will overflow
ret.rcl_duration_.nanoseconds = limit_ns;
return ret;
}
ret.rcl_duration_.nanoseconds = static_cast<rcl_duration_value_t>(total_ns);
return ret;
}
Duration
Duration::from_seconds(double seconds)
{
return Duration(static_cast<int64_t>(RCL_S_TO_NS(seconds)));
Duration ret;
ret.rcl_duration_.nanoseconds = static_cast<int64_t>(RCL_S_TO_NS(seconds));
return ret;
}
Duration
Duration::from_nanoseconds(rcl_duration_value_t nanoseconds)
{
Duration ret;
ret.rcl_duration_.nanoseconds = nanoseconds;
return ret;
}
} // namespace rclcpp

View File

@@ -25,6 +25,8 @@
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executor.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/scope_exit.hpp"
#include "rclcpp/utilities.hpp"
@@ -41,28 +43,35 @@ using rclcpp::FutureReturnCode;
Executor::Executor(const rclcpp::ExecutorOptions & options)
: spinning(false),
shutdown_guard_condition_(std::make_shared<rclcpp::GuardCondition>(options.context)),
memory_strategy_(options.memory_strategy)
{
// Store the context for later use.
context_ = options.context;
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
rcl_ret_t ret = rcl_guard_condition_init(
&interrupt_guard_condition_, options.context->get_rcl_context().get(), guard_condition_options);
&interrupt_guard_condition_, context_->get_rcl_context().get(), guard_condition_options);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "Failed to create interrupt guard condition in Executor constructor");
}
context_->on_shutdown(
[weak_gc = std::weak_ptr<rclcpp::GuardCondition>{shutdown_guard_condition_}]() {
auto strong_gc = weak_gc.lock();
if (strong_gc) {
strong_gc->trigger();
}
});
// The number of guard conditions is always at least 2: 1 for the ctrl-c guard cond,
// and one for the executor's guard cond (interrupt_guard_condition_)
// Put the global ctrl-c guard condition in
memory_strategy_->add_guard_condition(options.context->get_interrupt_guard_condition(&wait_set_));
memory_strategy_->add_guard_condition(&shutdown_guard_condition_->get_rcl_guard_condition());
// Put the executor's guard condition in
memory_strategy_->add_guard_condition(&interrupt_guard_condition_);
rcl_allocator_t allocator = memory_strategy_->get_allocator();
// Store the context for later use.
context_ = options.context;
ret = rcl_wait_set_init(
&wait_set_,
0, 2, 0, 0, 0, 0,
@@ -128,8 +137,7 @@ Executor::~Executor()
rcl_reset_error();
}
// Remove and release the sigint guard condition
memory_strategy_->remove_guard_condition(context_->get_interrupt_guard_condition(&wait_set_));
context_->release_interrupt_guard_condition(&wait_set_, std::nothrow);
memory_strategy_->remove_guard_condition(&shutdown_guard_condition_->get_rcl_guard_condition());
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
@@ -195,7 +203,7 @@ void
Executor::add_callback_group_to_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify)
{
// If the callback_group already has an executor
@@ -269,7 +277,7 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
void
Executor::remove_callback_group_from_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify)
{
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr;
@@ -342,27 +350,24 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
if (!found_node) {
throw std::runtime_error("Node needs to be associated with this executor.");
}
std::vector<rclcpp::CallbackGroup::SharedPtr> found_group_ptrs;
std::for_each(
weak_groups_to_nodes_associated_with_executor_.begin(),
weak_groups_to_nodes_associated_with_executor_.end(),
[&found_group_ptrs, node_ptr](std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> key_value_pair) {
auto weak_node_ptr = key_value_pair.second;
auto shared_node_ptr = weak_node_ptr.lock();
auto group_ptr = key_value_pair.first.lock();
if (shared_node_ptr == node_ptr) {
found_group_ptrs.push_back(group_ptr);
}
});
std::for_each(
found_group_ptrs.begin(), found_group_ptrs.end(), [this, notify]
(rclcpp::CallbackGroup::SharedPtr group_ptr) {
for (auto it = weak_groups_to_nodes_associated_with_executor_.begin();
it != weak_groups_to_nodes_associated_with_executor_.end(); )
{
auto weak_node_ptr = it->second;
auto shared_node_ptr = weak_node_ptr.lock();
auto group_ptr = it->first.lock();
// Increment iterator before removing in case it's invalidated
it++;
if (shared_node_ptr == node_ptr) {
remove_callback_group_from_map(
group_ptr,
weak_groups_to_nodes_associated_with_executor_,
notify);
});
}
}
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
has_executor.store(false);
}
@@ -506,7 +511,7 @@ Executor::execute_any_executable(AnyExecutable & any_exec)
execute_client(any_exec.client);
}
if (any_exec.waitable) {
any_exec.waitable->execute();
any_exec.waitable->execute(any_exec.data);
}
// Reset the callback_group, regardless of type
any_exec.callback_group->can_be_taken_from().store(true);
@@ -678,8 +683,11 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
if (weak_group_ptr.expired() || weak_node_ptr.expired()) {
invalid_group_ptrs.push_back(weak_group_ptr);
auto node_guard_pair = weak_nodes_to_guard_conditions_.find(weak_node_ptr);
weak_nodes_to_guard_conditions_.erase(weak_node_ptr);
memory_strategy_->remove_guard_condition(node_guard_pair->second);
if (node_guard_pair != weak_nodes_to_guard_conditions_.end()) {
auto guard_condition = node_guard_pair->second;
weak_nodes_to_guard_conditions_.erase(weak_node_ptr);
memory_strategy_->remove_guard_condition(guard_condition);
}
}
}
std::for_each(
@@ -738,7 +746,7 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
Executor::get_node_by_group(
WeakCallbackGroupsToNodesMap weak_groups_to_nodes,
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap weak_groups_to_nodes,
rclcpp::CallbackGroup::SharedPtr group)
{
if (!group) {
@@ -796,7 +804,7 @@ Executor::get_next_ready_executable(AnyExecutable & any_executable)
bool
Executor::get_next_ready_executable_from_map(
AnyExecutable & any_executable,
WeakCallbackGroupsToNodesMap weak_groups_to_nodes)
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap weak_groups_to_nodes)
{
bool success = false;
// Check the timers to see if there are any that are ready
@@ -829,6 +837,7 @@ Executor::get_next_ready_executable_from_map(
// Check the waitables to see if there are any that are ready
memory_strategy_->get_next_waitable(any_executable, weak_groups_to_nodes);
if (any_executable.waitable) {
any_executable.data = any_executable.waitable->take_data();
success = true;
}
}
@@ -884,7 +893,7 @@ Executor::get_next_executable(AnyExecutable & any_executable, std::chrono::nanos
bool
Executor::has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap weak_groups_to_nodes) const
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap weak_groups_to_nodes) const
{
return std::find_if(
weak_groups_to_nodes.begin(),

View File

@@ -77,7 +77,8 @@ StaticExecutorEntitiesCollector::init(
// Add executor's guard condition
memory_strategy_->add_guard_condition(executor_guard_condition);
// Get memory strategy and executable list. Prepare wait_set_
execute();
std::shared_ptr<void> shared_ptr;
execute(shared_ptr);
}
void
@@ -87,9 +88,16 @@ StaticExecutorEntitiesCollector::fini()
exec_list_.clear();
}
void
StaticExecutorEntitiesCollector::execute()
std::shared_ptr<void>
StaticExecutorEntitiesCollector::take_data()
{
return nullptr;
}
void
StaticExecutorEntitiesCollector::execute(std::shared_ptr<void> & data)
{
(void) data;
// Fill memory strategy with entities coming from weak_nodes_
fill_memory_strategy();
// Fill exec_list_ with entities coming from weak_nodes_ (same as memory strategy)
@@ -155,7 +163,8 @@ StaticExecutorEntitiesCollector::fill_executable_list()
}
void
StaticExecutorEntitiesCollector::fill_executable_list_from_map(
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes)
{
for (const auto & pair : weak_groups_to_nodes) {
auto group = pair.first.lock();
@@ -297,7 +306,7 @@ bool
StaticExecutorEntitiesCollector::add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
{
// If the callback_group already has an executor
std::atomic_bool & has_executor = group_ptr->get_associated_with_executor_atomic();
@@ -341,7 +350,7 @@ StaticExecutorEntitiesCollector::remove_callback_group(
bool
StaticExecutorEntitiesCollector::remove_callback_group_from_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
{
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr;
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
@@ -437,7 +446,8 @@ StaticExecutorEntitiesCollector::is_ready(rcl_wait_set_t * p_wait_set)
bool
StaticExecutorEntitiesCollector::has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes) const
{
return std::find_if(
weak_groups_to_nodes.begin(),

View File

@@ -176,7 +176,8 @@ StaticSingleThreadedExecutor::execute_ready_executables()
// Execute all the ready waitables
for (size_t i = 0; i < entities_collector_->get_number_of_waitables(); ++i) {
if (entities_collector_->get_waitable(i)->is_ready(&wait_set_)) {
entities_collector_->get_waitable(i)->execute();
std::shared_ptr<void> shared_ptr;
entities_collector_->get_waitable(i)->execute(shared_ptr);
}
}
}

View File

@@ -36,11 +36,11 @@ namespace rclcpp
namespace graph_listener
{
GraphListener::GraphListener(std::shared_ptr<rclcpp::Context> parent_context)
: parent_context_(parent_context),
GraphListener::GraphListener(const std::shared_ptr<Context> & parent_context)
: weak_parent_context_(parent_context),
rcl_parent_context_(parent_context->get_rcl_context()),
is_started_(false),
is_shutdown_(false),
shutdown_guard_condition_(nullptr)
is_shutdown_(false)
{
// TODO(wjwwood): make a guard condition class in rclcpp so this can be tracked
// automatically with the rcl guard condition
@@ -48,13 +48,11 @@ GraphListener::GraphListener(std::shared_ptr<rclcpp::Context> parent_context)
// guard condition is using it.
rcl_ret_t ret = rcl_guard_condition_init(
&interrupt_guard_condition_,
parent_context->get_rcl_context().get(),
rcl_parent_context_.get(),
rcl_guard_condition_get_default_options());
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to create interrupt guard condition");
}
shutdown_guard_condition_ = parent_context->get_interrupt_guard_condition(&wait_set_);
}
GraphListener::~GraphListener()
@@ -62,6 +60,23 @@ GraphListener::~GraphListener()
this->shutdown(std::nothrow);
}
void GraphListener::init_wait_set()
{
rcl_ret_t ret = rcl_wait_set_init(
&wait_set_,
0, // number_of_subscriptions
2, // number_of_guard_conditions
0, // number_of_timers
0, // number_of_clients
0, // number_of_services
0, // number_of_events
rcl_parent_context_.get(),
rcl_get_default_allocator());
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to initialize wait set");
}
}
void
GraphListener::start_if_not_started()
{
@@ -69,30 +84,13 @@ GraphListener::start_if_not_started()
if (is_shutdown_.load()) {
throw GraphListenerShutdownError();
}
if (!is_started_) {
// Initialize the wait set before starting.
auto parent_context = parent_context_.lock();
if (!parent_context) {
throw std::runtime_error("parent context was destroyed");
}
rcl_ret_t ret = rcl_wait_set_init(
&wait_set_,
0, // number_of_subscriptions
2, // number_of_guard_conditions
0, // number_of_timers
0, // number_of_clients
0, // number_of_services
0, // number_of_events
parent_context->get_rcl_context().get(),
rcl_get_default_allocator());
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to initialize wait set");
}
auto parent_context = weak_parent_context_.lock();
if (!is_started_ && parent_context) {
// Register an on_shutdown hook to shtudown the graph listener.
// This is important to ensure that the wait set is finalized before
// destruction of static objects occurs.
std::weak_ptr<GraphListener> weak_this = shared_from_this();
rclcpp::on_shutdown(
parent_context->on_shutdown(
[weak_this]() {
auto shared_this = weak_this.lock();
if (shared_this) {
@@ -100,6 +98,8 @@ GraphListener::start_if_not_started()
shared_this->shutdown(std::nothrow);
}
});
// Initialize the wait set before starting.
init_wait_set();
// Start the listener thread.
listener_thread_ = std::thread(&GraphListener::run, this);
is_started_ = true;
@@ -144,14 +144,6 @@ GraphListener::run_loop()
}
// This lock is released when the loop continues or exits.
std::lock_guard<std::mutex> nodes_lock(node_graph_interfaces_mutex_, std::adopt_lock);
// Ensure that the context doesn't go out of scope.
auto parent_context = parent_context_.lock();
if (!parent_context) {
// The parent context may be destroyed before this loop is stopped.
// In that case, the loop is broken and the function just returns silently.
return;
}
// Resize the wait set if necessary.
const size_t node_graph_interfaces_size = node_graph_interfaces_.size();
// Add 2 for the interrupt and shutdown guard conditions
@@ -171,13 +163,7 @@ GraphListener::run_loop()
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to add interrupt guard condition to wait set");
}
// Put the shutdown guard condition in the wait set.
size_t shutdown_guard_condition_index = 0u;
ret = rcl_wait_set_add_guard_condition(
&wait_set_, shutdown_guard_condition_, &shutdown_guard_condition_index);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to add shutdown guard condition to wait set");
}
// Put graph guard conditions for each node into the wait set.
std::vector<size_t> graph_gc_indexes(node_graph_interfaces_size, 0u);
for (size_t i = 0u; i < node_graph_interfaces_size; ++i) {
@@ -206,9 +192,6 @@ GraphListener::run_loop()
throw_from_rcl_error(ret, "failed to wait on wait set");
}
// Check to see if the shutdown guard condition has been triggered.
bool shutdown_guard_condition_triggered =
(shutdown_guard_condition_ == wait_set_.guard_conditions[shutdown_guard_condition_index]);
// Notify nodes who's guard conditions are set (triggered).
for (size_t i = 0u; i < node_graph_interfaces_size; ++i) {
const auto node_ptr = node_graph_interfaces_[i];
@@ -219,7 +202,7 @@ GraphListener::run_loop()
if (graph_gc == wait_set_.guard_conditions[graph_gc_indexes[i]]) {
node_ptr->notify_graph_change();
}
if (shutdown_guard_condition_triggered) {
if (is_shutdown_) {
// If shutdown, then notify the node of this as well.
node_ptr->notify_shutdown();
}
@@ -351,7 +334,16 @@ GraphListener::remove_node(rclcpp::node_interfaces::NodeGraphInterface * node_gr
}
void
GraphListener::__shutdown(bool should_throw)
GraphListener::cleanup_wait_set()
{
rcl_ret_t ret = rcl_wait_set_fini(&wait_set_);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to finalize wait set");
}
}
void
GraphListener::__shutdown()
{
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
if (!is_shutdown_.exchange(true)) {
@@ -363,33 +355,8 @@ GraphListener::__shutdown(bool should_throw)
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to finalize interrupt guard condition");
}
if (shutdown_guard_condition_) {
auto parent_context_ptr = parent_context_.lock();
if (parent_context_ptr) {
if (should_throw) {
parent_context_ptr->release_interrupt_guard_condition(&wait_set_);
} else {
parent_context_ptr->release_interrupt_guard_condition(&wait_set_, std::nothrow);
}
} else {
ret = rcl_guard_condition_fini(shutdown_guard_condition_);
if (RCL_RET_OK != ret) {
if (should_throw) {
throw_from_rcl_error(ret, "failed to finalize shutdown guard condition");
} else {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"failed to finalize shutdown guard condition");
}
}
}
shutdown_guard_condition_ = nullptr;
}
if (is_started_) {
ret = rcl_wait_set_fini(&wait_set_);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to finalize wait set");
}
cleanup_wait_set();
}
}
}
@@ -397,14 +364,14 @@ GraphListener::__shutdown(bool should_throw)
void
GraphListener::shutdown()
{
this->__shutdown(true);
this->__shutdown();
}
void
GraphListener::shutdown(const std::nothrow_t &) noexcept
{
try {
this->__shutdown(false);
this->__shutdown();
} catch (const std::exception & exc) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),

View File

@@ -38,7 +38,9 @@ get_node_logger(const rcl_node_t * node)
const char * logger_name = rcl_node_get_logger_name(node);
if (nullptr == logger_name) {
auto logger = rclcpp::get_logger("rclcpp");
RCLCPP_ERROR(logger, "failed to get logger name from node at address %p", node);
RCLCPP_ERROR(
logger, "failed to get logger name from node at address %p",
static_cast<void *>(const_cast<rcl_node_t *>(node)));
return logger;
}
return rclcpp::get_logger(logger_name);

View File

@@ -70,6 +70,7 @@ NodeBase::NodeBase(
std::shared_ptr<std::recursive_mutex> logging_mutex = get_global_logging_mutex();
{
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
// TODO(ivanpauno): /rosout Qos should be reconfigurable.
// TODO(ivanpauno): Instead of mutually excluding rcl_node_init with the global logger mutex,
// rcl_logging_rosout_init_publisher_for_node could be decoupled from there and be called
// here directly.
@@ -288,3 +289,24 @@ NodeBase::get_enable_topic_statistics_default() const
{
return enable_topic_statistics_default_;
}
std::string
NodeBase::resolve_topic_or_service_name(
const std::string & name, bool is_service, bool only_expand) const
{
char * output_cstr = NULL;
auto allocator = rcl_get_default_allocator();
rcl_ret_t ret = rcl_node_resolve_name(
node_handle_.get(),
name.c_str(),
allocator,
is_service,
only_expand,
&output_cstr);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to resolve name", rcl_get_error_state());
}
std::string output{output_cstr};
allocator.deallocate(output_cstr, allocator.state);
return output;
}

View File

@@ -67,6 +67,7 @@ NodeParameters::NodeParameters(
}
if (start_parameter_event_publisher) {
// TODO(ivanpauno): Qos of the `/parameters_event` topic should be somehow overridable.
events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
node_topics,
"/parameter_events",

View File

@@ -78,3 +78,9 @@ NodeServices::add_client(
}
}
}
std::string
NodeServices::resolve_service_name(const std::string & name, bool only_expand) const
{
return node_base_->resolve_topic_or_service_name(name, true, only_expand);
}

View File

@@ -129,3 +129,9 @@ NodeTopics::get_node_timers_interface() const
{
return node_timers_;
}
std::string
NodeTopics::resolve_topic_name(const std::string & name, bool only_expand) const
{
return node_base_->resolve_topic_or_service_name(name, false, only_expand);
}

View File

@@ -144,6 +144,35 @@ AsyncParametersClient::get_parameters(
return future_result;
}
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>
AsyncParametersClient::describe_parameters(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>)
> callback)
{
auto promise_result =
std::make_shared<std::promise<std::vector<rcl_interfaces::msg::ParameterDescriptor>>>();
auto future_result = promise_result->get_future().share();
auto request = std::make_shared<rcl_interfaces::srv::DescribeParameters::Request>();
request->names = names;
describe_parameters_client_->async_send_request(
request,
[promise_result, future_result, callback](
rclcpp::Client<rcl_interfaces::srv::DescribeParameters>::SharedFuture cb_f)
{
promise_result->set_value(cb_f.get()->descriptors);
if (callback != nullptr) {
callback(future_result);
}
}
);
return future_result;
}
std::shared_future<std::vector<rclcpp::ParameterType>>
AsyncParametersClient::get_parameter_types(
const std::vector<std::string> & names,
@@ -313,14 +342,16 @@ AsyncParametersClient::wait_for_service_nanoseconds(std::chrono::nanoseconds tim
}
std::vector<rclcpp::Parameter>
SyncParametersClient::get_parameters(const std::vector<std::string> & parameter_names)
SyncParametersClient::get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->get_parameters(parameter_names);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -337,16 +368,34 @@ SyncParametersClient::has_parameter(const std::string & parameter_name)
return vars.names.size() > 0;
}
std::vector<rcl_interfaces::msg::ParameterDescriptor>
SyncParametersClient::describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->describe_parameters(parameter_names);
using rclcpp::executors::spin_node_until_future_complete;
rclcpp::FutureReturnCode future =
spin_node_until_future_complete(*executor_, node_base_interface_, f, timeout);
if (future == rclcpp::FutureReturnCode::SUCCESS) {
return f.get();
}
return std::vector<rcl_interfaces::msg::ParameterDescriptor>();
}
std::vector<rclcpp::ParameterType>
SyncParametersClient::get_parameter_types(const std::vector<std::string> & parameter_names)
SyncParametersClient::get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->get_parameter_types(parameter_names);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -355,15 +404,16 @@ SyncParametersClient::get_parameter_types(const std::vector<std::string> & param
std::vector<rcl_interfaces::msg::SetParametersResult>
SyncParametersClient::set_parameters(
const std::vector<rclcpp::Parameter> & parameters)
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->set_parameters(parameters);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -372,15 +422,16 @@ SyncParametersClient::set_parameters(
rcl_interfaces::msg::SetParametersResult
SyncParametersClient::set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters)
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->set_parameters_atomically(parameters);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -391,15 +442,16 @@ SyncParametersClient::set_parameters_atomically(
rcl_interfaces::msg::ListParametersResult
SyncParametersClient::list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth)
uint64_t depth,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->list_parameters(parameter_prefixes, depth);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}

View File

@@ -99,6 +99,13 @@ QoS::history(rmw_qos_history_policy_t history)
return *this;
}
QoS &
QoS::history(HistoryPolicy history)
{
rmw_qos_profile_.history = static_cast<rmw_qos_history_policy_t>(history);
return *this;
}
QoS &
QoS::keep_last(size_t depth)
{
@@ -122,6 +129,13 @@ QoS::reliability(rmw_qos_reliability_policy_t reliability)
return *this;
}
QoS &
QoS::reliability(ReliabilityPolicy reliability)
{
rmw_qos_profile_.reliability = static_cast<rmw_qos_reliability_policy_t>(reliability);
return *this;
}
QoS &
QoS::reliable()
{
@@ -141,6 +155,13 @@ QoS::durability(rmw_qos_durability_policy_t durability)
return *this;
}
QoS &
QoS::durability(DurabilityPolicy durability)
{
rmw_qos_profile_.durability = static_cast<rmw_qos_durability_policy_t>(durability);
return *this;
}
QoS &
QoS::durability_volatile()
{
@@ -186,6 +207,14 @@ QoS::liveliness(rmw_qos_liveliness_policy_t liveliness)
return *this;
}
QoS &
QoS::liveliness(LivelinessPolicy liveliness)
{
rmw_qos_profile_.liveliness = static_cast<rmw_qos_liveliness_policy_t>(liveliness);
return *this;
}
QoS &
QoS::liveliness_lease_duration(rmw_time_t liveliness_lease_duration)
{
@@ -206,6 +235,51 @@ QoS::avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions)
return *this;
}
HistoryPolicy
QoS::history() const
{
return static_cast<HistoryPolicy>(rmw_qos_profile_.history);
}
size_t
QoS::depth() const {return rmw_qos_profile_.depth;}
ReliabilityPolicy
QoS::reliability() const
{
return static_cast<ReliabilityPolicy>(rmw_qos_profile_.reliability);
}
DurabilityPolicy
QoS::durability() const
{
return static_cast<DurabilityPolicy>(rmw_qos_profile_.durability);
}
Duration
QoS::deadline() const {return Duration::from_rmw_time(rmw_qos_profile_.deadline);}
Duration
QoS::lifespan() const {return Duration::from_rmw_time(rmw_qos_profile_.lifespan);}
LivelinessPolicy
QoS::liveliness() const
{
return static_cast<LivelinessPolicy>(rmw_qos_profile_.liveliness);
}
Duration
QoS::liveliness_lease_duration() const
{
return Duration::from_rmw_time(rmw_qos_profile_.liveliness_lease_duration);
}
bool
QoS::avoid_ros_namespace_conventions() const
{
return rmw_qos_profile_.avoid_ros_namespace_conventions;
}
namespace
{
/// Check if two rmw_time_t have the same values.

View File

@@ -0,0 +1,84 @@
// Copyright 2020 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 "rclcpp/qos_overriding_options.hpp"
#include <initializer_list>
#include <ostream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "rmw/qos_policy_kind.h"
#include "rmw/qos_string_conversions.h"
namespace rclcpp
{
const char *
qos_policy_kind_to_cstr(const QosPolicyKind & qpk)
{
const char * ret = rmw_qos_policy_kind_to_str(static_cast<rmw_qos_policy_kind_t>(qpk));
if (!ret) {
throw std::invalid_argument{"unknown QoS policy kind"};
}
return ret;
}
std::ostream &
operator<<(std::ostream & oss, const QosPolicyKind & qpk)
{
return oss << qos_policy_kind_to_cstr(qpk);
}
static std::initializer_list<QosPolicyKind> kDefaultPolicies =
{QosPolicyKind::History, QosPolicyKind::Depth, QosPolicyKind::Reliability};
QosOverridingOptions::QosOverridingOptions(
std::initializer_list<QosPolicyKind> policy_kinds,
QosCallback validation_callback,
std::string id)
: id_{std::move(id)},
policy_kinds_{policy_kinds},
validation_callback_{std::move(validation_callback)}
{}
QosOverridingOptions
QosOverridingOptions::with_default_policies(
QosCallback validation_callback,
std::string id)
{
return QosOverridingOptions{kDefaultPolicies, validation_callback, id};
}
const std::string &
QosOverridingOptions::get_id() const
{
return id_;
}
const std::vector<QosPolicyKind> &
QosOverridingOptions::get_policy_kinds() const
{
return policy_kinds_;
}
const QosCallback &
QosOverridingOptions::get_validation_callback() const
{
return validation_callback_;
}
} // namespace rclcpp

View File

@@ -243,7 +243,7 @@ SignalHandler::deferred_signal_handler()
get_logger(),
"deferred_signal_handler(): "
"shutting down rclcpp::Context @ %p, because it had shutdown_on_sigint == true",
context_ptr.get());
static_cast<void *>(context_ptr.get()));
context_ptr->shutdown("signal handler");
}
}

View File

@@ -199,7 +199,7 @@ Time::operator-(const rclcpp::Time & rhs) const
throw std::underflow_error("time subtraction leads to int64_t underflow");
}
return Duration(rcl_time_.nanoseconds - rhs.rcl_time_.nanoseconds);
return Duration::from_nanoseconds(rcl_time_.nanoseconds - rhs.rcl_time_.nanoseconds);
}
Time

View File

@@ -21,6 +21,7 @@
#include "./signal_handler.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/detail/utilities.hpp"
#include "rclcpp/exceptions.hpp"
#include "rcl/error_handling.h"
@@ -56,6 +57,47 @@ uninstall_signal_handlers()
return SignalHandler::get_global_signal_handler().uninstall();
}
static
std::vector<std::string>
_remove_ros_arguments(
char const * const argv[],
const rcl_arguments_t * args,
rcl_allocator_t alloc)
{
rcl_ret_t ret;
int nonros_argc = 0;
const char ** nonros_argv = NULL;
ret = rcl_remove_ros_arguments(
argv,
args,
alloc,
&nonros_argc,
&nonros_argv);
if (RCL_RET_OK != ret || nonros_argc < 0) {
// Not using throw_from_rcl_error, because we may need to append deallocation failures.
exceptions::RCLError exc(ret, rcl_get_error_state(), "");
rcl_reset_error();
if (NULL != nonros_argv) {
alloc.deallocate(nonros_argv, alloc.state);
}
throw exc;
}
std::vector<std::string> return_arguments(static_cast<size_t>(nonros_argc));
for (size_t ii = 0; ii < static_cast<size_t>(nonros_argc); ++ii) {
return_arguments[ii] = std::string(nonros_argv[ii]);
}
if (NULL != nonros_argv) {
alloc.deallocate(nonros_argv, alloc.state);
}
return return_arguments;
}
std::vector<std::string>
init_and_remove_ros_arguments(
int argc,
@@ -63,7 +105,10 @@ init_and_remove_ros_arguments(
const InitOptions & init_options)
{
init(argc, argv, init_options);
return remove_ros_arguments(argc, argv);
using rclcpp::contexts::get_global_default_context;
auto rcl_context = get_global_default_context()->get_rcl_context();
return _remove_ros_arguments(argv, &(rcl_context->global_arguments), rcl_get_default_allocator());
}
std::vector<std::string>
@@ -79,40 +124,17 @@ remove_ros_arguments(int argc, char const * const argv[])
exceptions::throw_from_rcl_error(ret, "failed to parse arguments");
}
int nonros_argc = 0;
const char ** nonros_argv = NULL;
ret = rcl_remove_ros_arguments(
argv,
&parsed_args,
alloc,
&nonros_argc,
&nonros_argv);
if (RCL_RET_OK != ret || nonros_argc < 0) {
// Not using throw_from_rcl_error, because we may need to append deallocation failures.
exceptions::RCLErrorBase base_exc(ret, rcl_get_error_state());
rcl_reset_error();
if (NULL != nonros_argv) {
alloc.deallocate(nonros_argv, alloc.state);
}
std::vector<std::string> return_arguments;
try {
return_arguments = _remove_ros_arguments(argv, &parsed_args, alloc);
} catch (exceptions::RCLError & exc) {
if (RCL_RET_OK != rcl_arguments_fini(&parsed_args)) {
base_exc.formatted_message += std::string(
exc.formatted_message += std::string(
", failed also to cleanup parsed arguments, leaking memory: ") +
rcl_get_error_string().str;
rcl_reset_error();
}
throw exceptions::RCLError(base_exc, "");
}
std::vector<std::string> return_arguments(static_cast<size_t>(nonros_argc));
for (size_t ii = 0; ii < static_cast<size_t>(nonros_argc); ++ii) {
return_arguments[ii] = std::string(nonros_argv[ii]);
}
if (NULL != nonros_argv) {
alloc.deallocate(nonros_argv, alloc.state);
throw exc;
}
ret = rcl_arguments_fini(&parsed_args);

View File

@@ -1,667 +1,17 @@
find_package(ament_cmake_gtest REQUIRED)
find_package(rmw_implementation_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(test_msgs REQUIRED)
include(cmake/rclcpp_add_build_failure_test.cmake)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/resources")
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
msg/Header.msg
msg/MessageWithHeader.msg
DEPENDENCIES builtin_interfaces
LIBRARY_NAME ${PROJECT_NAME}
SKIP_INSTALL
)
ament_add_gtest(
test_allocator_common
rclcpp/allocator/test_allocator_common.cpp)
if(TARGET test_allocator_common)
target_link_libraries(test_allocator_common ${PROJECT_NAME})
endif()
ament_add_gtest(
test_allocator_deleter
rclcpp/allocator/test_allocator_deleter.cpp)
if(TARGET test_allocator_deleter)
target_link_libraries(test_allocator_deleter ${PROJECT_NAME})
endif()
ament_add_gtest(
test_exceptions
rclcpp/exceptions/test_exceptions.cpp)
if(TARGET test_exceptions)
target_link_libraries(test_exceptions ${PROJECT_NAME} mimick)
endif()
# Increasing timeout because connext can take a long time to destroy nodes
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
# https://github.com/ros2/rclcpp/issues/1250
ament_add_gtest(
test_allocator_memory_strategy
rclcpp/strategies/test_allocator_memory_strategy.cpp
TIMEOUT 360)
if(TARGET test_allocator_memory_strategy)
ament_target_dependencies(test_allocator_memory_strategy
"rcl"
"test_msgs"
)
target_link_libraries(test_allocator_memory_strategy ${PROJECT_NAME})
endif()
ament_add_gtest(test_message_pool_memory_strategy rclcpp/strategies/test_message_pool_memory_strategy.cpp)
if(TARGET test_message_pool_memory_strategy)
ament_target_dependencies(test_message_pool_memory_strategy
"rcl"
"test_msgs"
)
target_link_libraries(test_message_pool_memory_strategy ${PROJECT_NAME})
endif()
ament_add_gtest(test_any_service_callback rclcpp/test_any_service_callback.cpp)
if(TARGET test_any_service_callback)
ament_target_dependencies(test_any_service_callback
"test_msgs"
)
target_link_libraries(test_any_service_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_any_subscription_callback rclcpp/test_any_subscription_callback.cpp)
if(TARGET test_any_subscription_callback)
ament_target_dependencies(test_any_subscription_callback
"test_msgs"
)
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_client rclcpp/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_client ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_create_timer rclcpp/test_create_timer.cpp)
if(TARGET test_create_timer)
ament_target_dependencies(test_create_timer
"rcl_interfaces"
"rmw"
"rcl"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_create_timer ${PROJECT_NAME})
target_include_directories(test_create_timer PRIVATE rclcpp/)
endif()
ament_add_gtest(test_create_subscription rclcpp/test_create_subscription.cpp)
if(TARGET test_create_subscription)
target_link_libraries(test_create_subscription ${PROJECT_NAME})
ament_target_dependencies(test_create_subscription
"test_msgs"
)
endif()
ament_add_gtest(test_add_callback_groups_to_executor
rclcpp/test_add_callback_groups_to_executor.cpp
TIMEOUT 120)
if(TARGET test_add_callback_groups_to_executor)
target_link_libraries(test_add_callback_groups_to_executor ${PROJECT_NAME})
ament_target_dependencies(test_add_callback_groups_to_executor
"test_msgs"
)
endif()
ament_add_gtest(test_expand_topic_or_service_name rclcpp/test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_function_traits rclcpp/test_function_traits.cpp)
if(TARGET test_function_traits)
target_include_directories(test_function_traits PUBLIC ../include)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
endif()
ament_add_gtest(
test_future_return_code
rclcpp/test_future_return_code.cpp)
if(TARGET test_future_return_code)
target_link_libraries(test_future_return_code ${PROJECT_NAME})
endif()
ament_add_gmock(test_intra_process_manager rclcpp/test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation rclcpp/test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
endif()
ament_add_gtest(test_intra_process_buffer rclcpp/test_intra_process_buffer.cpp)
if(TARGET test_intra_process_buffer)
ament_target_dependencies(test_intra_process_buffer
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
endif()
ament_add_gtest(test_loaned_message rclcpp/test_loaned_message.cpp)
ament_target_dependencies(test_loaned_message
"test_msgs"
)
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick)
ament_add_gtest(test_memory_strategy rclcpp/test_memory_strategy.cpp)
ament_target_dependencies(test_memory_strategy
"test_msgs"
)
target_link_libraries(test_memory_strategy ${PROJECT_NAME})
ament_add_gtest(test_message_memory_strategy rclcpp/test_message_memory_strategy.cpp)
ament_target_dependencies(test_message_memory_strategy
"test_msgs"
)
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME})
ament_add_gtest(test_node rclcpp/test_node.cpp TIMEOUT 240)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rcpputils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_node ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__get_node_interfaces
rclcpp/node_interfaces/test_get_node_interfaces.cpp)
if(TARGET test_node_interfaces__get_node_interfaces)
target_link_libraries(test_node_interfaces__get_node_interfaces ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_base
rclcpp/node_interfaces/test_node_base.cpp)
if(TARGET test_node_interfaces__node_base)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_clock
rclcpp/node_interfaces/test_node_clock.cpp)
if(TARGET test_node_interfaces__node_clock)
target_link_libraries(test_node_interfaces__node_clock ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_graph
rclcpp/node_interfaces/test_node_graph.cpp
TIMEOUT 120)
if(TARGET test_node_interfaces__node_graph)
ament_target_dependencies(
test_node_interfaces__node_graph
"test_msgs")
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_parameters
rclcpp/node_interfaces/test_node_parameters.cpp)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_services
rclcpp/node_interfaces/test_node_services.cpp)
if(TARGET test_node_interfaces__node_services)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_timers
rclcpp/node_interfaces/test_node_timers.cpp)
if(TARGET test_node_interfaces__node_timers)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_topics
rclcpp/node_interfaces/test_node_topics.cpp)
if(TARGET test_node_interfaces__node_topics)
ament_target_dependencies(
test_node_interfaces__node_topics
"test_msgs")
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_waitables
rclcpp/node_interfaces/test_node_waitables.cpp)
if(TARGET test_node_interfaces__node_waitables)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick)
endif()
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_wrapped_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_wrapped_node
# rclcpp/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
ament_add_gtest(test_node_global_args rclcpp/test_node_global_args.cpp)
if(TARGET test_node_global_args)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_options rclcpp/test_node_options.cpp)
if(TARGET test_node_options)
ament_target_dependencies(test_node_options "rcl")
target_link_libraries(test_node_options ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_init_options rclcpp/test_init_options.cpp)
if(TARGET test_init_options)
ament_target_dependencies(test_init_options "rcl")
target_link_libraries(test_init_options ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_parameter_client rclcpp/test_parameter_client.cpp)
if(TARGET test_parameter_client)
ament_target_dependencies(test_parameter_client
"rcl_interfaces"
)
target_link_libraries(test_parameter_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_service rclcpp/test_parameter_service.cpp)
if(TARGET test_parameter_service)
ament_target_dependencies(test_parameter_service
"rcl_interfaces"
)
target_link_libraries(test_parameter_service ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_events_filter rclcpp/test_parameter_events_filter.cpp)
if(TARGET test_parameter_events_filter)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter rclcpp/test_parameter.cpp)
if(TARGET test_parameter)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_map rclcpp/test_parameter_map.cpp)
if(TARGET test_parameter_map)
target_link_libraries(test_parameter_map ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher rclcpp/test_publisher.cpp TIMEOUT 120)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rcl"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_publisher_subscription_count_api rclcpp/test_publisher_subscription_count_api.cpp)
if(TARGET test_publisher_subscription_count_api)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_qos rclcpp/test_qos.cpp)
if(TARGET test_qos)
ament_target_dependencies(test_qos
"rmw"
)
target_link_libraries(test_qos
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_qos_event rclcpp/test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
"rmw"
"test_msgs"
)
target_link_libraries(test_qos_event
${PROJECT_NAME}
mimick
)
endif()
ament_add_gtest(test_rate rclcpp/test_rate.cpp)
if(TARGET test_rate)
ament_target_dependencies(test_rate
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_rate
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message_allocator rclcpp/test_serialized_message_allocator.cpp)
if(TARGET test_serialized_message_allocator)
ament_target_dependencies(test_serialized_message_allocator
test_msgs
)
target_link_libraries(test_serialized_message_allocator
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message rclcpp/test_serialized_message.cpp)
if(TARGET test_serialized_message)
ament_target_dependencies(test_serialized_message
test_msgs
)
target_link_libraries(test_serialized_message
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_service rclcpp/test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_service ${PROJECT_NAME} mimick)
endif()
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
ament_add_gtest(test_subscription rclcpp/test_subscription.cpp TIMEOUT 120)
if(TARGET test_subscription)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_subscription_publisher_count_api rclcpp/test_subscription_publisher_count_api.cpp)
if(TARGET test_subscription_publisher_count_api)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_traits rclcpp/test_subscription_traits.cpp)
if(TARGET test_subscription_traits)
ament_target_dependencies(test_subscription_traits
"rcl"
"test_msgs"
)
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_type_support rclcpp/test_type_support.cpp)
if(TARGET test_type_support)
ament_target_dependencies(test_type_support
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_type_support ${PROJECT_NAME})
endif()
ament_add_gtest(test_find_weak_nodes rclcpp/test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
"rcl"
)
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
endif()
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
if(WIN32)
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
endif()
ament_add_gtest(test_externally_defined_services rclcpp/test_externally_defined_services.cpp)
ament_target_dependencies(test_externally_defined_services
"rcl"
"test_msgs"
)
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
ament_add_gtest(test_duration rclcpp/test_duration.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_duration)
ament_target_dependencies(test_duration
"rcl")
target_link_libraries(test_duration ${PROJECT_NAME})
endif()
ament_add_gtest(test_logger rclcpp/test_logger.cpp)
target_link_libraries(test_logger ${PROJECT_NAME})
ament_add_gmock(test_logging rclcpp/test_logging.cpp)
target_link_libraries(test_logging ${PROJECT_NAME})
ament_add_gtest(test_time rclcpp/test_time.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time)
ament_target_dependencies(test_time
"rcl")
target_link_libraries(test_time ${PROJECT_NAME})
endif()
ament_add_gtest(test_timer rclcpp/test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer)
ament_target_dependencies(test_timer
"rcl")
target_link_libraries(test_timer ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_time_source rclcpp/test_time_source.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time_source)
ament_target_dependencies(test_time_source
"rcl")
target_link_libraries(test_time_source ${PROJECT_NAME})
endif()
ament_add_gtest(test_utilities rclcpp/test_utilities.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_utilities)
ament_target_dependencies(test_utilities
"rcl")
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_init rclcpp/test_init.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_init)
ament_target_dependencies(test_init
"rcl")
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits rclcpp/test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
# https://github.com/ros2/rclcpp/issues/1250
ament_add_gtest(
test_executors
rclcpp/executors/test_executors.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 180)
if(TARGET test_executors)
ament_target_dependencies(test_executors
"rcl"
"test_msgs")
target_link_libraries(test_executors ${PROJECT_NAME})
endif()
ament_add_gtest(test_static_single_threaded_executor rclcpp/executors/test_static_single_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_static_single_threaded_executor)
ament_target_dependencies(test_static_single_threaded_executor
"test_msgs")
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_multi_threaded_executor rclcpp/executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
ament_target_dependencies(test_multi_threaded_executor
"rcl")
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_static_executor_entities_collector rclcpp/executors/test_static_executor_entities_collector.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
if(TARGET test_static_executor_entities_collector)
ament_target_dependencies(test_static_executor_entities_collector
"rcl"
"test_msgs")
target_link_libraries(test_static_executor_entities_collector ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_guard_condition rclcpp/test_guard_condition.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_wait_set rclcpp/test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)
ament_target_dependencies(test_wait_set "test_msgs")
target_link_libraries(test_wait_set ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_topic_statistics rclcpp/topic_statistics/test_subscription_topic_statistics.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"builtin_interfaces"
"libstatistics_collector"
"rcl_interfaces"
"rcutils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
rosidl_target_interfaces(test_subscription_topic_statistics ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
target_link_libraries(test_subscription_topic_statistics ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_options rclcpp/test_subscription_options.cpp)
if(TARGET test_subscription_options)
ament_target_dependencies(test_subscription_options "rcl")
target_link_libraries(test_subscription_options ${PROJECT_NAME})
endif()
ament_add_gtest(test_dynamic_storage rclcpp/wait_set_policies/test_dynamic_storage.cpp)
if(TARGET test_dynamic_storage)
ament_target_dependencies(test_dynamic_storage "rcl" "test_msgs")
target_link_libraries(test_dynamic_storage ${PROJECT_NAME})
endif()
ament_add_gtest(test_storage_policy_common rclcpp/wait_set_policies/test_storage_policy_common.cpp)
if(TARGET test_storage_policy_common)
ament_target_dependencies(test_storage_policy_common "rcl" "test_msgs")
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_static_storage rclcpp/wait_set_policies/test_static_storage.cpp)
if(TARGET test_static_storage)
ament_target_dependencies(test_static_storage "rcl" "test_msgs")
target_link_libraries(test_static_storage ${PROJECT_NAME})
endif()
ament_add_gtest(test_thread_safe_synchronization rclcpp/wait_set_policies/test_thread_safe_synchronization.cpp)
if(TARGET test_thread_safe_synchronization)
ament_target_dependencies(test_thread_safe_synchronization "rcl" "test_msgs")
target_link_libraries(test_thread_safe_synchronization ${PROJECT_NAME})
endif()
add_subdirectory(benchmark)
add_subdirectory(rclcpp)
ament_add_gtest(test_rclcpp_gtest_macros utils/test_rclcpp_gtest_macros.cpp)
if(TARGET test_rclcpp_gtest_macros)
target_link_libraries(test_rclcpp_gtest_macros ${PROJECT_NAME})
endif()
ament_add_gtest(test_rosout_qos rclcpp/test_rosout_qos.cpp)
if(TARGET test_rosout_qos)
ament_target_dependencies(test_rosout_qos "rcl")
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
endif()
ament_add_gtest(test_executor rclcpp/test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 120)
if(TARGET test_executor)
ament_target_dependencies(test_executor "rcl")
target_link_libraries(test_executor ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_graph_listener rclcpp/test_graph_listener.cpp)
if(TARGET test_graph_listener)
target_link_libraries(test_graph_listener ${PROJECT_NAME} mimick)
endif()
# Install test resources
install(
DIRECTORY resources

View File

@@ -0,0 +1,44 @@
find_package(ament_cmake_google_benchmark REQUIRED)
find_package(performance_test_fixture REQUIRED)
# These benchmarks are only being created and run for the default RMW
# implementation. We are looking to test the performance of the ROS 2 code, not
# the underlying middleware.
add_performance_test(benchmark_client benchmark_client.cpp)
if(TARGET benchmark_client)
target_link_libraries(benchmark_client ${PROJECT_NAME})
ament_target_dependencies(benchmark_client test_msgs rcl_interfaces)
endif()
add_performance_test(benchmark_executor benchmark_executor.cpp)
if(TARGET benchmark_executor)
target_link_libraries(benchmark_executor ${PROJECT_NAME})
ament_target_dependencies(benchmark_executor test_msgs)
endif()
add_performance_test(benchmark_init_shutdown benchmark_init_shutdown.cpp)
if(TARGET benchmark_init_shutdown)
target_link_libraries(benchmark_init_shutdown ${PROJECT_NAME})
endif()
add_performance_test(benchmark_node benchmark_node.cpp)
if(TARGET benchmark_node)
target_link_libraries(benchmark_node ${PROJECT_NAME})
endif()
add_performance_test(benchmark_node_parameters_interface benchmark_node_parameters_interface.cpp)
if(TARGET benchmark_node_parameters_interface)
target_link_libraries(benchmark_node_parameters_interface ${PROJECT_NAME})
endif()
ament_add_google_benchmark(benchmark_parameter_client benchmark_parameter_client.cpp)
if(TARGET benchmark_parameter_client)
target_link_libraries(benchmark_parameter_client ${PROJECT_NAME})
endif()
add_performance_test(benchmark_service benchmark_service.cpp)
if(TARGET benchmark_service)
target_link_libraries(benchmark_service ${PROJECT_NAME})
ament_target_dependencies(benchmark_service test_msgs rcl_interfaces)
endif()

View File

@@ -0,0 +1,153 @@
// Copyright 2020 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 <memory>
#include <string>
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/srv/empty.hpp"
using performance_test_fixture::PerformanceTest;
constexpr char empty_service_name[] = "empty_service";
class ClientPerformanceTest : public PerformanceTest
{
public:
explicit ClientPerformanceTest(rclcpp::NodeOptions = rclcpp::NodeOptions()) {}
void SetUp(benchmark::State & state)
{
rclcpp::init(0, nullptr);
node = std::make_unique<rclcpp::Node>("node", "ns");
auto empty_service_callback =
[](
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {};
empty_service =
node->create_service<test_msgs::srv::Empty>(empty_service_name, empty_service_callback);
performance_test_fixture::PerformanceTest::SetUp(state);
}
void TearDown(benchmark::State & state)
{
performance_test_fixture::PerformanceTest::TearDown(state);
empty_service.reset();
node.reset();
rclcpp::shutdown();
}
protected:
std::unique_ptr<rclcpp::Node> node;
std::shared_ptr<rclcpp::Service<test_msgs::srv::Empty>> empty_service;
};
BENCHMARK_F(ClientPerformanceTest, construct_client_no_service)(benchmark::State & state) {
// Prime cache
auto outer_client = node->create_client<test_msgs::srv::Empty>("not_an_existing_service");
outer_client.reset();
reset_heap_counters();
for (auto _ : state) {
auto client = node->create_client<test_msgs::srv::Empty>("not_an_existing_service");
benchmark::DoNotOptimize(client);
benchmark::ClobberMemory();
state.PauseTiming();
client.reset();
state.ResumeTiming();
}
}
BENCHMARK_F(ClientPerformanceTest, construct_client_empty_srv)(benchmark::State & state) {
// Prime cache
auto outer_client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
outer_client.reset();
reset_heap_counters();
for (auto _ : state) {
auto client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
benchmark::DoNotOptimize(client);
benchmark::ClobberMemory();
state.PauseTiming();
client.reset();
state.ResumeTiming();
}
}
BENCHMARK_F(ClientPerformanceTest, destroy_client_empty_srv)(benchmark::State & state) {
// Prime cache
auto outer_client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
outer_client.reset();
reset_heap_counters();
for (auto _ : state) {
state.PauseTiming();
auto client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
state.ResumeTiming();
benchmark::DoNotOptimize(client);
benchmark::ClobberMemory();
client.reset();
}
}
BENCHMARK_F(ClientPerformanceTest, wait_for_service)(benchmark::State & state) {
int count = 0;
for (auto _ : state) {
state.PauseTiming();
const std::string service_name = std::string("service_") + std::to_string(count++);
// Create client before service so it has to 'discover' the service after construction
auto client = node->create_client<test_msgs::srv::Empty>(service_name);
auto callback =
[](
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {};
auto service =
node->create_service<test_msgs::srv::Empty>(service_name, callback);
state.ResumeTiming();
client->wait_for_service(std::chrono::seconds(1));
benchmark::ClobberMemory();
}
}
BENCHMARK_F(ClientPerformanceTest, async_send_request_only)(benchmark::State & state) {
auto client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
auto shared_request = std::make_shared<test_msgs::srv::Empty::Request>();
reset_heap_counters();
for (auto _ : state) {
auto future = client->async_send_request(shared_request);
benchmark::DoNotOptimize(future);
benchmark::ClobberMemory();
}
}
BENCHMARK_F(ClientPerformanceTest, async_send_request_and_response)(benchmark::State & state) {
auto client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
auto shared_request = std::make_shared<test_msgs::srv::Empty::Request>();
reset_heap_counters();
for (auto _ : state) {
auto future = client->async_send_request(shared_request);
rclcpp::spin_until_future_complete(
node->get_node_base_interface(), future, std::chrono::seconds(1));
benchmark::DoNotOptimize(future);
benchmark::ClobberMemory();
}
}

View File

@@ -0,0 +1,390 @@
// Copyright 2020 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 <memory>
#include <string>
#include <utility>
#include <vector>
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/scope_exit.hpp"
#include "test_msgs/msg/empty.hpp"
using namespace std::chrono_literals;
using performance_test_fixture::PerformanceTest;
constexpr unsigned int kNumberOfNodes = 10;
class PerformanceTestExecutor : public PerformanceTest
{
public:
void SetUp(benchmark::State & st)
{
rclcpp::init(0, nullptr);
callback_count = 0;
for (unsigned int i = 0u; i < kNumberOfNodes; i++) {
nodes.push_back(std::make_shared<rclcpp::Node>("my_node_" + std::to_string(i)));
publishers.push_back(
nodes[i]->create_publisher<test_msgs::msg::Empty>(
"/empty_msgs_" + std::to_string(i), rclcpp::QoS(10)));
auto callback = [this](test_msgs::msg::Empty::SharedPtr) {this->callback_count++;};
subscriptions.push_back(
nodes[i]->create_subscription<test_msgs::msg::Empty>(
"/empty_msgs_" + std::to_string(i), rclcpp::QoS(10), std::move(callback)));
}
PerformanceTest::SetUp(st);
}
void TearDown(benchmark::State & st)
{
PerformanceTest::TearDown(st);
subscriptions.clear();
publishers.clear();
nodes.clear();
rclcpp::shutdown();
}
test_msgs::msg::Empty empty_msgs;
std::vector<rclcpp::Node::SharedPtr> nodes;
std::vector<rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr> publishers;
std::vector<rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr> subscriptions;
int callback_count;
};
BENCHMARK_F(PerformanceTestExecutor, single_thread_executor_spin_some)(benchmark::State & st)
{
rclcpp::executors::SingleThreadedExecutor executor;
for (unsigned int i = 0u; i < kNumberOfNodes; i++) {
executor.add_node(nodes[i]);
publishers[i]->publish(empty_msgs);
executor.spin_some(100ms);
}
callback_count = 0;
reset_heap_counters();
for (auto _ : st) {
st.PauseTiming();
for (unsigned int i = 0u; i < kNumberOfNodes; i++) {
publishers[i]->publish(empty_msgs);
}
st.ResumeTiming();
executor.spin_some(100ms);
}
if (callback_count == 0) {
st.SkipWithError("No message was received");
}
}
BENCHMARK_F(PerformanceTestExecutor, multi_thread_executor_spin_some)(benchmark::State & st)
{
rclcpp::executors::MultiThreadedExecutor executor;
for (unsigned int i = 0u; i < kNumberOfNodes; i++) {
executor.add_node(nodes[i]);
publishers[i]->publish(empty_msgs);
executor.spin_some(100ms);
}
callback_count = 0;
reset_heap_counters();
for (auto _ : st) {
st.PauseTiming();
for (unsigned int i = 0u; i < kNumberOfNodes; i++) {
publishers[i]->publish(empty_msgs);
}
st.ResumeTiming();
executor.spin_some(100ms);
}
if (callback_count == 0) {
st.SkipWithError("No message was received");
}
}
class PerformanceTestExecutorSimple : public PerformanceTest
{
public:
void SetUp(benchmark::State & st)
{
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>("my_node");
PerformanceTest::SetUp(st);
}
void TearDown(benchmark::State & st)
{
PerformanceTest::TearDown(st);
node.reset();
rclcpp::shutdown();
}
rclcpp::Node::SharedPtr node;
};
BENCHMARK_F(PerformanceTestExecutorSimple, single_thread_executor_add_node)(benchmark::State & st)
{
rclcpp::executors::SingleThreadedExecutor executor;
for (auto _ : st) {
executor.add_node(node);
st.PauseTiming();
executor.remove_node(node);
st.ResumeTiming();
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple, single_thread_executor_remove_node)(benchmark::State & st)
{
rclcpp::executors::SingleThreadedExecutor executor;
for (auto _ : st) {
st.PauseTiming();
executor.add_node(node);
st.ResumeTiming();
executor.remove_node(node);
}
}
BENCHMARK_F(PerformanceTestExecutorSimple, multi_thread_executor_add_node)(benchmark::State & st)
{
rclcpp::executors::MultiThreadedExecutor executor;
for (auto _ : st) {
executor.add_node(node);
st.PauseTiming();
executor.remove_node(node);
st.ResumeTiming();
}
}
BENCHMARK_F(PerformanceTestExecutorSimple, multi_thread_executor_remove_node)(benchmark::State & st)
{
rclcpp::executors::MultiThreadedExecutor executor;
for (auto _ : st) {
st.PauseTiming();
executor.add_node(node);
st.ResumeTiming();
executor.remove_node(node);
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_add_node)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
for (auto _ : st) {
executor.add_node(node);
st.PauseTiming();
executor.remove_node(node);
st.ResumeTiming();
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_remove_node)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
for (auto _ : st) {
st.PauseTiming();
executor.add_node(node);
st.ResumeTiming();
executor.remove_node(node);
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_spin_until_future_complete)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
auto ret = executor.spin_until_future_complete(shared_future, 100ms);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
}
reset_heap_counters();
for (auto _ : st) {
// static_single_thread_executor has a special design. We need to add/remove the node each
// time you call spin
st.PauseTiming();
executor.add_node(node);
st.ResumeTiming();
ret = executor.spin_until_future_complete(shared_future, 100ms);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
st.PauseTiming();
executor.remove_node(node);
st.ResumeTiming();
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
single_thread_executor_spin_node_until_future_complete)(benchmark::State & st)
{
rclcpp::executors::SingleThreadedExecutor executor;
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
auto ret = rclcpp::executors::spin_node_until_future_complete(
executor, node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
}
reset_heap_counters();
for (auto _ : st) {
ret = rclcpp::executors::spin_node_until_future_complete(
executor, node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
multi_thread_executor_spin_node_until_future_complete)(benchmark::State & st)
{
rclcpp::executors::MultiThreadedExecutor executor;
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
auto ret = rclcpp::executors::spin_node_until_future_complete(
executor, node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
}
reset_heap_counters();
for (auto _ : st) {
ret = rclcpp::executors::spin_node_until_future_complete(
executor, node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_single_thread_executor_spin_node_until_future_complete)(benchmark::State & st)
{
rclcpp::executors::StaticSingleThreadedExecutor executor;
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
reset_heap_counters();
for (auto _ : st) {
auto ret = rclcpp::executors::spin_node_until_future_complete(
executor, node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
}
}
BENCHMARK_F(PerformanceTestExecutorSimple, spin_until_future_complete)(benchmark::State & st)
{
// test success of an immediately finishing future
std::promise<bool> promise;
std::future<bool> future = promise.get_future();
promise.set_value(true);
auto shared_future = future.share();
auto ret = rclcpp::spin_until_future_complete(node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
}
reset_heap_counters();
for (auto _ : st) {
ret = rclcpp::spin_until_future_complete(node, shared_future, 1s);
if (ret != rclcpp::FutureReturnCode::SUCCESS) {
st.SkipWithError(rcutils_get_error_string().str);
break;
}
}
}
BENCHMARK_F(
PerformanceTestExecutorSimple,
static_executor_entities_collector_execute)(benchmark::State & st)
{
rclcpp::executors::StaticExecutorEntitiesCollector::SharedPtr entities_collector_ =
std::make_shared<rclcpp::executors::StaticExecutorEntitiesCollector>();
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
rcl_ret_t ret = rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator);
if (ret != RCL_RET_OK) {
st.SkipWithError(rcutils_get_error_string().str);
}
RCLCPP_SCOPE_EXIT(
{
rcl_ret_t ret = rcl_wait_set_fini(&wait_set);
if (ret != RCL_RET_OK) {
st.SkipWithError(rcutils_get_error_string().str);
}
});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
rcl_guard_condition_t rcl_guard_condition = guard_condition.get_rcl_guard_condition();
entities_collector_->init(&wait_set, memory_strategy, &rcl_guard_condition);
RCLCPP_SCOPE_EXIT(entities_collector_->fini());
reset_heap_counters();
for (auto _ : st) {
std::shared_ptr<void> data = entities_collector_->take_data();
entities_collector_->execute(data);
}
}

View File

@@ -0,0 +1,53 @@
// Copyright 2020 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 "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
using performance_test_fixture::PerformanceTest;
BENCHMARK_F(PerformanceTest, rclcpp_init)(benchmark::State & state)
{
// Warmup and prime caches
rclcpp::init(0, nullptr);
rclcpp::shutdown();
reset_heap_counters();
for (auto _ : state) {
rclcpp::init(0, nullptr);
state.PauseTiming();
rclcpp::shutdown();
state.ResumeTiming();
benchmark::ClobberMemory();
}
}
BENCHMARK_F(PerformanceTest, rclcpp_shutdown)(benchmark::State & state)
{
// Warmup and prime caches
rclcpp::init(0, nullptr);
rclcpp::shutdown();
reset_heap_counters();
for (auto _ : state) {
state.PauseTiming();
rclcpp::init(0, nullptr);
state.ResumeTiming();
rclcpp::shutdown();
benchmark::ClobberMemory();
}
}

View File

@@ -0,0 +1,77 @@
// Copyright 2020 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 <memory>
#include <string>
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
using performance_test_fixture::PerformanceTest;
class NodePerformanceTest : public PerformanceTest
{
public:
void SetUp(benchmark::State & state)
{
rclcpp::init(0, nullptr);
performance_test_fixture::PerformanceTest::SetUp(state);
}
void TearDown(benchmark::State & state)
{
performance_test_fixture::PerformanceTest::TearDown(state);
rclcpp::shutdown();
}
};
BENCHMARK_F(NodePerformanceTest, create_node)(benchmark::State & state)
{
// Warmup and prime caches
auto outer_node = std::make_shared<rclcpp::Node>("node");
outer_node.reset();
reset_heap_counters();
for (auto _ : state) {
// Using pointer to separate construction and destruction in timing
auto node = std::make_shared<rclcpp::Node>("node");
benchmark::DoNotOptimize(node);
benchmark::ClobberMemory();
// Ensure destruction of node is not counted toward timing
state.PauseTiming();
node.reset();
state.ResumeTiming();
}
}
BENCHMARK_F(NodePerformanceTest, destroy_node)(benchmark::State & state)
{
// Warmup and prime caches
auto outer_node = std::make_shared<rclcpp::Node>("node");
outer_node.reset();
reset_heap_counters();
for (auto _ : state) {
// Using pointer to separate construction and destruction in timing
state.PauseTiming();
auto node = std::make_shared<rclcpp::Node>("node");
state.ResumeTiming();
benchmark::DoNotOptimize(node);
benchmark::ClobberMemory();
node.reset();
}
}

View File

@@ -0,0 +1,262 @@
// Copyright 2020 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 <memory>
#include <string>
#include <vector>
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
class NodeParametersInterfaceTest : public performance_test_fixture::PerformanceTest
{
public:
NodeParametersInterfaceTest()
: node_name("my_node"),
param_prefix("my_prefix"),
param1_name(param_prefix + ".my_param_1"),
param2_name(param_prefix + ".my_param_2"),
param3_name(param_prefix + ".my_param_3")
{
}
void SetUp(benchmark::State & state)
{
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>(node_name);
node->declare_parameter(param1_name);
node->declare_parameter(param2_name);
node->declare_parameter(param3_name);
node->undeclare_parameter(param3_name);
performance_test_fixture::PerformanceTest::SetUp(state);
}
void TearDown(benchmark::State & state)
{
performance_test_fixture::PerformanceTest::TearDown(state);
node.reset();
rclcpp::shutdown();
}
const std::string node_name;
const std::string param_prefix;
const std::string param1_name;
const std::string param2_name;
const std::string param3_name;
protected:
rclcpp::Node::SharedPtr node;
};
BENCHMARK_F(NodeParametersInterfaceTest, declare_undeclare)(benchmark::State & state)
{
for (auto _ : state) {
node->declare_parameter(param3_name);
node->undeclare_parameter(param3_name);
}
}
BENCHMARK_F(NodeParametersInterfaceTest, has_parameter_hit)(benchmark::State & state)
{
for (auto _ : state) {
if (!node->has_parameter(param1_name)) {
state.SkipWithError("Parameter was expected");
break;
}
}
}
BENCHMARK_F(NodeParametersInterfaceTest, has_parameter_miss)(benchmark::State & state)
{
for (auto _ : state) {
if (node->has_parameter(param3_name)) {
state.SkipWithError("Parameter was not expected");
break;
}
}
}
BENCHMARK_F(NodeParametersInterfaceTest, set_parameters_bool)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, true),
rclcpp::Parameter(param2_name, false),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, false),
rclcpp::Parameter(param2_name, true),
};
reset_heap_counters();
for (auto _ : state) {
node->set_parameters(param_values2);
node->set_parameters(param_values1);
}
}
BENCHMARK_F(NodeParametersInterfaceTest, set_parameters_atomically_bool)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, true),
rclcpp::Parameter(param2_name, false),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, false),
rclcpp::Parameter(param2_name, true),
};
reset_heap_counters();
for (auto _ : state) {
node->set_parameters_atomically(param_values2);
node->set_parameters_atomically(param_values1);
}
}
BENCHMARK_F(NodeParametersInterfaceTest, set_parameters_callback_bool)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, true),
rclcpp::Parameter(param2_name, false),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, false),
rclcpp::Parameter(param2_name, true),
};
rcl_interfaces::msg::SetParametersResult callback_result;
bool callback_received = false;
callback_result.successful = true;
auto callback =
[&callback_result, &callback_received](const std::vector<rclcpp::Parameter> &) {
callback_received = true;
return callback_result;
};
auto handle = node->add_on_set_parameters_callback(callback);
reset_heap_counters();
for (auto _ : state) {
node->set_parameters(param_values2);
node->set_parameters(param_values1);
}
if (!callback_received) {
state.SkipWithError("Callback is not functioning");
}
node->remove_on_set_parameters_callback(handle.get());
}
BENCHMARK_F(NodeParametersInterfaceTest, set_parameters_string)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, "param 1 value A"),
rclcpp::Parameter(param2_name, "param 2 value B"),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, "param 1 value B"),
rclcpp::Parameter(param2_name, "param 2 value A"),
};
reset_heap_counters();
for (auto _ : state) {
node->set_parameters(param_values2);
node->set_parameters(param_values1);
}
}
BENCHMARK_F(NodeParametersInterfaceTest, set_parameters_array)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, std::vector<int> {0, 1, 2}),
rclcpp::Parameter(param2_name, std::vector<int> {3, 4, 5}),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, std::vector<int> {4, 5, 6}),
rclcpp::Parameter(param2_name, std::vector<int> {7, 8, 9}),
};
reset_heap_counters();
for (auto _ : state) {
node->set_parameters(param_values2);
node->set_parameters(param_values1);
}
}
BENCHMARK_F(NodeParametersInterfaceTest, get_parameter)(benchmark::State & state)
{
rclcpp::Parameter param1_value;
reset_heap_counters();
for (auto _ : state) {
node->get_parameter(param1_name, param1_value);
}
}
BENCHMARK_F(NodeParametersInterfaceTest, list_parameters_hit)(benchmark::State & state)
{
rcl_interfaces::msg::ListParametersResult param_list;
const std::vector<std::string> prefixes
{
param_prefix,
};
reset_heap_counters();
for (auto _ : state) {
param_list = node->list_parameters(prefixes, 10);
if (param_list.names.size() != 2) {
state.SkipWithError("Expected node names");
break;
}
}
}
BENCHMARK_F(NodeParametersInterfaceTest, list_parameters_miss)(benchmark::State & state)
{
rcl_interfaces::msg::ListParametersResult param_list;
const std::vector<std::string> prefixes
{
"your_param",
};
reset_heap_counters();
for (auto _ : state) {
param_list = node->list_parameters(prefixes, 10);
if (param_list.names.size() != 0) {
state.SkipWithError("Expected no node names");
break;
}
}
}

View File

@@ -0,0 +1,324 @@
// Copyright 2020 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 <memory>
#include <vector>
#include <string>
#include "benchmark/benchmark.h"
#include "rclcpp/rclcpp.hpp"
class RemoteNodeTest : public benchmark::Fixture
{
public:
RemoteNodeTest()
: remote_node_name("my_remote_node")
{
}
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
void SetUp(benchmark::State &)
{
remote_context = std::make_shared<rclcpp::Context>();
remote_context->init(0, nullptr, rclcpp::InitOptions().auto_initialize_logging(false));
rclcpp::ExecutorOptions exec_options;
exec_options.context = remote_context;
remote_executor = std::make_shared<rclcpp::executors::SingleThreadedExecutor>(exec_options);
remote_node = std::make_shared<rclcpp::Node>(
remote_node_name, rclcpp::NodeOptions().context(remote_context));
remote_executor->add_node(remote_node);
remote_thread = std::thread(&rclcpp::executors::SingleThreadedExecutor::spin, remote_executor);
}
void TearDown(benchmark::State &)
{
remote_executor->cancel();
remote_context->shutdown("Test is complete");
remote_thread.join();
remote_node.reset();
remote_executor.reset();
remote_context.reset();
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
const std::string remote_node_name;
protected:
rclcpp::Context::SharedPtr remote_context;
rclcpp::executors::SingleThreadedExecutor::SharedPtr remote_executor;
rclcpp::Node::SharedPtr remote_node;
std::thread remote_thread;
};
class ParameterClientTest : public RemoteNodeTest
{
public:
ParameterClientTest()
: node_name("my_node"),
param_prefix("my_prefix"),
param1_name(param_prefix + ".my_param_1"),
param2_name(param_prefix + ".my_param_2"),
param3_name(param_prefix + ".my_param_3")
{
}
void SetUp(benchmark::State & state)
{
RemoteNodeTest::SetUp(state);
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>(node_name);
remote_node->declare_parameter(
param1_name, rclcpp::ParameterValue("param1_value"));
remote_node->declare_parameter(
param2_name, rclcpp::ParameterValue(std::vector<int> {1, 2, 3}));
remote_node->declare_parameter(param3_name);
remote_node->undeclare_parameter(param3_name);
params_client = std::make_shared<rclcpp::SyncParametersClient>(node, remote_node_name);
if (!params_client->wait_for_service()) {
state.SkipWithError("Client failed to become ready");
}
}
void TearDown(benchmark::State & state)
{
RemoteNodeTest::TearDown(state);
rclcpp::shutdown();
node.reset();
params_client.reset();
}
const std::string node_name;
const std::string param_prefix;
const std::string param1_name;
const std::string param2_name;
const std::string param3_name;
protected:
rclcpp::Node::SharedPtr node;
rclcpp::SyncParametersClient::SharedPtr params_client;
};
static bool result_is_successful(rcl_interfaces::msg::SetParametersResult result)
{
return result.successful;
}
BENCHMARK_F(ParameterClientTest, create_destroy_client)(benchmark::State & state)
{
for (auto _ : state) {
params_client.reset();
params_client = std::make_shared<rclcpp::SyncParametersClient>(node, remote_node_name);
if (!params_client->wait_for_service()) {
state.SkipWithError("Client failed to become ready");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, has_parameter_hit)(benchmark::State & state)
{
for (auto _ : state) {
if (!params_client->has_parameter(param1_name)) {
state.SkipWithError("Parameter was expected");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, has_parameter_miss)(benchmark::State & state)
{
for (auto _ : state) {
if (params_client->has_parameter(param3_name)) {
state.SkipWithError("Parameter was not expected");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, set_parameters_bool)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, true),
rclcpp::Parameter(param2_name, false),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, false),
rclcpp::Parameter(param2_name, true),
};
for (auto _ : state) {
std::vector<rcl_interfaces::msg::SetParametersResult> results =
params_client->set_parameters(param_values2);
if (!std::all_of(results.begin(), results.end(), result_is_successful)) {
state.SkipWithError("Failed to set one or more parameters");
break;
}
results = params_client->set_parameters(param_values1);
if (!std::all_of(results.begin(), results.end(), result_is_successful)) {
state.SkipWithError("Failed to set one or more parameters");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, set_parameters_atomically_bool)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, true),
rclcpp::Parameter(param2_name, false),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, false),
rclcpp::Parameter(param2_name, true),
};
for (auto _ : state) {
rcl_interfaces::msg::SetParametersResult result =
params_client->set_parameters_atomically(param_values2);
if (!result.successful) {
state.SkipWithError(("Failed to set parameters: " + result.reason).c_str());
break;
}
result = params_client->set_parameters_atomically(param_values1);
if (!result.successful) {
state.SkipWithError(("Failed to set parameters: " + result.reason).c_str());
break;
}
}
}
BENCHMARK_F(ParameterClientTest, set_parameters_string)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, "param 1 value A"),
rclcpp::Parameter(param2_name, "param 2 value B"),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, "param 1 value B"),
rclcpp::Parameter(param2_name, "param 2 value A"),
};
for (auto _ : state) {
std::vector<rcl_interfaces::msg::SetParametersResult> results =
params_client->set_parameters(param_values2);
if (!std::all_of(results.begin(), results.end(), result_is_successful)) {
state.SkipWithError("Failed to set one or more parameters");
break;
}
results = params_client->set_parameters(param_values1);
if (!std::all_of(results.begin(), results.end(), result_is_successful)) {
state.SkipWithError("Failed to set one or more parameters");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, set_parameters_array)(benchmark::State & state)
{
const std::vector<rclcpp::Parameter> param_values1
{
rclcpp::Parameter(param1_name, std::vector<int> {0, 1, 2}),
rclcpp::Parameter(param2_name, std::vector<int> {3, 4, 5}),
};
const std::vector<rclcpp::Parameter> param_values2
{
rclcpp::Parameter(param1_name, std::vector<int> {4, 5, 6}),
rclcpp::Parameter(param2_name, std::vector<int> {7, 8, 9}),
};
for (auto _ : state) {
std::vector<rcl_interfaces::msg::SetParametersResult> results =
params_client->set_parameters(param_values2);
if (!std::all_of(results.begin(), results.end(), result_is_successful)) {
state.SkipWithError("Failed to set one or more parameters");
break;
}
results = params_client->set_parameters(param_values1);
if (!std::all_of(results.begin(), results.end(), result_is_successful)) {
state.SkipWithError("Failed to set one or more parameters");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, get_parameters)(benchmark::State & state)
{
for (auto _ : state) {
std::vector<rclcpp::Parameter> results = params_client->get_parameters({param1_name});
if (results.size() != 1 || results[0].get_name() != param1_name) {
state.SkipWithError("Got the wrong parameter(s)");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, list_parameters_hit)(benchmark::State & state)
{
const std::vector<std::string> prefixes
{
param_prefix,
};
for (auto _ : state) {
rcl_interfaces::msg::ListParametersResult param_list =
params_client->list_parameters(prefixes, 10);
if (param_list.names.size() != 2) {
state.SkipWithError("Expected parameters");
break;
}
}
}
BENCHMARK_F(ParameterClientTest, list_parameters_miss)(benchmark::State & state)
{
const std::vector<std::string> prefixes
{
"your_prefix",
};
for (auto _ : state) {
rcl_interfaces::msg::ListParametersResult param_list =
params_client->list_parameters(prefixes, 10);
if (param_list.names.size() != 0) {
state.SkipWithError("Expected no parameters");
break;
}
}
}

View File

@@ -0,0 +1,141 @@
// Copyright 2020 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 <memory>
#include "performance_test_fixture/performance_test_fixture.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/srv/empty.hpp"
using performance_test_fixture::PerformanceTest;
constexpr char empty_service_name[] = "empty_service";
class ServicePerformanceTest : public PerformanceTest
{
public:
ServicePerformanceTest()
: callback_count(0) {}
void SetUp(benchmark::State & state)
{
rclcpp::init(0, nullptr);
node = std::make_unique<rclcpp::Node>("node", "ns");
empty_client = node->create_client<test_msgs::srv::Empty>(empty_service_name);
callback_count = 0;
performance_test_fixture::PerformanceTest::SetUp(state);
}
void TearDown(benchmark::State & state)
{
performance_test_fixture::PerformanceTest::TearDown(state);
empty_client.reset();
node.reset();
rclcpp::shutdown();
}
void ServiceCallback(
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr)
{
callback_count++;
}
protected:
std::unique_ptr<rclcpp::Node> node;
std::shared_ptr<rclcpp::Client<test_msgs::srv::Empty>> empty_client;
int callback_count;
};
BENCHMARK_F(ServicePerformanceTest, construct_service_no_client)(benchmark::State & state) {
auto callback = std::bind(
&ServicePerformanceTest::ServiceCallback,
this, std::placeholders::_1, std::placeholders::_2);
auto outer_service = node->create_service<test_msgs::srv::Empty>("not_a_service", callback);
reset_heap_counters();
for (auto _ : state) {
auto service = node->create_service<test_msgs::srv::Empty>("not_a_service", callback);
benchmark::DoNotOptimize(service);
benchmark::ClobberMemory();
state.PauseTiming();
service.reset();
state.ResumeTiming();
}
}
BENCHMARK_F(ServicePerformanceTest, construct_service_empty_srv)(benchmark::State & state) {
auto callback = std::bind(
&ServicePerformanceTest::ServiceCallback,
this, std::placeholders::_1, std::placeholders::_2);
auto outer_service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
reset_heap_counters();
for (auto _ : state) {
auto service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
benchmark::DoNotOptimize(service);
benchmark::ClobberMemory();
state.PauseTiming();
service.reset();
state.ResumeTiming();
}
}
BENCHMARK_F(ServicePerformanceTest, destroy_service_empty_srv)(benchmark::State & state) {
auto callback = std::bind(
&ServicePerformanceTest::ServiceCallback,
this, std::placeholders::_1, std::placeholders::_2);
auto outer_service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
reset_heap_counters();
for (auto _ : state) {
state.PauseTiming();
auto service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
state.ResumeTiming();
benchmark::DoNotOptimize(service);
benchmark::ClobberMemory();
service.reset();
}
}
BENCHMARK_F(ServicePerformanceTest, async_send_response)(benchmark::State & state) {
auto callback = std::bind(
&ServicePerformanceTest::ServiceCallback,
this, std::placeholders::_1, std::placeholders::_2);
auto service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
reset_heap_counters();
for (auto _ : state) {
state.PauseTiming();
// Clear executor queue
rclcpp::spin_some(node->get_node_base_interface());
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
auto future = empty_client->async_send_request(request);
state.ResumeTiming();
benchmark::DoNotOptimize(service);
benchmark::ClobberMemory();
rclcpp::spin_until_future_complete(node->get_node_base_interface(), future);
}
if (callback_count == 0) {
state.SkipWithError("Service callback was not called");
}
}

View File

@@ -0,0 +1,665 @@
find_package(ament_cmake_gtest REQUIRED)
find_package(rmw_implementation_cmake REQUIRED)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/../resources")
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
../msg/Header.msg
../msg/MessageWithHeader.msg
DEPENDENCIES builtin_interfaces
LIBRARY_NAME ${PROJECT_NAME}
SKIP_INSTALL
)
ament_add_gtest(
test_allocator_common
allocator/test_allocator_common.cpp)
if(TARGET test_allocator_common)
target_link_libraries(test_allocator_common ${PROJECT_NAME})
endif()
ament_add_gtest(
test_allocator_deleter
allocator/test_allocator_deleter.cpp)
if(TARGET test_allocator_deleter)
target_link_libraries(test_allocator_deleter ${PROJECT_NAME})
endif()
ament_add_gtest(
test_exceptions
exceptions/test_exceptions.cpp)
if(TARGET test_exceptions)
target_link_libraries(test_exceptions ${PROJECT_NAME} mimick)
endif()
# Increasing timeout because connext can take a long time to destroy nodes
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
# https://github.com/ros2/rclcpp/issues/1250
ament_add_gtest(
test_allocator_memory_strategy
strategies/test_allocator_memory_strategy.cpp
TIMEOUT 360)
if(TARGET test_allocator_memory_strategy)
ament_target_dependencies(test_allocator_memory_strategy
"rcl"
"test_msgs"
)
target_link_libraries(test_allocator_memory_strategy ${PROJECT_NAME})
endif()
ament_add_gtest(test_message_pool_memory_strategy strategies/test_message_pool_memory_strategy.cpp)
if(TARGET test_message_pool_memory_strategy)
ament_target_dependencies(test_message_pool_memory_strategy
"rcl"
"test_msgs"
)
target_link_libraries(test_message_pool_memory_strategy ${PROJECT_NAME})
endif()
ament_add_gtest(test_any_service_callback test_any_service_callback.cpp)
if(TARGET test_any_service_callback)
ament_target_dependencies(test_any_service_callback
"test_msgs"
)
target_link_libraries(test_any_service_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_any_subscription_callback test_any_subscription_callback.cpp)
if(TARGET test_any_subscription_callback)
ament_target_dependencies(test_any_subscription_callback
"test_msgs"
)
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_client test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_client ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_create_timer test_create_timer.cpp)
if(TARGET test_create_timer)
ament_target_dependencies(test_create_timer
"rcl_interfaces"
"rmw"
"rcl"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_create_timer ${PROJECT_NAME})
target_include_directories(test_create_timer PRIVATE ./)
endif()
ament_add_gtest(test_create_subscription test_create_subscription.cpp)
if(TARGET test_create_subscription)
target_link_libraries(test_create_subscription ${PROJECT_NAME})
ament_target_dependencies(test_create_subscription
"test_msgs"
)
endif()
ament_add_gtest(test_add_callback_groups_to_executor
test_add_callback_groups_to_executor.cpp
TIMEOUT 120)
if(TARGET test_add_callback_groups_to_executor)
target_link_libraries(test_add_callback_groups_to_executor ${PROJECT_NAME})
ament_target_dependencies(test_add_callback_groups_to_executor
"test_msgs"
)
endif()
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_function_traits test_function_traits.cpp)
if(TARGET test_function_traits)
target_include_directories(test_function_traits PUBLIC ../../include)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
endif()
ament_add_gtest(
test_future_return_code
test_future_return_code.cpp)
if(TARGET test_future_return_code)
target_link_libraries(test_future_return_code ${PROJECT_NAME})
endif()
ament_add_gmock(test_intra_process_manager test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
endif()
ament_add_gtest(test_intra_process_buffer test_intra_process_buffer.cpp)
if(TARGET test_intra_process_buffer)
ament_target_dependencies(test_intra_process_buffer
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
endif()
ament_add_gtest(test_loaned_message test_loaned_message.cpp)
ament_target_dependencies(test_loaned_message
"test_msgs"
)
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick)
ament_add_gtest(test_memory_strategy test_memory_strategy.cpp)
ament_target_dependencies(test_memory_strategy
"test_msgs"
)
target_link_libraries(test_memory_strategy ${PROJECT_NAME})
ament_add_gtest(test_message_memory_strategy test_message_memory_strategy.cpp)
ament_target_dependencies(test_message_memory_strategy
"test_msgs"
)
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME})
ament_add_gtest(test_node test_node.cpp TIMEOUT 240)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rcpputils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_node ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__get_node_interfaces
node_interfaces/test_get_node_interfaces.cpp)
if(TARGET test_node_interfaces__get_node_interfaces)
target_link_libraries(test_node_interfaces__get_node_interfaces ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_base
node_interfaces/test_node_base.cpp)
if(TARGET test_node_interfaces__node_base)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_clock
node_interfaces/test_node_clock.cpp)
if(TARGET test_node_interfaces__node_clock)
target_link_libraries(test_node_interfaces__node_clock ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_graph
node_interfaces/test_node_graph.cpp
TIMEOUT 120)
if(TARGET test_node_interfaces__node_graph)
ament_target_dependencies(
test_node_interfaces__node_graph
"test_msgs")
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_parameters
node_interfaces/test_node_parameters.cpp)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_services
node_interfaces/test_node_services.cpp)
if(TARGET test_node_interfaces__node_services)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_timers
node_interfaces/test_node_timers.cpp)
if(TARGET test_node_interfaces__node_timers)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_topics
node_interfaces/test_node_topics.cpp)
if(TARGET test_node_interfaces__node_topics)
ament_target_dependencies(
test_node_interfaces__node_topics
"test_msgs")
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_node_interfaces__node_waitables
node_interfaces/test_node_waitables.cpp)
if(TARGET test_node_interfaces__node_waitables)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick)
endif()
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_wrapped_node
# node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_wrapped_node
# node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
ament_add_gtest(test_node_global_args test_node_global_args.cpp)
if(TARGET test_node_global_args)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_options test_node_options.cpp)
if(TARGET test_node_options)
ament_target_dependencies(test_node_options "rcl")
target_link_libraries(test_node_options ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_init_options test_init_options.cpp)
if(TARGET test_init_options)
ament_target_dependencies(test_init_options "rcl")
target_link_libraries(test_init_options ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_parameter_client test_parameter_client.cpp)
if(TARGET test_parameter_client)
ament_target_dependencies(test_parameter_client
"rcl_interfaces"
)
target_link_libraries(test_parameter_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_service test_parameter_service.cpp)
if(TARGET test_parameter_service)
ament_target_dependencies(test_parameter_service
"rcl_interfaces"
)
target_link_libraries(test_parameter_service ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_events_filter test_parameter_events_filter.cpp)
if(TARGET test_parameter_events_filter)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter test_parameter.cpp)
if(TARGET test_parameter)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_map test_parameter_map.cpp)
if(TARGET test_parameter_map)
target_link_libraries(test_parameter_map ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher test_publisher.cpp TIMEOUT 120)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rcl"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_publisher_subscription_count_api test_publisher_subscription_count_api.cpp)
if(TARGET test_publisher_subscription_count_api)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_qos test_qos.cpp)
if(TARGET test_qos)
ament_target_dependencies(test_qos
"rmw"
)
target_link_libraries(test_qos
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_qos_event test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
"rmw"
"test_msgs"
)
target_link_libraries(test_qos_event
${PROJECT_NAME}
mimick
)
endif()
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
if(TARGET test_qos_overriding_options)
target_link_libraries(test_qos_overriding_options
${PROJECT_NAME}
)
endif()
ament_add_gmock(test_qos_parameters test_qos_parameters.cpp)
if(TARGET test_qos_parameters)
target_link_libraries(test_qos_parameters
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_rate test_rate.cpp)
if(TARGET test_rate)
ament_target_dependencies(test_rate
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_rate
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message_allocator test_serialized_message_allocator.cpp)
if(TARGET test_serialized_message_allocator)
ament_target_dependencies(test_serialized_message_allocator
test_msgs
)
target_link_libraries(test_serialized_message_allocator
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message test_serialized_message.cpp)
if(TARGET test_serialized_message)
ament_target_dependencies(test_serialized_message
test_msgs
)
target_link_libraries(test_serialized_message
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_service test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_service ${PROJECT_NAME} mimick)
endif()
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
if(TARGET test_subscription)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_subscription_publisher_count_api test_subscription_publisher_count_api.cpp)
if(TARGET test_subscription_publisher_count_api)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_traits test_subscription_traits.cpp)
if(TARGET test_subscription_traits)
ament_target_dependencies(test_subscription_traits
"rcl"
"test_msgs"
)
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_type_support test_type_support.cpp)
if(TARGET test_type_support)
ament_target_dependencies(test_type_support
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_type_support ${PROJECT_NAME})
endif()
ament_add_gtest(test_find_weak_nodes test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
"rcl"
)
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
endif()
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
if(WIN32)
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
endif()
ament_add_gtest(test_externally_defined_services test_externally_defined_services.cpp)
ament_target_dependencies(test_externally_defined_services
"rcl"
"test_msgs"
)
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
ament_add_gtest(test_duration test_duration.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_duration)
ament_target_dependencies(test_duration
"rcl")
target_link_libraries(test_duration ${PROJECT_NAME})
endif()
ament_add_gtest(test_logger test_logger.cpp)
target_link_libraries(test_logger ${PROJECT_NAME})
ament_add_gmock(test_logging test_logging.cpp)
target_link_libraries(test_logging ${PROJECT_NAME})
ament_add_gtest(test_time test_time.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time)
ament_target_dependencies(test_time
"rcl")
target_link_libraries(test_time ${PROJECT_NAME})
endif()
ament_add_gtest(test_timer test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer)
ament_target_dependencies(test_timer
"rcl")
target_link_libraries(test_timer ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_time_source test_time_source.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time_source)
ament_target_dependencies(test_time_source
"rcl")
target_link_libraries(test_time_source ${PROJECT_NAME})
endif()
ament_add_gtest(test_utilities test_utilities.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_utilities)
ament_target_dependencies(test_utilities
"rcl")
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_init test_init.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_init)
ament_target_dependencies(test_init
"rcl")
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
# https://github.com/ros2/rclcpp/issues/1250
ament_add_gtest(
test_executors
executors/test_executors.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 180)
if(TARGET test_executors)
ament_target_dependencies(test_executors
"rcl"
"test_msgs")
target_link_libraries(test_executors ${PROJECT_NAME})
endif()
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_static_single_threaded_executor)
ament_target_dependencies(test_static_single_threaded_executor
"test_msgs")
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_multi_threaded_executor executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
ament_target_dependencies(test_multi_threaded_executor
"rcl")
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_static_executor_entities_collector executors/test_static_executor_entities_collector.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
if(TARGET test_static_executor_entities_collector)
ament_target_dependencies(test_static_executor_entities_collector
"rcl"
"test_msgs")
target_link_libraries(test_static_executor_entities_collector ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_guard_condition test_guard_condition.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_wait_set test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)
ament_target_dependencies(test_wait_set "test_msgs")
target_link_libraries(test_wait_set ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_topic_statistics topic_statistics/test_subscription_topic_statistics.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"builtin_interfaces"
"libstatistics_collector"
"rcl_interfaces"
"rcutils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
rosidl_target_interfaces(test_subscription_topic_statistics ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
target_link_libraries(test_subscription_topic_statistics ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_options test_subscription_options.cpp)
if(TARGET test_subscription_options)
ament_target_dependencies(test_subscription_options "rcl")
target_link_libraries(test_subscription_options ${PROJECT_NAME})
endif()
ament_add_gtest(test_dynamic_storage wait_set_policies/test_dynamic_storage.cpp)
if(TARGET test_dynamic_storage)
ament_target_dependencies(test_dynamic_storage "rcl" "test_msgs")
target_link_libraries(test_dynamic_storage ${PROJECT_NAME})
endif()
ament_add_gtest(test_storage_policy_common wait_set_policies/test_storage_policy_common.cpp)
if(TARGET test_storage_policy_common)
ament_target_dependencies(test_storage_policy_common "rcl" "test_msgs")
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_static_storage wait_set_policies/test_static_storage.cpp)
if(TARGET test_static_storage)
ament_target_dependencies(test_static_storage "rcl" "test_msgs")
target_link_libraries(test_static_storage ${PROJECT_NAME})
endif()
ament_add_gtest(test_thread_safe_synchronization wait_set_policies/test_thread_safe_synchronization.cpp)
if(TARGET test_thread_safe_synchronization)
ament_target_dependencies(test_thread_safe_synchronization "rcl" "test_msgs")
target_link_libraries(test_thread_safe_synchronization ${PROJECT_NAME})
endif()
ament_add_gtest(test_rosout_qos test_rosout_qos.cpp)
if(TARGET test_rosout_qos)
ament_target_dependencies(test_rosout_qos "rcl")
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
endif()
ament_add_gtest(test_executor test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 120)
if(TARGET test_executor)
ament_target_dependencies(test_executor "rcl")
target_link_libraries(test_executor ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_graph_listener test_graph_listener.cpp)
if(TARGET test_graph_listener)
target_link_libraries(test_graph_listener ${PROJECT_NAME} mimick)
endif()

View File

@@ -23,7 +23,9 @@ TEST(TestAllocatorCommon, retyped_allocate) {
void * untyped_allocator = &allocator;
void * allocated_mem =
rclcpp::allocator::retyped_allocate<std::allocator<char>>(1u, untyped_allocator);
ASSERT_NE(nullptr, allocated_mem);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
auto code = [&untyped_allocator, allocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
@@ -32,11 +34,15 @@ TEST(TestAllocatorCommon, retyped_allocate) {
EXPECT_NO_THROW(code());
allocated_mem = allocator.allocate(1);
ASSERT_NE(nullptr, allocated_mem);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
void * reallocated_mem =
rclcpp::allocator::retyped_reallocate<int, std::allocator<int>>(
allocated_mem, 2u, untyped_allocator);
ASSERT_NE(nullptr, reallocated_mem);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != reallocated_mem);
auto code2 = [&untyped_allocator, reallocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(

View File

@@ -38,7 +38,9 @@ TEST(TestAllocatorDeleter, construct_destruct) {
TEST(TestAllocatorDeleter, delete) {
std::allocator<int> allocator;
int * some_mem = allocator.allocate(1u);
ASSERT_NE(nullptr, some_mem);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != some_mem);
rclcpp::allocator::AllocatorDeleter<std::allocator<int>> deleter(&allocator);
EXPECT_NO_THROW(deleter(some_mem));

View File

@@ -115,9 +115,9 @@ public:
}
};
// TYPED_TEST_CASE is deprecated as of gtest 1.9, use TYPED_TEST_SUITE when gtest dependency
// TYPED_TEST_SUITE is deprecated as of gtest 1.9, use TYPED_TEST_SUITE when gtest dependency
// is updated.
TYPED_TEST_CASE(TestExecutors, ExecutorTypes, ExecutorTypeNames);
TYPED_TEST_SUITE(TestExecutors, ExecutorTypes, ExecutorTypeNames);
// StaticSingleThreadedExecutor is not included in these tests for now, due to:
// https://github.com/ros2/rclcpp/issues/1219
@@ -125,7 +125,7 @@ using StandardExecutors =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor>;
TYPED_TEST_CASE(TestExecutorsStable, StandardExecutors, ExecutorTypeNames);
TYPED_TEST_SUITE(TestExecutorsStable, StandardExecutors, ExecutorTypeNames);
// Make sure that executors detach from nodes when destructing
TYPED_TEST(TestExecutors, detachOnDestruction) {
@@ -436,9 +436,16 @@ public:
return true;
}
void
execute() override
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void
execute(std::shared_ptr<void> & data) override
{
(void) data;
count_++;
std::this_thread::sleep_for(1ms);
}

View File

@@ -235,7 +235,16 @@ public:
bool is_ready(rcl_wait_set_t *) override {return true;}
void execute() override {}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void
execute(std::shared_ptr<void> & data) override
{
(void) data;
}
};
TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_with_entities) {
@@ -363,8 +372,9 @@ TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_clear_
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
std::shared_ptr<void> data = entities_collector_->take_data();
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->execute(),
entities_collector_->execute(data),
std::runtime_error("Couldn't clear wait set"));
}
@@ -393,8 +403,9 @@ TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_resize
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_resize, RCL_RET_ERROR);
std::shared_ptr<void> data = entities_collector_->take_data();
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->execute(),
entities_collector_->execute(data),
std::runtime_error("Couldn't resize the wait set: error not set"));
}
@@ -616,7 +627,8 @@ TEST_F(
RCLCPP_SCOPE_EXIT(entities_collector_->fini());
cb_group->get_associated_with_executor_atomic().exchange(false);
entities_collector_->execute();
std::shared_ptr<void> data = entities_collector_->take_data();
entities_collector_->execute(data);
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}

View File

@@ -14,9 +14,11 @@
#include <gtest/gtest.h>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "rcl/graph.h"
#include "rcl/node_options.h"
@@ -66,6 +68,43 @@ protected:
const rclcpp::node_interfaces::NodeGraph * node_graph() const {return node_graph_;}
size_t get_num_graph_things(std::function<size_t()> predicate)
{
constexpr std::chrono::milliseconds timeout(100);
size_t tries = 0;
size_t num_things = 0;
while (tries++ < 5) {
num_things = predicate();
if (num_things >= 1) {
break;
}
auto event = node()->get_graph_event();
EXPECT_NO_THROW(node()->wait_for_graph_change(event, timeout));
}
return num_things;
}
size_t get_num_topics()
{
return get_num_graph_things(
[this]() -> size_t {
auto topic_names_and_types = node_graph()->get_topic_names_and_types();
return topic_names_and_types.size();
});
}
size_t get_num_services()
{
return get_num_graph_things(
[this]() -> size_t {
auto service_names_and_types = node_graph()->get_service_names_and_types();
return service_names_and_types.size();
});
}
private:
std::shared_ptr<rclcpp::Node> node_;
rclcpp::node_interfaces::NodeGraph * node_graph_;
@@ -73,11 +112,9 @@ private:
TEST_F(TestNodeGraph, construct_from_node)
{
auto topic_names_and_types = node_graph()->get_topic_names_and_types(false);
EXPECT_LT(0u, topic_names_and_types.size());
EXPECT_LT(0u, get_num_topics());
auto service_names_and_types = node_graph()->get_service_names_and_types();
EXPECT_LT(0u, service_names_and_types.size());
EXPECT_LT(0u, get_num_services());
auto names = node_graph()->get_node_names();
EXPECT_EQ(1u, names.size());
@@ -91,13 +128,12 @@ TEST_F(TestNodeGraph, construct_from_node)
// get_graph_event is non-const
EXPECT_NE(nullptr, node()->get_node_graph_interface()->get_graph_event());
EXPECT_EQ(1u, node_graph()->count_graph_users());
EXPECT_LE(1u, node_graph()->count_graph_users());
}
TEST_F(TestNodeGraph, get_topic_names_and_types)
{
auto topic_names_and_types = node_graph()->get_topic_names_and_types();
EXPECT_LT(0u, topic_names_and_types.size());
ASSERT_LT(0u, get_num_topics());
}
TEST_F(TestNodeGraph, get_topic_names_and_types_rcl_error)
@@ -126,8 +162,7 @@ TEST_F(TestNodeGraph, get_topic_names_and_types_rcl_names_and_types_fini_error)
TEST_F(TestNodeGraph, get_service_names_and_types)
{
auto service_names_and_types = node_graph()->get_service_names_and_types();
EXPECT_LT(0u, service_names_and_types.size());
ASSERT_LT(0u, get_num_services());
}
TEST_F(TestNodeGraph, get_service_names_and_types_rcl_error)
@@ -309,8 +344,13 @@ TEST_F(TestNodeGraph, get_info_by_topic)
EXPECT_EQ(0u, node_graph()->get_publishers_info_by_topic("topic", true).size());
auto publishers = node_graph()->get_publishers_info_by_topic("topic", false);
ASSERT_EQ(1u, publishers.size());
std::vector<rclcpp::TopicEndpointInfo> publishers;
size_t num_publishers = get_num_graph_things(
[this, &publishers]() {
publishers = node_graph()->get_publishers_info_by_topic("topic", false);
return publishers.size();
});
ASSERT_EQ(1u, num_publishers);
auto publisher_endpoint_info = publishers[0];
const auto const_publisher_endpoint_info = publisher_endpoint_info;

View File

@@ -16,6 +16,7 @@
#include <memory>
#include <string>
#include <vector>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
@@ -55,7 +56,9 @@ public:
{
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::NodeOptions options{};
options.arguments(std::vector<std::string>{"-r", "foo:=bar"});
node = std::make_shared<rclcpp::Node>("node", "ns", options);
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
@@ -129,3 +132,13 @@ TEST_F(TestNodeService, add_client_rcl_trigger_guard_condition_error)
node_services->add_client(client, callback_group),
std::runtime_error("Failed to notify wait set on client creation: error not set"));
}
TEST_F(TestNodeService, resolve_service_name)
{
EXPECT_EQ("/ns/bar", node_services->resolve_service_name("foo", false));
EXPECT_EQ("/ns/foo", node_services->resolve_service_name("foo", true));
EXPECT_EQ("/foo", node_services->resolve_service_name("/foo", true));
EXPECT_THROW(
node_services->resolve_service_name("this is not a valid name!~>", true),
rclcpp::exceptions::RCLError);
}

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
@@ -80,7 +81,9 @@ public:
void SetUp()
{
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::NodeOptions options{};
options.arguments(std::vector<std::string>{"-r", "foo:=bar"});
node = std::make_shared<rclcpp::Node>("node", "ns", options);
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
@@ -154,3 +157,13 @@ TEST_F(TestNodeTopics, add_subscription_rcl_trigger_guard_condition_error)
node_topics->add_subscription(subscription, callback_group),
std::runtime_error("failed to notify wait set on subscription creation: error not set"));
}
TEST_F(TestNodeTopics, resolve_topic_name)
{
EXPECT_EQ("/ns/bar", node_topics->resolve_topic_name("foo", false));
EXPECT_EQ("/ns/foo", node_topics->resolve_topic_name("foo", true));
EXPECT_EQ("/foo", node_topics->resolve_topic_name("/foo", true));
EXPECT_THROW(
node_topics->resolve_topic_name("this is not a valid name!~>", true),
rclcpp::exceptions::RCLError);
}

View File

@@ -30,7 +30,17 @@ class TestWaitable : public rclcpp::Waitable
public:
bool add_to_wait_set(rcl_wait_set_t *) override {return false;}
bool is_ready(rcl_wait_set_t *) override {return false;}
void execute() override {}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void execute(std::shared_ptr<void> & data) override
{
(void) data;
}
};
class TestNodeWaitables : public ::testing::Test

View File

@@ -49,7 +49,16 @@ public:
return test_waitable_result;
}
void execute() override {}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void execute(std::shared_ptr<void> & data) override
{
(void) data;
}
};
struct RclWaitSetSizes

View File

@@ -79,7 +79,7 @@ public:
}
};
TYPED_TEST_CASE(TestAddCallbackGroupsToExecutor, ExecutorTypes, ExecutorTypeNames);
TYPED_TEST_SUITE(TestAddCallbackGroupsToExecutor, ExecutorTypes, ExecutorTypeNames);
/*
* Test adding callback groups.

View File

@@ -50,6 +50,34 @@ TEST_F(TestCreateSubscription, create) {
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}
TEST_F(TestCreateSubscription, create_with_overriding_options) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);
auto options = rclcpp::SubscriptionOptions();
options.qos_overriding_options = rclcpp::QosOverridingOptions::with_default_policies();
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
auto subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(node, "topic_name", qos, callback, options);
ASSERT_NE(nullptr, subscription);
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}
TEST_F(TestCreateSubscription, create_separated_node_topics_and_parameters) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);
auto options = rclcpp::SubscriptionOptions();
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
auto node_parameters = node->get_node_parameters_interface();
auto node_topics = node->get_node_topics_interface();
auto subscription = rclcpp::create_subscription<test_msgs::msg::Empty>(
node_parameters, node_topics, "topic_name", qos, callback, options);
ASSERT_NE(nullptr, subscription);
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}
TEST_F(TestCreateSubscription, create_with_statistics) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);

View File

@@ -68,7 +68,7 @@ TEST_F(TestDuration, operators) {
TEST_F(TestDuration, chrono_overloads) {
int64_t ns = 123456789l;
auto chrono_ns = std::chrono::nanoseconds(ns);
auto d1 = rclcpp::Duration(ns);
auto d1 = rclcpp::Duration::from_nanoseconds(ns);
auto d2 = rclcpp::Duration(chrono_ns);
auto d3 = rclcpp::Duration(123456789ns);
EXPECT_EQ(d1, d2);
@@ -85,11 +85,11 @@ TEST_F(TestDuration, chrono_overloads) {
}
TEST_F(TestDuration, overflows) {
rclcpp::Duration max(std::numeric_limits<rcl_duration_value_t>::max());
rclcpp::Duration min(std::numeric_limits<rcl_duration_value_t>::min());
auto max = rclcpp::Duration::from_nanoseconds(std::numeric_limits<rcl_duration_value_t>::max());
auto min = rclcpp::Duration::from_nanoseconds(std::numeric_limits<rcl_duration_value_t>::min());
rclcpp::Duration one(1);
rclcpp::Duration negative_one(-1);
rclcpp::Duration one(1ns);
rclcpp::Duration negative_one(-1ns);
EXPECT_THROW(max + one, std::overflow_error);
EXPECT_THROW(min - one, std::underflow_error);
@@ -106,7 +106,7 @@ TEST_F(TestDuration, overflows) {
}
TEST_F(TestDuration, negative_duration) {
rclcpp::Duration assignable_duration = rclcpp::Duration(0) - rclcpp::Duration(5, 0);
rclcpp::Duration assignable_duration = rclcpp::Duration(0ns) - rclcpp::Duration(5, 0);
{
// avoid windows converting a literal number less than -INT_MAX to unsigned int C4146
@@ -140,22 +140,52 @@ static const int64_t ONE_SEC_IN_NS = 1000 * 1000 * 1000;
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
TEST_F(TestDuration, from_seconds) {
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration::from_seconds(0.0));
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration::from_seconds(0));
EXPECT_EQ(rclcpp::Duration(0ns), rclcpp::Duration::from_seconds(0.0));
EXPECT_EQ(rclcpp::Duration(0ns), rclcpp::Duration::from_seconds(0));
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration::from_seconds(1.5));
EXPECT_EQ(rclcpp::Duration(-ONE_AND_HALF_SEC_IN_NS), rclcpp::Duration::from_seconds(-1.5));
EXPECT_EQ(
rclcpp::Duration::from_nanoseconds(-ONE_AND_HALF_SEC_IN_NS),
rclcpp::Duration::from_seconds(-1.5));
}
TEST_F(TestDuration, from_rmw_time) {
constexpr auto max_rcl_duration = std::numeric_limits<rcl_duration_value_t>::max();
{
rmw_time_t rmw_duration{};
rmw_duration.sec = RCL_NS_TO_S(max_rcl_duration) + 1uLL;
EXPECT_EQ(rclcpp::Duration::from_rmw_time(rmw_duration).nanoseconds(), max_rcl_duration);
}
{
rmw_time_t rmw_duration{};
rmw_duration.nsec = max_rcl_duration + 1uLL;
EXPECT_EQ(rclcpp::Duration::from_rmw_time(rmw_duration).nanoseconds(), max_rcl_duration);
}
{
rmw_time_t rmw_duration{};
rmw_duration.nsec = max_rcl_duration;
rmw_duration.sec = RCL_NS_TO_S(max_rcl_duration);
EXPECT_EQ(rclcpp::Duration::from_rmw_time(rmw_duration).nanoseconds(), max_rcl_duration);
}
{
rmw_time_t rmw_duration{};
rmw_duration.sec = 1u;
rmw_duration.nsec = 1000u;
EXPECT_EQ(
rclcpp::Duration::from_rmw_time(rmw_duration).nanoseconds(),
static_cast<rcl_duration_value_t>(RCL_S_TO_NS(rmw_duration.sec) + rmw_duration.nsec));
}
}
TEST_F(TestDuration, std_chrono_constructors) {
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0.0s));
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0s));
EXPECT_EQ(rclcpp::Duration(0ns), rclcpp::Duration(0.0s));
EXPECT_EQ(rclcpp::Duration(0ns), rclcpp::Duration(0s));
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration(1.5s));
EXPECT_EQ(rclcpp::Duration(-1, 0), rclcpp::Duration(-1s));
}
TEST_F(TestDuration, conversions) {
{
const rclcpp::Duration duration(HALF_SEC_IN_NS);
auto duration = rclcpp::Duration::from_nanoseconds(HALF_SEC_IN_NS);
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, 0);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
@@ -170,7 +200,7 @@ TEST_F(TestDuration, conversions) {
}
{
const rclcpp::Duration duration(ONE_SEC_IN_NS);
auto duration = rclcpp::Duration::from_nanoseconds(ONE_SEC_IN_NS);
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, 1);
EXPECT_EQ(duration_msg.nanosec, 0u);
@@ -185,7 +215,7 @@ TEST_F(TestDuration, conversions) {
}
{
const rclcpp::Duration duration(ONE_AND_HALF_SEC_IN_NS);
auto duration = rclcpp::Duration::from_nanoseconds(ONE_AND_HALF_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, 1);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
@@ -200,7 +230,7 @@ TEST_F(TestDuration, conversions) {
}
{
rclcpp::Duration duration(-HALF_SEC_IN_NS);
auto duration = rclcpp::Duration::from_nanoseconds(-HALF_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, -1);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
@@ -213,7 +243,7 @@ TEST_F(TestDuration, conversions) {
}
{
rclcpp::Duration duration(-ONE_SEC_IN_NS);
auto duration = rclcpp::Duration::from_nanoseconds(-ONE_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, -1);
EXPECT_EQ(duration_msg.nanosec, 0u);
@@ -226,7 +256,7 @@ TEST_F(TestDuration, conversions) {
}
{
rclcpp::Duration duration(-ONE_AND_HALF_SEC_IN_NS);
auto duration = rclcpp::Duration::from_nanoseconds(-ONE_AND_HALF_SEC_IN_NS);
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
EXPECT_EQ(duration_msg.sec, -2);
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
@@ -253,9 +283,10 @@ TEST_F(TestDuration, test_some_constructors) {
}
TEST_F(TestDuration, test_some_exceptions) {
rclcpp::Duration test_duration(0u);
rclcpp::Duration test_duration(0ns);
RCLCPP_EXPECT_THROW_EQ(
test_duration = rclcpp::Duration(INT64_MAX) - rclcpp::Duration(-1),
test_duration =
rclcpp::Duration::from_nanoseconds(INT64_MAX) - rclcpp::Duration(-1ns),
std::overflow_error("duration subtraction leads to int64_t overflow"));
RCLCPP_EXPECT_THROW_EQ(
test_duration = test_duration * (std::numeric_limits<double>::infinity()),

View File

@@ -90,10 +90,9 @@ MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, >)
TEST_F(TestExecutor, constructor_bad_guard_condition_init) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_guard_condition_init, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
EXPECT_THROW(
new DummyExecutor(),
std::runtime_error(
"Failed to create interrupt guard condition in Executor constructor: error not set"));
rclcpp::exceptions::RCLError);
}
TEST_F(TestExecutor, constructor_bad_wait_set_init) {

View File

@@ -125,16 +125,14 @@ public:
this->run();
}
void mock_start_thread()
void mock_init_wait_set()
{
// This function prepares the loop thread to be run, but leave
// early with the failure thrown. That way the graph_listener wait_set
// is init, without being started
auto mock_wait_set_init = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_wait_set_init, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
this->start_if_not_started(),
std::runtime_error("failed to initialize wait set: error not set"));
this->init_wait_set();
}
void mock_cleanup_wait_set()
{
this->cleanup_wait_set();
}
};
@@ -145,14 +143,16 @@ TEST_F(TestGraphListener, error_run_graph_listener_destroy_context) {
auto graph_listener_error =
std::make_shared<TestGraphListenerProtectedMethods>(context_to_destroy);
context_to_destroy.reset();
EXPECT_NO_THROW(graph_listener_error->run_protected());
EXPECT_THROW(
graph_listener_error->run_protected(),
rclcpp::exceptions::RCLError);
}
TEST_F(TestGraphListener, error_run_graph_listener_mock_wait_set_clear) {
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->mock_start_thread();
graph_listener_test->mock_init_wait_set();
auto mock_wait_set_clear = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
@@ -164,7 +164,7 @@ TEST_F(TestGraphListener, error_run_graph_listener_mock_wait_set_add_guard_condi
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->mock_start_thread();
graph_listener_test->mock_init_wait_set();
auto mock_wait_set_clear = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait_set_add_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
@@ -172,31 +172,11 @@ TEST_F(TestGraphListener, error_run_graph_listener_mock_wait_set_add_guard_condi
std::runtime_error("failed to add interrupt guard condition to wait set: error not set"));
}
TEST_F(TestGraphListener, error_run_graph_listener_mock_wait_set_add_guard_condition_twice) {
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->mock_start_thread();
auto mock = mocking_utils::patch(
"lib:rclcpp", rcl_wait_set_add_guard_condition, [](auto, ...) {
static int counter = 1;
if (counter == 1) {
counter++;
return RCL_RET_OK;
} else {
return RCL_RET_ERROR;
}
});
RCLCPP_EXPECT_THROW_EQ(
graph_listener_test->run_protected(),
std::runtime_error("failed to add shutdown guard condition to wait set: error not set"));
}
TEST_F(TestGraphListener, error_run_graph_listener_mock_wait_error) {
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->mock_start_thread();
graph_listener_test->mock_init_wait_set();
auto mock_wait_set_clear = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
@@ -208,7 +188,7 @@ TEST_F(TestGraphListener, error_run_graph_listener_mock_wait_timeout) {
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->mock_start_thread();
graph_listener_test->mock_init_wait_set();
auto mock_wait_set_clear = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait, RCL_RET_TIMEOUT);
RCLCPP_EXPECT_THROW_EQ(
@@ -267,27 +247,54 @@ TEST_F(TestGraphListener, test_errors_graph_listener_add_remove_node) {
/* Shutdown errors */
TEST_F(TestGraphListener, test_graph_listener_shutdown_wait_fini_error_nothrow) {
graph_listener()->start_if_not_started();
auto mock_wait_set_fini = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_wait_set_fini, RCL_RET_ERROR);
// Exception is logged when using nothrow_t
EXPECT_NO_THROW(graph_listener()->shutdown(std::nothrow_t()));
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->start_if_not_started();
{
auto mock_wait_set_fini = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait_set_fini, RCL_RET_ERROR);
// Exception is logged when using nothrow_t
EXPECT_NO_THROW(graph_listener_test->shutdown(std::nothrow_t()));
}
graph_listener_test->mock_cleanup_wait_set();
}
TEST_F(TestGraphListener, test_graph_listener_shutdown_wait_fini_error_throw) {
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener()->start_if_not_started();
auto mock_wait_set_fini = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_wait_set_fini, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
graph_listener()->shutdown(),
std::runtime_error("failed to finalize wait set: error not set"));
{
auto mock_wait_set_fini = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait_set_fini, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
graph_listener()->shutdown(),
std::runtime_error("failed to finalize wait set: error not set"));
}
graph_listener_test->mock_cleanup_wait_set();
}
TEST_F(TestGraphListener, test_graph_listener_shutdown_guard_fini_error_throw) {
graph_listener()->start_if_not_started();
auto mock_wait_set_fini = mocking_utils::inject_on_return(
auto global_context = rclcpp::contexts::get_global_default_context();
auto graph_listener_test =
std::make_shared<TestGraphListenerProtectedMethods>(global_context);
graph_listener_test->start_if_not_started();
auto mock_wait_set_fini = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_guard_condition_fini, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
graph_listener()->shutdown(),
graph_listener_test->shutdown(),
std::runtime_error("failed to finalize interrupt guard condition: error not set"));
graph_listener_test->mock_cleanup_wait_set();
}

View File

@@ -80,75 +80,77 @@ TEST(TestLogger, set_level) {
rcutils_logging_set_output_handler(rcutils_logging_console_output_handler);
// default
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message info", g_last_log_event.message);
// unset
g_last_log_event.console_output_handler_called = false;
logger.set_level(rclcpp::Logger::Level::Unset);
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message info", g_last_log_event.message);
// debug
g_last_log_event.console_output_handler_called = false;
logger.set_level(rclcpp::Logger::Level::Debug);
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message debug", g_last_log_event.message);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_EQ("message info", g_last_log_event.message);
// info
g_last_log_event.console_output_handler_called = false;
logger.set_level(rclcpp::Logger::Level::Info);
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message info", g_last_log_event.message);
// warn
g_last_log_event.console_output_handler_called = false;
logger.set_level(rclcpp::Logger::Level::Warn);
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_WARN(logger, std::string("message %s"), "warn");
RCLCPP_WARN(logger, "message %s", "warn");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message warn", g_last_log_event.message);
// error
g_last_log_event.console_output_handler_called = false;
logger.set_level(rclcpp::Logger::Level::Error);
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_WARN(logger, std::string("message %s"), "warn");
RCLCPP_WARN(logger, "message %s", "warn");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_ERROR(logger, std::string("message %s"), "error");
RCLCPP_ERROR(logger, "message %s", "error");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message error", g_last_log_event.message);
// fatal
g_last_log_event.console_output_handler_called = false;
logger.set_level(rclcpp::Logger::Level::Fatal);
RCLCPP_DEBUG(logger, std::string("message %s"), "debug");
RCLCPP_DEBUG(logger, "message %s", "debug");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_INFO(logger, std::string("message %s"), "info");
RCLCPP_INFO(logger, "message %s", "info");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_WARN(logger, std::string("message %s"), "warn");
RCLCPP_WARN(logger, "message %s", "warn");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_ERROR(logger, std::string("message %s"), "error");
RCLCPP_ERROR(logger, "message %s", "error");
EXPECT_FALSE(g_last_log_event.console_output_handler_called);
RCLCPP_FATAL(logger, std::string("message %s"), "fatal");
RCLCPP_FATAL(logger, "message %s", "fatal");
EXPECT_TRUE(g_last_log_event.console_output_handler_called);
EXPECT_EQ("message fatal", g_last_log_event.message);

View File

@@ -110,26 +110,6 @@ TEST_F(TestLoggingMacros, test_logging_named) {
EXPECT_EQ("message 3", g_last_log_event.message);
}
TEST_F(TestLoggingMacros, test_logging_string) {
for (std::string i : {"one", "two", "three"}) {
RCLCPP_DEBUG(g_logger, "message " + i);
}
EXPECT_EQ(3u, g_log_calls);
EXPECT_EQ("message three", g_last_log_event.message);
RCLCPP_DEBUG(g_logger, "message " "four");
EXPECT_EQ("message four", g_last_log_event.message);
RCLCPP_DEBUG(g_logger, std::string("message " "five"));
EXPECT_EQ("message five", g_last_log_event.message);
RCLCPP_DEBUG(g_logger, std::string("message %s"), "six");
EXPECT_EQ("message six", g_last_log_event.message);
RCLCPP_DEBUG(g_logger, "message seven");
EXPECT_EQ("message seven", g_last_log_event.message);
}
TEST_F(TestLoggingMacros, test_logging_stream) {
for (std::string i : {"one", "two", "three"}) {
RCLCPP_DEBUG_STREAM(g_logger, "message " << i);

View File

@@ -37,7 +37,8 @@ class TestWaitable : public rclcpp::Waitable
public:
bool add_to_wait_set(rcl_wait_set_t *) override {return true;}
bool is_ready(rcl_wait_set_t *) override {return true;}
void execute() override {}
std::shared_ptr<void> take_data() override {return nullptr;}
void execute(std::shared_ptr<void> & data) override {(void)data;}
};
class TestMemoryStrategy : public ::testing::Test

View File

@@ -28,6 +28,8 @@
#include "rcl_interfaces/msg/parameter_event.hpp"
using namespace std::chrono_literals;
class TestParameterClient : public ::testing::Test
{
public:
@@ -45,14 +47,20 @@ protected:
void SetUp()
{
node = std::make_shared<rclcpp::Node>("test_parameter_client", "/ns");
node_with_option =
std::make_shared<rclcpp::Node>(
"test_parameter_client_allow_undeclare", "/ns",
rclcpp::NodeOptions().allow_undeclared_parameters(true));
}
void TearDown()
{
node.reset();
node_with_option.reset();
}
rclcpp::Node::SharedPtr node;
rclcpp::Node::SharedPtr node_with_option;
};
/*
@@ -287,7 +295,337 @@ TEST_F(TestParameterClient, sync_parameter_get_parameter_types) {
auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(node);
std::vector<std::string> names{"foo"};
std::vector<rclcpp::ParameterType> parameter_types =
synchronous_client->get_parameter_types(names);
synchronous_client->get_parameter_types(names, 10s);
ASSERT_EQ(1u, parameter_types.size());
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_types[0]);
}
/*
Coverage for async describe_parameters
*/
TEST_F(TestParameterClient, async_parameter_describe_parameters) {
node->declare_parameter("foo", 4);
node->declare_parameter("bar", "this is bar");
auto asynchronous_client = std::make_shared<rclcpp::AsyncParametersClient>(node);
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
// We expect the result to be empty since we tried to get a parameter that didn't exist.
if (result.valid() && result.get().size() == 0) {
callback_called = true;
}
};
std::vector<std::string> names{"none"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
ASSERT_TRUE(callback_called);
}
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
if (result.valid() && result.get().size() == 1) {
callback_called = true;
}
};
std::vector<std::string> names{"foo"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs = future.get();
ASSERT_EQ(1u, parameter_descs.size());
ASSERT_EQ("foo", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_TRUE(callback_called);
}
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
// We expect the result to be empty since we tried to get a parameter that didn't exist.
if (result.valid() && result.get().size() == 0) {
callback_called = true;
}
};
std::vector<std::string> names{"foo", "baz"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
ASSERT_TRUE(callback_called);
}
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
// We expect the result to be empty since we tried to get a parameter that didn't exist.
if (result.valid() && result.get().size() == 0) {
callback_called = true;
}
};
std::vector<std::string> names{"baz", "foo"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
ASSERT_TRUE(callback_called);
}
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
if (result.valid() && result.get().size() == 2) {
callback_called = true;
}
};
std::vector<std::string> names{"foo", "bar"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs = future.get();
ASSERT_EQ(2u, parameter_descs.size());
ASSERT_EQ("foo", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_EQ("bar", parameter_descs[1].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_STRING, parameter_descs[1].type);
ASSERT_EQ("", parameter_descs[1].description);
ASSERT_EQ("", parameter_descs[1].additional_constraints);
ASSERT_FALSE(parameter_descs[1].read_only);
ASSERT_TRUE(callback_called);
}
}
/*
Coverage for sync describe_parameters
*/
TEST_F(TestParameterClient, sync_parameter_describe_parameters) {
node->declare_parameter("foo", 4);
node->declare_parameter("bar", "this is bar");
auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(node);
{
std::vector<std::string> names{"none"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(0u, parameter_descs.size());
}
{
std::vector<std::string> names{"foo"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(1u, parameter_descs.size());
ASSERT_EQ("foo", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
}
{
std::vector<std::string> names{"foo", "baz"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(0u, parameter_descs.size());
}
{
std::vector<std::string> names{"baz", "foo"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(0u, parameter_descs.size());
}
{
std::vector<std::string> names{"foo", "bar"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(2u, parameter_descs.size());
ASSERT_EQ("foo", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_EQ("bar", parameter_descs[1].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_STRING, parameter_descs[1].type);
ASSERT_EQ("", parameter_descs[1].description);
ASSERT_EQ("", parameter_descs[1].additional_constraints);
ASSERT_FALSE(parameter_descs[1].read_only);
}
}
/*
Coverage for async describe_parameters with allow_undeclared_ enabled
*/
TEST_F(TestParameterClient, async_parameter_describe_parameters_allow_undeclared) {
node_with_option->declare_parameter("foo", 4);
node_with_option->declare_parameter("bar", "this is bar");
auto asynchronous_client =
std::make_shared<rclcpp::AsyncParametersClient>(node_with_option);
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
// We expect the result to be defaut since we tried to get a parameter that didn't exist.
if (result.valid() && result.get().size() == 1) {
callback_called = true;
}
};
std::vector<std::string> names{"none"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node_with_option, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs = future.get();
ASSERT_EQ(1u, parameter_descs.size());
ASSERT_EQ("none", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_TRUE(callback_called);
}
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
if (result.valid() && result.get().size() == 2) {
callback_called = true;
}
};
std::vector<std::string> names{"foo", "baz"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node_with_option, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs = future.get();
ASSERT_EQ(2u, parameter_descs.size());
ASSERT_EQ("foo", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_EQ("baz", parameter_descs[1].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET, parameter_descs[1].type);
ASSERT_EQ("", parameter_descs[1].description);
ASSERT_EQ("", parameter_descs[1].additional_constraints);
ASSERT_FALSE(parameter_descs[1].read_only);
ASSERT_TRUE(callback_called);
}
{
bool callback_called = false;
auto callback = [&callback_called](
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> result)
{
if (result.valid() && result.get().size() == 2) {
callback_called = true;
}
};
std::vector<std::string> names{"baz", "foo"};
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>> future =
asynchronous_client->describe_parameters(names, callback);
auto return_code = rclcpp::spin_until_future_complete(
node_with_option, future, std::chrono::milliseconds(100));
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs = future.get();
ASSERT_EQ(2u, parameter_descs.size());
ASSERT_EQ("baz", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_EQ("foo", parameter_descs[1].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[1].type);
ASSERT_EQ("", parameter_descs[1].description);
ASSERT_EQ("", parameter_descs[1].additional_constraints);
ASSERT_FALSE(parameter_descs[1].read_only);
ASSERT_TRUE(callback_called);
}
}
/*
Coverage for sync describe_parameters with allow_undeclared_ enabled
*/
TEST_F(TestParameterClient, sync_parameter_describe_parameters_allow_undeclared) {
node_with_option->declare_parameter("foo", 4);
node_with_option->declare_parameter("bar", "this is bar");
auto synchronous_client =
std::make_shared<rclcpp::SyncParametersClient>(node_with_option);
{
std::vector<std::string> names{"none"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(1u, parameter_descs.size());
ASSERT_EQ("none", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
}
{
std::vector<std::string> names{"foo", "baz"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(2u, parameter_descs.size());
ASSERT_EQ("foo", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_EQ("baz", parameter_descs[1].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET, parameter_descs[1].type);
ASSERT_EQ("", parameter_descs[1].description);
ASSERT_EQ("", parameter_descs[1].additional_constraints);
ASSERT_FALSE(parameter_descs[1].read_only);
}
{
std::vector<std::string> names{"baz", "foo"};
std::vector<rcl_interfaces::msg::ParameterDescriptor> parameter_descs =
synchronous_client->describe_parameters(names, 10s);
ASSERT_EQ(2u, parameter_descs.size());
ASSERT_EQ("baz", parameter_descs[0].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET, parameter_descs[0].type);
ASSERT_EQ("", parameter_descs[0].description);
ASSERT_EQ("", parameter_descs[0].additional_constraints);
ASSERT_FALSE(parameter_descs[0].read_only);
ASSERT_EQ("foo", parameter_descs[1].name);
ASSERT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_descs[1].type);
ASSERT_EQ("", parameter_descs[1].description);
ASSERT_EQ("", parameter_descs[1].additional_constraints);
ASSERT_FALSE(parameter_descs[1].read_only);
}
}

View File

@@ -22,6 +22,8 @@
#include "rclcpp/rclcpp.hpp"
#include "../../src/rclcpp/parameter_service_names.hpp"
using namespace std::chrono_literals;
// This tests the ParameterService as it is included in an rclcpp::Node. Creating a separate
// ParameterService would interfere with the built-in one
class TestParameterService : public ::testing::Test
@@ -59,12 +61,12 @@ TEST_F(TestParameterService, get_parameter_types) {
node->declare_parameter("parameter1", rclcpp::ParameterValue(42));
const std::vector<std::string> declared_parameters = {"parameter1"};
const auto parameter_types = client->get_parameter_types(declared_parameters);
const auto parameter_types = client->get_parameter_types(declared_parameters, 10s);
ASSERT_EQ(1u, parameter_types.size());
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, parameter_types[0]);
const std::vector<std::string> undeclared_parameters = {"parameter2"};
const auto undeclared_parameter_types = client->get_parameter_types(undeclared_parameters);
const auto undeclared_parameter_types = client->get_parameter_types(undeclared_parameters, 10s);
EXPECT_EQ(0u, undeclared_parameter_types.size());
}
@@ -75,7 +77,7 @@ TEST_F(TestParameterService, set_parameters) {
const std::vector<rclcpp::Parameter> parameters = {
rclcpp::Parameter("parameter1", 0),
};
client->set_parameters(parameters);
client->set_parameters(parameters, 10s);
EXPECT_EQ(0, client->get_parameter("parameter1", 100));
}
@@ -86,15 +88,15 @@ TEST_F(TestParameterService, set_parameters_atomically) {
const std::vector<rclcpp::Parameter> parameters = {
rclcpp::Parameter("parameter1", 0),
};
client->set_parameters_atomically(parameters);
client->set_parameters_atomically(parameters, 10s);
EXPECT_EQ(0, client->get_parameter("parameter1", 100));
}
TEST_F(TestParameterService, list_parameters) {
const size_t number_parameters_in_basic_node = client->list_parameters({}, 1).names.size();
const size_t number_parameters_in_basic_node = client->list_parameters({}, 1, 10s).names.size();
node->declare_parameter("parameter1", rclcpp::ParameterValue(42));
const auto list_result = client->list_parameters({}, 1);
const auto list_result = client->list_parameters({}, 1, 10s);
EXPECT_EQ(1u + number_parameters_in_basic_node, list_result.names.size());
}

View File

@@ -151,6 +151,20 @@ TEST_F(TestPublisher, various_creation_signatures) {
rclcpp::create_publisher<Empty>(node, "topic", 42, rclcpp::PublisherOptions());
(void)publisher;
}
{
rclcpp::PublisherOptions options;
options.qos_overriding_options = rclcpp::QosOverridingOptions::with_default_policies();
auto publisher =
rclcpp::create_publisher<Empty>(node, "topic", 42, options);
(void)publisher;
}
{
auto node_parameters = node->get_node_parameters_interface();
auto node_topics = node->get_node_topics_interface();
auto publisher = rclcpp::create_publisher<Empty>(
node_parameters, node_topics, "topic", 42, rclcpp::PublisherOptions());
(void)publisher;
}
}
/*
@@ -184,7 +198,7 @@ static std::vector<TestParameters> invalid_qos_profiles()
return parameters;
}
INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_SUITE_P(
TestPublisherThrows, TestPublisherInvalidIntraprocessQos,
::testing::ValuesIn(invalid_qos_profiles()),
::testing::PrintToStringParamName());
@@ -489,7 +503,9 @@ TEST_F(TestPublisher, default_incompatible_qos_callback) {
TEST_F(TestPublisher, run_event_handlers) {
initialize();
auto publisher = node->create_publisher<test_msgs::msg::Empty>("topic", 10);
for (const auto & handler : publisher->get_event_handlers()) {
EXPECT_NO_THROW(handler->execute());
std::shared_ptr<void> data = handler->take_data();
handler->execute(data);
}
}

View File

@@ -192,7 +192,7 @@ using AllTestDescriptions = ::testing::Types<
TwoSubscriptionsInTwoContextsWithIntraprocessComm,
TwoSubscriptionsInTwoContextsWithoutIntraprocessComm
>;
TYPED_TEST_CASE(TestPublisherSubscriptionCount, AllTestDescriptions, PrintTestDescription);
TYPED_TEST_SUITE(TestPublisherSubscriptionCount, AllTestDescriptions, PrintTestDescription);
using test_msgs::msg::Empty;

View File

@@ -78,33 +78,41 @@ TEST(TestQoS, equality_namespace) {
EXPECT_NE(a, b);
}
TEST(TestQoS, setters) {
TEST(TestQoS, setters_and_getters) {
rclcpp::QoS qos(10);
qos.keep_all();
EXPECT_EQ(RMW_QOS_POLICY_HISTORY_KEEP_ALL, qos.get_rmw_qos_profile().history);
EXPECT_EQ(rclcpp::HistoryPolicy::KeepAll, qos.history());
qos.keep_last(20);
EXPECT_EQ(RMW_QOS_POLICY_HISTORY_KEEP_LAST, qos.get_rmw_qos_profile().history);
EXPECT_EQ(20u, qos.get_rmw_qos_profile().depth);
EXPECT_EQ(rclcpp::HistoryPolicy::KeepLast, qos.history());
EXPECT_EQ(20u, qos.depth());
qos.reliable();
EXPECT_EQ(RMW_QOS_POLICY_RELIABILITY_RELIABLE, qos.get_rmw_qos_profile().reliability);
EXPECT_EQ(rclcpp::ReliabilityPolicy::Reliable, qos.reliability());
qos.reliability(rclcpp::ReliabilityPolicy::BestEffort);
EXPECT_EQ(rclcpp::ReliabilityPolicy::BestEffort, qos.reliability());
qos.durability_volatile();
EXPECT_EQ(RMW_QOS_POLICY_DURABILITY_VOLATILE, qos.get_rmw_qos_profile().durability);
EXPECT_EQ(rclcpp::DurabilityPolicy::Volatile, qos.durability());
qos.transient_local();
EXPECT_EQ(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL, qos.get_rmw_qos_profile().durability);
EXPECT_EQ(rclcpp::DurabilityPolicy::TransientLocal, qos.durability());
qos.durability(rclcpp::DurabilityPolicy::Volatile);
EXPECT_EQ(rclcpp::DurabilityPolicy::Volatile, qos.durability());
qos.history(RMW_QOS_POLICY_HISTORY_KEEP_ALL);
EXPECT_EQ(RMW_QOS_POLICY_HISTORY_KEEP_ALL, qos.get_rmw_qos_profile().history);
EXPECT_EQ(rclcpp::HistoryPolicy::KeepAll, qos.history());
constexpr size_t duration_ns = 12345;
qos.history(rclcpp::HistoryPolicy::KeepLast);
EXPECT_EQ(rclcpp::HistoryPolicy::KeepLast, qos.history());
constexpr rcl_duration_value_t duration_ns = 12345;
constexpr std::chrono::nanoseconds duration(duration_ns);
qos.deadline(duration);
EXPECT_EQ(0u, qos.get_rmw_qos_profile().deadline.sec);
EXPECT_EQ(duration_ns, qos.get_rmw_qos_profile().deadline.nsec);
EXPECT_EQ(duration_ns, qos.deadline().nanoseconds());
const rmw_time_t rmw_time {0, 54321};
qos.deadline(rmw_time);
@@ -112,28 +120,29 @@ TEST(TestQoS, setters) {
EXPECT_EQ(rmw_time.nsec, qos.get_rmw_qos_profile().deadline.nsec);
qos.lifespan(duration);
EXPECT_EQ(0u, qos.get_rmw_qos_profile().lifespan.sec);
EXPECT_EQ(duration_ns, qos.get_rmw_qos_profile().lifespan.nsec);
EXPECT_EQ(duration_ns, qos.lifespan().nanoseconds());
qos.lifespan(rmw_time);
EXPECT_EQ(rmw_time.sec, qos.get_rmw_qos_profile().lifespan.sec);
EXPECT_EQ(rmw_time.nsec, qos.get_rmw_qos_profile().lifespan.nsec);
qos.liveliness(RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC);
EXPECT_EQ(RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC, qos.get_rmw_qos_profile().liveliness);
EXPECT_EQ(rclcpp::LivelinessPolicy::ManualByTopic, qos.liveliness());
qos.liveliness(rclcpp::LivelinessPolicy::Automatic);
EXPECT_EQ(rclcpp::LivelinessPolicy::Automatic, qos.liveliness());
qos.liveliness_lease_duration(duration);
EXPECT_EQ(0u, qos.get_rmw_qos_profile().liveliness_lease_duration.sec);
EXPECT_EQ(duration_ns, qos.get_rmw_qos_profile().liveliness_lease_duration.nsec);
EXPECT_EQ(duration_ns, qos.liveliness_lease_duration().nanoseconds());
qos.liveliness_lease_duration(rmw_time);
EXPECT_EQ(rmw_time.sec, qos.get_rmw_qos_profile().liveliness_lease_duration.sec);
EXPECT_EQ(rmw_time.nsec, qos.get_rmw_qos_profile().liveliness_lease_duration.nsec);
qos.avoid_ros_namespace_conventions(true);
EXPECT_TRUE(qos.get_rmw_qos_profile().avoid_ros_namespace_conventions);
EXPECT_TRUE(qos.avoid_ros_namespace_conventions());
qos.avoid_ros_namespace_conventions(false);
EXPECT_FALSE(qos.get_rmw_qos_profile().avoid_ros_namespace_conventions);
EXPECT_FALSE(qos.avoid_ros_namespace_conventions());
}
bool operator==(const rmw_qos_profile_t & lhs, const rmw_qos_profile_t & rhs)

View File

@@ -285,14 +285,16 @@ TEST_F(TestQosEvent, execute) {
rclcpp::QOSEventHandler<decltype(callback), decltype(rcl_handle)> handler(
callback, rcl_publisher_event_init, rcl_handle, event_type);
EXPECT_NO_THROW(handler.execute());
std::shared_ptr<void> data = handler.take_data();
EXPECT_NO_THROW(handler.execute(data));
EXPECT_TRUE(handler_callback_executed);
{
handler_callback_executed = false;
// Logs error and returns early
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_take_event, RCL_RET_ERROR);
EXPECT_NO_THROW(handler.execute());
std::shared_ptr<void> data = handler.take_data();
EXPECT_THROW(handler.execute(data), std::runtime_error);
EXPECT_FALSE(handler_callback_executed);
}
}

View File

@@ -0,0 +1,34 @@
// Copyright 2020 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 "gmock/gmock.h"
#include "rclcpp/qos_overriding_options.hpp"
TEST(TestQosOverridingOptions, test_overriding_options) {
auto options = rclcpp::QosOverridingOptions::with_default_policies();
EXPECT_EQ(options.get_id(), "");
EXPECT_EQ(options.get_validation_callback(), nullptr);
EXPECT_THAT(
options.get_policy_kinds(), testing::ElementsAre(
rclcpp::QosPolicyKind::History,
rclcpp::QosPolicyKind::Depth,
rclcpp::QosPolicyKind::Reliability));
}
TEST(TestQosOverridingOptions, test_qos_policy_kind_to_cstr) {
EXPECT_THROW(
rclcpp::qos_policy_kind_to_cstr(rclcpp::QosPolicyKind::Invalid),
std::invalid_argument);
}

View File

@@ -0,0 +1,256 @@
// Copyright 2020 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 <map>
#include <memory>
#include <string>
#include "gmock/gmock.h"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rclcpp/detail/qos_parameters.hpp"
TEST(TestQosParameters, declare) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>(
"my_node", "/ns", rclcpp::NodeOptions().parameter_overrides(
{
rclcpp::Parameter(
"qos_overrides./my/fully/qualified/topic_name.publisher.reliability", "best_effort"),
}));
for (size_t i = 0; i < 2; ++i) {
// The first iteration will declare parameters, the second will get the previosuly declared
// ones, check both have the same result.
rclcpp::QoS qos{rclcpp::KeepLast(10)};
qos = rclcpp::detail::declare_qos_parameters(
rclcpp::QosOverridingOptions::with_default_policies(),
node,
"/my/fully/qualified/topic_name",
qos,
rclcpp::detail::PublisherQosParametersTraits{});
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.publisher.history").get_value<std::string>(),
"keep_last");
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.publisher.depth").get_value<int64_t>(),
10);
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.publisher.reliability"
).get_value<std::string>(),
"best_effort");
EXPECT_EQ(RMW_QOS_POLICY_HISTORY_KEEP_LAST, qos.get_rmw_qos_profile().history);
EXPECT_EQ(RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT, qos.get_rmw_qos_profile().reliability);
EXPECT_EQ(10u, qos.get_rmw_qos_profile().depth);
std::map<std::string, rclcpp::Parameter> qos_params;
EXPECT_TRUE(
node->get_node_parameters_interface()->get_parameters_by_prefix(
"qos_overrides./my/fully/qualified/topic_name.publisher", qos_params));
EXPECT_EQ(3u, qos_params.size());
}
rclcpp::shutdown();
}
TEST(TestQosParameters, declare_with_callback) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>(
"my_node", "/ns", rclcpp::NodeOptions().parameter_overrides(
{
rclcpp::Parameter(
"qos_overrides./my/fully/qualified/topic_name.publisher.reliability", "best_effort"),
}));
rclcpp::QoS qos{rclcpp::KeepLast(10)};
// *INDENT-OFF*, uncrustify suggestion makes the code unreadable
EXPECT_THROW(
rclcpp::detail::declare_qos_parameters(
{
{rclcpp::QosPolicyKind::Lifespan},
[](const rclcpp::QoS &) {
return rclcpp::QosCallbackResult{};
}
},
node,
"/my/fully/qualified/topic_name/fails_validation",
qos,
rclcpp::detail::PublisherQosParametersTraits{}),
rclcpp::exceptions::InvalidQosOverridesException);
rclcpp::detail::declare_qos_parameters(
rclcpp::QosOverridingOptions::with_default_policies([](const rclcpp::QoS &) {
rclcpp::QosCallbackResult result;
result.successful = true;
return result;
}),
node,
"/my/fully/qualified/topic_name",
qos,
rclcpp::detail::PublisherQosParametersTraits{});
// *INDENT-ON*
rclcpp::shutdown();
}
constexpr int64_t kDuration{1000000};
TEST(TestQosParameters, declare_qos_subscription_parameters) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>(
"my_node", "/ns", rclcpp::NodeOptions().parameter_overrides(
{
rclcpp::Parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.reliability", "best_effort"),
rclcpp::Parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.deadline", kDuration),
rclcpp::Parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.liveliness_lease_duration",
kDuration),
}));
for (size_t i = 0; i < 2; ++i) {
// The first iteration will declare parameters, the second will get the previosuly declared
// ones, check both have the same result.
rclcpp::QoS qos{rclcpp::KeepLast(10)};
qos = rclcpp::detail::declare_qos_parameters(
{
rclcpp::QosPolicyKind::AvoidRosNamespaceConventions, rclcpp::QosPolicyKind::Deadline,
rclcpp::QosPolicyKind::Depth, rclcpp::QosPolicyKind::Durability,
// lifespan will be ignored
rclcpp::QosPolicyKind::History, rclcpp::QosPolicyKind::Lifespan,
rclcpp::QosPolicyKind::Liveliness, rclcpp::QosPolicyKind::LivelinessLeaseDuration,
rclcpp::QosPolicyKind::Reliability
},
node,
"/my/fully/qualified/topic_name",
qos,
rclcpp::detail::SubscriptionQosParametersTraits{});
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.avoid_ros_namespace_conventions"
).get_value<bool>(), false);
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.deadline"
).get_value<int64_t>(), kDuration);
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.depth"
).get_value<int64_t>(), 10);
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.durability"
).get_value<std::string>(), "volatile");
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.history"
).get_value<std::string>(), "keep_last");
EXPECT_FALSE(
node->has_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.lifespan"));
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.liveliness"
).get_value<std::string>(), "system_default");
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.liveliness_lease_duration"
).get_value<int64_t>(), kDuration);
EXPECT_EQ(
node->get_parameter(
"qos_overrides./my/fully/qualified/topic_name.subscription.reliability"
).get_value<std::string>(),
"best_effort");
std::map<std::string, rclcpp::Parameter> qos_params;
EXPECT_TRUE(
node->get_node_parameters_interface()->get_parameters_by_prefix(
"qos_overrides./my/fully/qualified/topic_name.subscription", qos_params));
EXPECT_EQ(8u, qos_params.size());
}
rclcpp::shutdown();
}
TEST(TestQosParameters, declare_with_id) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
rclcpp::QoS qos{rclcpp::KeepLast{10}};
qos = rclcpp::detail::declare_qos_parameters(
rclcpp::QosOverridingOptions::with_default_policies(nullptr, "my_id"),
node,
"/my/fully/qualified/topic_name",
qos,
rclcpp::detail::PublisherQosParametersTraits{});
std::map<std::string, rclcpp::Parameter> qos_params;
EXPECT_TRUE(
node->get_node_parameters_interface()->get_parameters_by_prefix(
"qos_overrides./my/fully/qualified/topic_name.publisher_my_id", qos_params));
EXPECT_EQ(3u, qos_params.size());
rclcpp::shutdown();
}
TEST(TestQosParameters, declare_no_parameters_interface) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
rclcpp::QoS qos{rclcpp::KeepLast{10}};
auto node_base_interface = node->get_node_base_interface();
EXPECT_THROW(
rclcpp::detail::declare_qos_parameters(
rclcpp::QosOverridingOptions::with_default_policies(),
node_base_interface,
"/my/fully/qualified/topic_name",
qos,
rclcpp::detail::PublisherQosParametersTraits{}),
std::runtime_error);
qos = rclcpp::detail::declare_qos_parameters(
rclcpp::QosOverridingOptions{},
node_base_interface,
"/my/fully/qualified/topic_name",
qos,
rclcpp::detail::PublisherQosParametersTraits{});
std::map<std::string, rclcpp::Parameter> qos_params;
EXPECT_FALSE(
node->get_node_parameters_interface()->get_parameters_by_prefix("qos_overrides", qos_params));
rclcpp::shutdown();
}
TEST(TestQosParameters, internal_functions_failure_modes) {
rclcpp::QoS qos{rclcpp::KeepLast{10}};
EXPECT_THROW(
rclcpp::detail::apply_qos_override(
rclcpp::QosPolicyKind::Invalid, rclcpp::ParameterValue{}, qos),
std::invalid_argument);
EXPECT_THROW(
rclcpp::detail::get_default_qos_param_value(
rclcpp::QosPolicyKind::Invalid, qos),
std::invalid_argument);
EXPECT_THROW(
rclcpp::detail::check_if_stringified_policy_is_null(
nullptr, rclcpp::QosPolicyKind::Reliability),
std::invalid_argument);
}

View File

@@ -506,7 +506,7 @@ static std::vector<TestParameters> invalid_qos_profiles()
return parameters;
}
INSTANTIATE_TEST_CASE_P(
INSTANTIATE_TEST_SUITE_P(
TestSubscriptionThrows, TestSubscriptionInvalidIntraprocessQos,
::testing::ValuesIn(invalid_qos_profiles()),
::testing::PrintToStringParamName());

View File

@@ -129,7 +129,7 @@ struct TwoContextsPerTest
};
using AllTestDescriptions = ::testing::Types<OneContextPerTest, TwoContextsPerTest>;
TYPED_TEST_CASE(TestSubscriptionPublisherCount, AllTestDescriptions, PrintTestDescription);
TYPED_TEST_SUITE(TestSubscriptionPublisherCount, AllTestDescriptions, PrintTestDescription);
using test_msgs::msg::Empty;

View File

@@ -15,6 +15,7 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <limits>
#include <string>
@@ -30,6 +31,8 @@
namespace
{
using namespace std::chrono_literals;
bool logical_eq(const bool a, const bool b)
{
return (a && b) || ((!a) && !(b));
@@ -221,7 +224,7 @@ TEST_F(TestTime, operators) {
EXPECT_EQ(sub, young - old);
rclcpp::Time young_changed(young);
young_changed -= rclcpp::Duration(old.nanoseconds());
young_changed -= rclcpp::Duration::from_nanoseconds(old.nanoseconds());
EXPECT_EQ(sub.nanoseconds(), young_changed.nanoseconds());
rclcpp::Time system_time(0, 0, RCL_SYSTEM_TIME);
@@ -320,8 +323,8 @@ TEST_F(TestTime, overflow_detectors) {
TEST_F(TestTime, overflows) {
rclcpp::Time max_time(std::numeric_limits<rcl_time_point_value_t>::max());
rclcpp::Time min_time(std::numeric_limits<rcl_time_point_value_t>::min());
rclcpp::Duration one(1);
rclcpp::Duration two(2);
rclcpp::Duration one(1ns);
rclcpp::Duration two(2ns);
// Cross min/max
EXPECT_THROW(max_time + one, std::overflow_error);
@@ -394,7 +397,7 @@ TEST_F(TestTime, test_assignment_operator_from_builtin_msg_time) {
}
TEST_F(TestTime, test_sum_operator) {
const rclcpp::Duration one(1);
const rclcpp::Duration one(1ns);
const rclcpp::Time test_time(0u);
EXPECT_EQ(0u, test_time.nanoseconds());
@@ -406,41 +409,41 @@ TEST_F(TestTime, test_overflow_underflow_throws) {
rclcpp::Time test_time(0u);
RCLCPP_EXPECT_THROW_EQ(
test_time = rclcpp::Time(INT64_MAX) + rclcpp::Duration(1),
test_time = rclcpp::Time(INT64_MAX) + rclcpp::Duration(1ns),
std::overflow_error("addition leads to int64_t overflow"));
RCLCPP_EXPECT_THROW_EQ(
test_time = rclcpp::Time(INT64_MIN) + rclcpp::Duration(-1),
test_time = rclcpp::Time(INT64_MIN) + rclcpp::Duration(-1ns),
std::underflow_error("addition leads to int64_t underflow"));
RCLCPP_EXPECT_THROW_EQ(
test_time = rclcpp::Time(INT64_MAX) - rclcpp::Duration(-1),
test_time = rclcpp::Time(INT64_MAX) - rclcpp::Duration(-1ns),
std::overflow_error("time subtraction leads to int64_t overflow"));
RCLCPP_EXPECT_THROW_EQ(
test_time = rclcpp::Time(INT64_MIN) - rclcpp::Duration(1),
test_time = rclcpp::Time(INT64_MIN) - rclcpp::Duration(1ns),
std::underflow_error("time subtraction leads to int64_t underflow"));
test_time = rclcpp::Time(INT64_MAX);
RCLCPP_EXPECT_THROW_EQ(
test_time += rclcpp::Duration(1),
test_time += rclcpp::Duration(1ns),
std::overflow_error("addition leads to int64_t overflow"));
test_time = rclcpp::Time(INT64_MIN);
RCLCPP_EXPECT_THROW_EQ(
test_time += rclcpp::Duration(-1),
test_time += rclcpp::Duration(-1ns),
std::underflow_error("addition leads to int64_t underflow"));
test_time = rclcpp::Time(INT64_MAX);
RCLCPP_EXPECT_THROW_EQ(
test_time -= rclcpp::Duration(-1),
test_time -= rclcpp::Duration(-1ns),
std::overflow_error("time subtraction leads to int64_t overflow"));
test_time = rclcpp::Time(INT64_MIN);
RCLCPP_EXPECT_THROW_EQ(
test_time -= rclcpp::Duration(1),
test_time -= rclcpp::Duration(1ns),
std::underflow_error("time subtraction leads to int64_t underflow"));
RCLCPP_EXPECT_THROW_EQ(
test_time = rclcpp::Duration(INT64_MAX) + rclcpp::Time(1),
test_time = rclcpp::Duration::from_nanoseconds(INT64_MAX) + rclcpp::Time(1),
std::overflow_error("addition leads to int64_t overflow"));
RCLCPP_EXPECT_THROW_EQ(
test_time = rclcpp::Duration(INT64_MIN) + rclcpp::Time(-1),
test_time = rclcpp::Duration::from_nanoseconds(INT64_MIN) + rclcpp::Time(-1),
std::underflow_error("addition leads to int64_t underflow"));
}

View File

@@ -61,6 +61,29 @@ TEST(TestUtilities, init_with_args) {
rclcpp::shutdown();
}
TEST(TestUtilities, init_with_args_contains_ros) {
EXPECT_FALSE(rclcpp::signal_handlers_installed());
const char * const argv[] = {
"process_name",
"-d", "--ros-args",
"-r", "__ns:=/foo/bar",
"-r", "__ns:=/fiz/buz",
"--", "--foo=bar", "--baz"
};
int argc = sizeof(argv) / sizeof(const char *);
auto args = rclcpp::init_and_remove_ros_arguments(argc, argv);
ASSERT_EQ(4u, args.size());
ASSERT_EQ(std::string{"process_name"}, args[0]);
ASSERT_EQ(std::string{"-d"}, args[1]);
ASSERT_EQ(std::string{"--foo=bar"}, args[2]);
ASSERT_EQ(std::string{"--baz"}, args[3]);
EXPECT_TRUE(rclcpp::signal_handlers_installed());
EXPECT_TRUE(rclcpp::ok());
rclcpp::shutdown();
}
TEST(TestUtilities, multi_init) {
auto context1 = std::make_shared<rclcpp::contexts::DefaultContext>();
auto context2 = std::make_shared<rclcpp::contexts::DefaultContext>();
@@ -108,59 +131,6 @@ MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, !=)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, >)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, <)
TEST(TestUtilities, test_context_release_interrupt_guard_condition) {
auto context1 = std::make_shared<rclcpp::contexts::DefaultContext>();
context1->init(0, nullptr);
RCLCPP_SCOPE_EXIT(rclcpp::shutdown(context1););
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_ret_t ret = rcl_wait_set_init(
&wait_set, 0, 2, 0, 0, 0, 0, context1->get_rcl_context().get(),
rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret);
// Expected usage
rcl_guard_condition_t * interrupt_guard_condition =
context1->get_interrupt_guard_condition(&wait_set);
EXPECT_NE(nullptr, interrupt_guard_condition);
EXPECT_NO_THROW(context1->release_interrupt_guard_condition(&wait_set));
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_guard_condition_init, RCL_RET_ERROR);
EXPECT_THROW(
{interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);},
rclcpp::exceptions::RCLError);
}
{
interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_guard_condition_fini, RCL_RET_ERROR);
EXPECT_THROW(
{context1->release_interrupt_guard_condition(&wait_set);},
rclcpp::exceptions::RCLError);
}
{
interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_guard_condition_fini, RCL_RET_ERROR);
EXPECT_NO_THROW({context1->release_interrupt_guard_condition(&wait_set, std::nothrow);});
}
{
EXPECT_THROW(
context1->release_interrupt_guard_condition(nullptr),
std::runtime_error);
}
// Test it works after restore mocks
interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);
EXPECT_NE(nullptr, interrupt_guard_condition);
EXPECT_NO_THROW(context1->release_interrupt_guard_condition(&wait_set));
}
TEST(TestUtilities, test_context_init_shutdown_fails) {
{
auto context = std::make_shared<rclcpp::contexts::DefaultContext>();

View File

@@ -55,7 +55,10 @@ public:
bool is_ready(rcl_wait_set_t *) override {return is_ready_;}
void execute() override {}
std::shared_ptr<void> take_data() override {return nullptr;}
void
execute(std::shared_ptr<void> & data) override {(void)data;}
void set_is_ready(bool value) {is_ready_ = value;}

View File

@@ -54,7 +54,10 @@ public:
bool is_ready(rcl_wait_set_t *) override {return is_ready_;}
void execute() override {}
std::shared_ptr<void> take_data() override {return nullptr;}
void
execute(std::shared_ptr<void> & data) override {(void)data;}
void set_is_ready(bool value) {is_ready_ = value;}

View File

@@ -54,7 +54,10 @@ public:
bool is_ready(rcl_wait_set_t *) override {return is_ready_;}
void execute() override {}
std::shared_ptr<void> take_data() override {return nullptr;}
void
execute(std::shared_ptr<void> & data) override {(void)data;}
void set_is_ready(bool value) {is_ready_ = value;}

View File

@@ -54,7 +54,10 @@ public:
bool is_ready(rcl_wait_set_t *) override {return is_ready_;}
void execute() override {}
std::shared_ptr<void> take_data() override {return nullptr;}
void
execute(std::shared_ptr<void> & data) override {(void)data;}
void set_is_ready(bool value) {is_ready_ = value;}

View File

@@ -3,6 +3,34 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6.2.0 (2021-01-08)
------------------
* Goal response callback compatibility shim with deprecation of old signature (`#1495 <https://github.com/ros2/rclcpp/issues/1495>`_)
* [rclcpp_action] Add warnings (`#1405 <https://github.com/ros2/rclcpp/issues/1405>`_)
* Contributors: Audrow Nash, Ivan Santiago Paunovic
6.1.0 (2020-12-10)
------------------
* Update QDs to QL 1 (`#1477 <https://github.com/ros2/rclcpp/issues/1477>`_)
* Contributors: Stephen Brawner
6.0.0 (2020-11-18)
------------------
* Add `take_data` to `Waitable` and `data` to `AnyExecutable` (`#1241 <https://github.com/ros2/rclcpp/issues/1241>`_)
* Fix test crashes on CentOS 7 (`#1449 <https://github.com/ros2/rclcpp/issues/1449>`_)
* Bump rclcpp packages to Quality Level 2 (`#1445 <https://github.com/ros2/rclcpp/issues/1445>`_)
* Add rclcpp_action action_server benchmarks (`#1433 <https://github.com/ros2/rclcpp/issues/1433>`_)
* Contributors: Audrow Nash, Chris Lalancette, Louise Poubel, brawner
5.1.0 (2020-11-02)
------------------
* Benchmark rclcpp_action action_client (`#1429 <https://github.com/ros2/rclcpp/issues/1429>`_)
* Add missing locking to the rclcpp_action::ServerBase. (`#1421 <https://github.com/ros2/rclcpp/issues/1421>`_)
* Increase test timeouts of slow running tests with rmw_connext_cpp (`#1400 <https://github.com/ros2/rclcpp/issues/1400>`_)
* Update maintainers (`#1384 <https://github.com/ros2/rclcpp/issues/1384>`_)
* Increase coverage rclcpp_action to 95% (`#1290 <https://github.com/ros2/rclcpp/issues/1290>`_)
* Contributors: Chris Lalancette, Ivan Santiago Paunovic, brawner
5.0.0 (2020-09-18)
------------------
* Pass goal handle to goal response callback instead of a future (`#1311 <https://github.com/ros2/rclcpp/issues/1311>`_)

View File

@@ -13,7 +13,10 @@ if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Wnon-virtual-dtor -Woverloaded-virtual)
add_compile_options(
-Wall -Wextra -Wpedantic -Wnon-virtual-dtor -Woverloaded-virtual
-Wformat=2 -Wconversion -Wshadow -Wsign-conversion -Wcast-qual
)
endif()
set(${PROJECT_NAME}_SRCS
@@ -74,6 +77,8 @@ if(BUILD_TESTING)
set(ament_cmake_cppcheck_ADDITIONAL_INCLUDE_DIRS ${rclcpp_INCLUDE_DIRS})
ament_lint_auto_find_test_dependencies()
add_subdirectory(test/benchmark)
ament_add_gtest(test_client test/test_client.cpp TIMEOUT 180)
if(TARGET test_client)
ament_target_dependencies(test_client

View File

@@ -2,7 +2,7 @@ This document is a declaration of software quality for the `rclcpp_action` packa
# rclcpp_action Quality Declaration
The package `rclcpp_action` claims to be in the **Quality Level 3** category.
The package `rclcpp_action` claims to be in the **Quality Level 1** category when it is used with a **Quality Level 1** middleware.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -80,13 +80,13 @@ The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.
The license for `rclcpp_action` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_action/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Rpr/job/Rpr__rclcpp__ubuntu_focal_amd64/lastCompletedBuild/testReport/rclcpp_action/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp_action`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_action/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Rpr/job/Rpr__rclcpp__ubuntu_focal_amd64/lastCompletedBuild/testReport/rclcpp_action/copyright/).
## Testing [4]
@@ -119,11 +119,19 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_action_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_action_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
`rclcpp_action` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
The performance tests of `rclcpp_action` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp_action/test/benchmark).
System level performance benchmarks that cover features of `rclcpp_action` can be found at:
* [Benchmarks](http://build.ros2.org/view/Rci/job/Rci__benchmark_ubuntu_focal_amd64/BenchmarkTable/)
* [Performance](http://build.ros2.org/view/Rci/job/Rci__nightly-performance_ubuntu_focal_amd64/lastCompletedBuild/)
Changes that introduce regressions in performance must be adequately justified in order to be accepted and merged.
### Linters and Static Analysis [4.v]
@@ -151,19 +159,19 @@ It also has several test dependencies, which do not affect the resulting quality
`action_msgs` provides messages and services for ROS 2 actions.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/action_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/action_msgs/QUALITY_DECLARATION.md).
#### `rclcpp`
The `rclcpp` package provides the ROS client library in C++.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
#### `rcl_action`
The `rcl_action` package provides C-based ROS action implementation.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl_action/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl_action/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

@@ -6,4 +6,4 @@ Visit the [rclcpp_action API documentation](http://docs.ros2.org/latest/api/rclc
## Quality Declaration
This package claims to be in the **Quality Level 3** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.
This package claims to be in the **Quality Level 1** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

View File

@@ -116,10 +116,15 @@ public:
bool
is_ready(rcl_wait_set_t * wait_set) override;
/// \internal
RCLCPP_ACTION_PUBLIC
std::shared_ptr<void>
take_data() override;
/// \internal
RCLCPP_ACTION_PUBLIC
void
execute() override;
execute(std::shared_ptr<void> & data) override;
// End Waitables API
// -----------------
@@ -263,13 +268,107 @@ public:
using Feedback = typename ActionT::Feedback;
using GoalHandle = ClientGoalHandle<ActionT>;
using WrappedResult = typename GoalHandle::WrappedResult;
using GoalResponseCallback = std::function<void (typename GoalHandle::SharedPtr)>;
using FeedbackCallback = typename GoalHandle::FeedbackCallback;
using ResultCallback = typename GoalHandle::ResultCallback;
using CancelRequest = typename ActionT::Impl::CancelGoalService::Request;
using CancelResponse = typename ActionT::Impl::CancelGoalService::Response;
using CancelCallback = std::function<void (typename CancelResponse::SharedPtr)>;
/// Compatibility wrapper for `goal_response_callback`.
class GoalResponseCallback
{
public:
using NewSignature = std::function<void (typename GoalHandle::SharedPtr)>;
using OldSignature = std::function<void (std::shared_future<typename GoalHandle::SharedPtr>)>;
GoalResponseCallback() = default;
GoalResponseCallback(std::nullptr_t) {} // NOLINT, intentionally implicit.
// implicit constructor
[[deprecated(
"Use new goal response callback signature "
"`std::function<void (Client<ActionT>::GoalHandle::SharedPtr)>` "
"instead of the old "
"`std::function<void (std::shared_future<Client<ActionT>::GoalHandle::SharedPtr>)>`.\n"
"e.g.:\n"
"```cpp\n"
"Client<ActionT>::SendGoalOptions options;\n"
"options.goal_response_callback = [](Client<ActionT>::GoalHandle::SharedPtr goal) {\n"
" // do something with `goal` here\n"
"};")]]
GoalResponseCallback(OldSignature old_callback) // NOLINT, intentionally implicit.
: old_callback_(std::move(old_callback)) {}
GoalResponseCallback(NewSignature new_callback) // NOLINT, intentionally implicit.
: new_callback_(std::move(new_callback)) {}
GoalResponseCallback &
operator=(OldSignature old_callback) {old_callback_ = std::move(old_callback); return *this;}
GoalResponseCallback &
operator=(NewSignature new_callback) {new_callback_ = std::move(new_callback); return *this;}
void
operator()(typename GoalHandle::SharedPtr goal_handle) const
{
if (new_callback_) {
new_callback_(std::move(goal_handle));
return;
}
if (old_callback_) {
throw std::runtime_error{
"Cannot call GoalResponseCallback(GoalHandle::SharedPtr) "
"if using the old goal response callback signature."};
}
throw std::bad_function_call{};
}
[[deprecated(
"Calling "
"`void goal_response_callback("
" std::shared_future<Client<ActionT>::GoalHandle::SharedPtr> goal_handle_shared_future)`"
" is deprecated.")]]
void
operator()(std::shared_future<typename GoalHandle::SharedPtr> goal_handle_future) const
{
if (old_callback_) {
old_callback_(std::move(goal_handle_future));
return;
}
if (new_callback_) {
new_callback_(std::move(goal_handle_future).get_future().share());
return;
}
throw std::bad_function_call{};
}
explicit operator bool() const noexcept {
return new_callback_ || old_callback_;
}
private:
friend class Client;
void
operator()(
typename GoalHandle::SharedPtr goal_handle,
std::shared_future<typename GoalHandle::SharedPtr> goal_handle_future) const
{
if (new_callback_) {
new_callback_(std::move(goal_handle));
return;
}
if (old_callback_) {
old_callback_(std::move(goal_handle_future));
return;
}
throw std::bad_function_call{};
}
NewSignature new_callback_;
OldSignature old_callback_;
};
/// Options for sending a goal.
/**
* This struct is used to pass parameters to the function `async_send_goal`.
@@ -358,7 +457,7 @@ public:
if (!goal_response->accepted) {
promise->set_value(nullptr);
if (options.goal_response_callback) {
options.goal_response_callback(nullptr);
options.goal_response_callback(nullptr, future);
}
return;
}
@@ -374,7 +473,7 @@ public:
}
promise->set_value(goal_handle);
if (options.goal_response_callback) {
options.goal_response_callback(goal_handle);
options.goal_response_callback(goal_handle, future);
}
if (options.result_callback) {

View File

@@ -118,11 +118,15 @@ public:
bool
is_ready(rcl_wait_set_t *) override;
RCLCPP_ACTION_PUBLIC
std::shared_ptr<void>
take_data() override;
/// Act on entities in the wait set which are ready to be acted upon.
/// \internal
RCLCPP_ACTION_PUBLIC
void
execute() override;
execute(std::shared_ptr<void> & data) override;
// End Waitables API
// -----------------
@@ -229,19 +233,19 @@ private:
/// \internal
RCLCPP_ACTION_PUBLIC
void
execute_goal_request_received();
execute_goal_request_received(std::shared_ptr<void> & data);
/// Handle a request to cancel goals on the server
/// \internal
RCLCPP_ACTION_PUBLIC
void
execute_cancel_request_received();
execute_cancel_request_received(std::shared_ptr<void> & data);
/// Handle a request to get the result of an action
/// \internal
RCLCPP_ACTION_PUBLIC
void
execute_result_request_received();
execute_result_request_received(std::shared_ptr<void> & data);
/// Handle a timeout indicating a completed goal should be forgotten by the server
/// \internal
@@ -377,31 +381,31 @@ protected:
std::weak_ptr<Server<ActionT>> weak_this = this->shared_from_this();
std::function<void(const GoalUUID &, std::shared_ptr<void>)> on_terminal_state =
[weak_this](const GoalUUID & uuid, std::shared_ptr<void> result_message)
[weak_this](const GoalUUID & goal_uuid, std::shared_ptr<void> result_message)
{
std::shared_ptr<Server<ActionT>> shared_this = weak_this.lock();
if (!shared_this) {
return;
}
// Send result message to anyone that asked
shared_this->publish_result(uuid, result_message);
shared_this->publish_result(goal_uuid, result_message);
// Publish a status message any time a goal handle changes state
shared_this->publish_status();
// notify base so it can recalculate the expired goal timer
shared_this->notify_goal_terminal_state();
// Delete data now (ServerBase and rcl_action_server_t keep data until goal handle expires)
std::lock_guard<std::mutex> lock(shared_this->goal_handles_mutex_);
shared_this->goal_handles_.erase(uuid);
shared_this->goal_handles_.erase(goal_uuid);
};
std::function<void(const GoalUUID &)> on_executing =
[weak_this](const GoalUUID & uuid)
[weak_this](const GoalUUID & goal_uuid)
{
std::shared_ptr<Server<ActionT>> shared_this = weak_this.lock();
if (!shared_this) {
return;
}
(void)uuid;
(void)goal_uuid;
// Publish a status message any time a goal handle changes state
shared_this->publish_status();
};

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_action</name>
<version>5.0.0</version>
<version>6.2.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
@@ -26,6 +26,7 @@
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>mimick_vendor</test_depend>
<test_depend>performance_test_fixture</test_depend>
<test_depend>test_msgs</test_depend>
<export>

Some files were not shown because too many files have changed in this diff Show More