Compare commits

..

25 Commits
3.0.0 ... 2.2.0

Author SHA1 Message Date
Jacob Perron
cf1be86f5c 2.2.0 2020-10-07 10:50:16 -07:00
Jacob Perron
4dcb0eda68 Fix implementation of NodeOptions::use_global_arguments() (#1176) (#1372)
`this->node_options_` might still be `nullptr` for a default initialized NodeOptions instance.
`use_global_arguments()` must return `this->use_global_arguments_`, in analogy to `NodeOptions::enable_rosout()`.

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

Co-authored-by: Johannes Meyer <johannes@intermodalics.eu>
2020-10-06 11:33:26 -07:00
Jacob Perron
9c1cbdf6c7 Fix conversion of negative durations to messages (#1188) (#1371)
* Fix conversion from negative Duration or Time to the respective message type and throw in Duration::to_rmw_time() if the duration is negative.
rmw_time_t cannot represent negative durations.

Constructors and assignment operators can be just defaulted.

Other changes are mainly cosmetical, to make conversions between signed
and unsigned types and between 32-bit and 64-bit types more explicit.

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

* Add -Wconversion compiler option and fix implicit conversions that might alter the value

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

* Fix usage of fixture class in some unit tests by using gtest macro TEST_F() instead of TEST().

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

* Add compiler option -Wno-sign-conversion to fix build with Clang on macOS

Signed-off-by: Johannes Meyer <johannes@intermodalics.eu>

Co-authored-by: Johannes Meyer <johannes@intermodalics.eu>
2020-10-06 11:30:43 -07:00
brawner
6e6dd9cb1a [backport foxy] Log error instead of throwing exception in Transition and State reset() mark no except (#1297) (#1378)
* Log error instead of throwing exception in Transition and State reset(), mark no except (#1297)

* Catch potential exception in destructor and log

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

* Remove thrown error from reset and mark it no except

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

* Remove noexcept for ABI compatibility

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-05 15:44:55 -07:00
brawner
45a47c6448 Call vector.erase with end iterator overload (#1314) (#1380)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-05 13:39:42 -07:00
brawner
6e408b79f3 Check waitable for nullptr during constructor (#1315) (#1379)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-05 13:39:22 -07:00
brawner
b843c75ef8 Remove rmw-dependent unit-test checks (#1293) (#1377)
* Remove rmw-dependent unit-test checks

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

* Address feedback

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

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-05 13:38:17 -07:00
Dereck Wonnacott
cb1b32ee15 Include original exception in ComponentManagerException (#1157) (#1223)
* Include original exception in ComponentManagerException

Signed-off-by: Martijn Buijs <martijn.buijs@gmail.com>

* Update rclcpp_components/src/component_manager.cpp

Co-authored-by: tomoya <Tomoya.Fujita@sony.com>
Signed-off-by: Martijn Buijs <martijn.buijs@gmail.com>

Co-authored-by: tomoya <Tomoya.Fujita@sony.com>

Co-authored-by: Martijn Buijs <Martijn.buijs@gmail.com>
Co-authored-by: tomoya <Tomoya.Fujita@sony.com>
2020-10-01 12:42:49 -07:00
Jacob Perron
b67fa594f8 Fix pub/sub count API tests. (#1203) (#1319)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>

Co-authored-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-09-18 13:30:25 -07:00
brawner
8bfc8e631f Reorganize test directory and split CMakeLists.txt (#1173) (#1262)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-08-19 14:43:28 -07:00
Ivan Santiago Paunovic
75f3d54d57 Add operator!= for duration (#1236) (#1278)
Signed-off-by: Jannik Abbenseth <jannik.abbenseth@ipa.fraunhofer.de>

Co-authored-by: Jannik Abbenseth <ipa-jba@users.noreply.github.com>
2020-08-18 09:58:50 -03:00
Jacob Perron
27e59d930a 2.1.0 2020-08-03 15:03:27 -07:00
Jacob Perron
ce5de8757d Warn about unused result of add_on_set_parameters_callback (#1238) (#1244)
If the user doesn't retain a reference to the returned shared pointer there will be zero references and their callback will be unregistered.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2020-08-03 12:10:27 -07:00
brawner
6ea67a4e9f Add missing RCLCPP_PUBLIC to ~StaticExecutorEntitiesCollector (#1227) (#1228)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-07-14 09:54:15 -07:00
brawner
5f6bf45202 Remove recreation of entities_collector (#1217) (#1224)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-07-13 09:50:41 -07:00
Jacob Perron
dc528ad710 2.0.2 2020-07-07 21:07:12 -07:00
Dirk Thomas
26e824c7c0 link against thread library where necessary (#1210) (#1214)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-07-07 20:34:33 -07:00
tomoya
3a3ba55fa2 fix exception message on rcl_clock_init (#1182) (#1193)
* fix exception message on rcl_clock_init.

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

* error messages start with lower case.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-06-25 09:45:13 -07:00
Jacob Perron
1745db6dcd 2.0.1 2020-06-23 17:32:15 -07:00
brawner
7ed387f862 Add create_publisher include to create_subscription (#1180) (#1192)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-23 14:44:39 -07:00
Jacob Perron
a10ae56629 Fix get_node_time_source_interface() docstring (#988) (#1185)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2020-06-23 10:44:19 -07:00
Alejandro Hernández Cordero
1f000b8d97 Fixed doxygen warnings (#1163) (#1191)
Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-06-23 19:43:41 +02:00
Ivan Santiago Paunovic
c14f46e6f3 Check if context is valid when looping in spin_some (#1167)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-17 09:52:04 -03:00
DongheeYe
70e1830ecd Fix spin_until_future_complete: check spinning value (#1023)
Signed-off-by: Donghee Ye <donghee.ye@samsung.com>

Make Executor::spin_once_impl private before backporting, to avoid API compatibility issues

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-06-17 09:52:04 -03:00
Devin Bonnie
77564eb2ff Add check for invalid topic statistics publish period (#1151) (#1172)
* Add check for invalid topic statistics publish period

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update documentation

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address doc formatting comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update doc spacing

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-06-15 10:25:17 -07:00
52 changed files with 842 additions and 903 deletions

View File

@@ -2,20 +2,40 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3.0.0 (2020-06-18)
2.2.0 (2020-10-07)
------------------
* Check period duration in create_wall_timer (`#1178 <https://github.com/ros2/rclcpp/issues/1178>`_)
* Fix get_node_time_source_interface() docstring (`#988 <https://github.com/ros2/rclcpp/issues/988>`_)
* Add message lost subscription event (`#1164 <https://github.com/ros2/rclcpp/issues/1164>`_)
* Add spin_all method to Executor (`#1156 <https://github.com/ros2/rclcpp/issues/1156>`_)
* Reorganize test directory and split CMakeLists.txt (`#1173 <https://github.com/ros2/rclcpp/issues/1173>`_)
* Fix implementation of NodeOptions::use_global_arguments() (`#1176 <https://github.com/ros2/rclcpp/issues/1176>`_) (`#1372 <https://github.com/ros2/rclcpp/issues/1372>`_)
* Fix conversion of negative durations to messages (`#1188 <https://github.com/ros2/rclcpp/issues/1188>`_) (`#1371 <https://github.com/ros2/rclcpp/issues/1371>`_)
* Call vector.erase with end iterator overload (`#1314 <https://github.com/ros2/rclcpp/issues/1314>`_) (`#1380 <https://github.com/ros2/rclcpp/issues/1380>`_)
* Check waitable for nullptr during constructor (`#1315 <https://github.com/ros2/rclcpp/issues/1315>`_) (`#1379 <https://github.com/ros2/rclcpp/issues/1379>`_)
* Fix pub/sub count API tests. (`#1203 <https://github.com/ros2/rclcpp/issues/1203>`_) (`#1319 <https://github.com/ros2/rclcpp/issues/1319>`_)
* Reorganize test directory and split CMakeLists.txt (`#1173 <https://github.com/ros2/rclcpp/issues/1173>`_) (`#1262 <https://github.com/ros2/rclcpp/issues/1262>`_)
* Add operator!= for duration (`#1236 <https://github.com/ros2/rclcpp/issues/1236>`_) (`#1278 <https://github.com/ros2/rclcpp/issues/1278>`_)
* Contributors: Ivan Santiago Paunovic, Jacob Perron, Jannik Abbenseth, Johannes Meyer, Michel Hidalgo, Stephen Brawner
2.1.0 (2020-08-03)
------------------
* Warn about unused result of add_on_set_parameters_callback (`#1238 <https://github.com/ros2/rclcpp/issues/1238>`_) (`#1244 <https://github.com/ros2/rclcpp/issues/1244>`_)
* Add missing RCLCPP_PUBLIC to ~StaticExecutorEntitiesCollector (`#1227 <https://github.com/ros2/rclcpp/issues/1227>`_) (`#1228 <https://github.com/ros2/rclcpp/issues/1228>`_)
* Remove recreation of entities_collector (`#1217 <https://github.com/ros2/rclcpp/issues/1217>`_) (`#1224 <https://github.com/ros2/rclcpp/issues/1224>`_)
* Contributors: Jacob Perron, brawner
2.0.2 (2020-07-07)
------------------
* Link against thread library where necessary (`#1210 <https://github.com/ros2/rclcpp/issues/1210>`_) (`#1214 <https://github.com/ros2/rclcpp/issues/1214>`_)
* Fix exception message on rcl_clock_init (`#1182 <https://github.com/ros2/rclcpp/issues/1182>`_) (`#1193 <https://github.com/ros2/rclcpp/issues/1193>`_)
* Contributors: Dirk Thomas, tomoya
2.0.1 (2020-06-23)
------------------
* Add create_publisher include to create_subscription (`#1180 <https://github.com/ros2/rclcpp/issues/1180>`_) (`#1192 <https://github.com/ros2/rclcpp/issues/1192>`_)
* Fix get_node_time_source_interface() docstring (`#988 <https://github.com/ros2/rclcpp/issues/988>`_) (`#1185 <https://github.com/ros2/rclcpp/issues/1185>`_)
* Fixed doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_) (`#1191 <https://github.com/ros2/rclcpp/issues/1191>`_)
* Check if context is valid when looping in spin_some (`#1167 <https://github.com/ros2/rclcpp/issues/1167>`_)
* Add check for invalid topic statistics publish period (`#1151 <https://github.com/ros2/rclcpp/issues/1151>`_)
* Fix spin_until_future_complete: check spinning value (`#1023 <https://github.com/ros2/rclcpp/issues/1023>`_)
* Fix doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_)
* Fix reference to rclcpp in its Quality declaration (`#1161 <https://github.com/ros2/rclcpp/issues/1161>`_)
* Allow spin_until_future_complete to accept any future like object (`#1113 <https://github.com/ros2/rclcpp/issues/1113>`_)
* Contributors: Alejandro Hernández Cordero, Christophe Bedard, Devin Bonnie, Dirk Thomas, DongheeYe, Ivan Santiago Paunovic, Jacob Perron, Sarthak Mittal, brawner, tomoya
Make Executor::spin_once_impl private before backporting, to avoid API compatibility issues
* Add check for invalid topic statistics publish period (`#1151 <https://github.com/ros2/rclcpp/issues/1151>`_) (`#1172 <https://github.com/ros2/rclcpp/issues/1172>`_)
* Contributors: Alejandro Hernández Cordero, Devin Bonnie, DongheeYe, Ivan Santiago Paunovic, Jacob Perron, Stephen Brawner
2.0.0 (2020-06-01)
------------------

View File

@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.5)
project(rclcpp)
find_package(Threads REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
@@ -23,7 +25,11 @@ 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)
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
# implicit sign conversions in rclcpp and gtest.cc, see https://ci.ros2.org/job/ci_osx/9265/.
# Hence disabling -Wsign-conversion for now until all those have eventually been fixed.
# (from https://github.com/ros2/rclcpp/pull/1188#issuecomment-650229140)
add_compile_options(-Wall -Wextra -Wconversion -Wno-sign-conversion -Wpedantic -Wnon-virtual-dtor -Woverloaded-virtual)
endif()
set(${PROJECT_NAME}_SRCS
@@ -166,6 +172,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"libstatistics_collector"

View File

@@ -191,7 +191,7 @@ It is **Quality Level 4**, see its [Quality Declaration document](https://github
#### `tracetools`
The `tracetools` package provides utilities for instrumenting the code in `rclcpp` so that it may be traced for debugging and performance analysis.
The `tracetools` package provides utilities for instrumenting the code in `rcl` so that it may be traced for debugging and performance analysis.
It is **Quality Level 4**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).

View File

@@ -29,6 +29,7 @@
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription_factory.hpp"

View File

@@ -76,14 +76,14 @@ create_timer(
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param period period to exectute callback
* \param callback callback to execute via the timer period
* \param group
* \param node_base
* \param node_timers
* \return
* \throws std::invalid argument if either node_base or node_timers
* are null, or period is negative or too large
* are null
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
@@ -102,38 +102,10 @@ create_wall_timer(
throw std::invalid_argument{"input node_timers cannot be null"};
}
if (period < std::chrono::duration<DurationRepT, DurationT>::zero()) {
throw std::invalid_argument{"timer period cannot be negative"};
}
// Casting to a double representation might lose precision and allow the check below to succeed
// but the actual cast to nanoseconds fail. Using 1 DurationT worth of nanoseconds less than max.
constexpr auto maximum_safe_cast_ns =
std::chrono::nanoseconds::max() - std::chrono::duration<DurationRepT, DurationT>(1);
// If period is greater than nanoseconds::max(), the duration_cast to nanoseconds will overflow
// a signed integer, which is undefined behavior. Checking whether any std::chrono::duration is
// greater than nanoseconds::max() is a difficult general problem. This is a more conservative
// version of Howard Hinnant's (the <chrono> guy>) response here:
// https://stackoverflow.com/a/44637334/2089061
// However, this doesn't solve the issue for all possible duration types of period.
// Follow-up issue: https://github.com/ros2/rclcpp/issues/1177
constexpr auto ns_max_as_double =
std::chrono::duration_cast<std::chrono::duration<double, std::chrono::nanoseconds::period>>(
maximum_safe_cast_ns);
if (period > ns_max_as_double) {
throw std::invalid_argument{
"timer period must be less than std::chrono::nanoseconds::max()"};
}
const auto period_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(period);
if (period_ns < std::chrono::nanoseconds::zero()) {
throw std::runtime_error{
"Casting timer period to nanoseconds resulted in integer overflow."};
}
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
period_ns, std::move(callback), node_base->get_context());
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
std::move(callback),
node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}

View File

@@ -72,11 +72,14 @@ public:
operator=(const Duration & rhs);
Duration &
operator=(const builtin_interfaces::msg::Duration & Duration_msg);
operator=(const builtin_interfaces::msg::Duration & duration_msg);
bool
operator==(const rclcpp::Duration & rhs) const;
bool
operator!=(const rclcpp::Duration & rhs) const;
bool
operator<(const rclcpp::Duration & rhs) const;

View File

@@ -160,7 +160,7 @@ public:
void
spin_node_some(std::shared_ptr<rclcpp::Node> node);
/// Collect work once and execute all available work, optionally within a duration.
/// Complete all available queued work without blocking.
/**
* This function can be overridden. The default implementation is suitable for a
* single-threaded model of execution.
@@ -175,23 +175,6 @@ public:
virtual void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
/// Collect and execute work repeatedly within a duration or until no more work is available.
/**
* This function can be overridden. The default implementation is suitable for a
* single-threaded model of execution.
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
* to block (which may have unintended consequences).
* If the time that waitables take to be executed is longer than the period on which new waitables
* become ready, this method will execute work repeatedly until `max_duration` has elapsed.
*
* \param[in] max_duration The maximum amount of time to spend executing work. Must be positive.
* Note that spin_all() may take longer than this time as it only returns once max_duration has
* been exceeded.
*/
RCLCPP_PUBLIC
virtual void
spin_all(std::chrono::nanoseconds max_duration);
RCLCPP_PUBLIC
virtual void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
@@ -206,10 +189,10 @@ public:
* code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
FutureReturnCode
spin_until_future_complete(
const FutureT & future,
const std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
@@ -287,10 +270,6 @@ protected:
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
/// Find the next available executable and do the work associated with it.
/**
* \param[in] any_exec Union structure that can hold any executable type (timer, subscription,
@@ -363,12 +342,13 @@ protected:
RCLCPP_DISABLE_COPY(Executor)
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
std::list<const rcl_guard_condition_t *> guard_conditions_;
private:
RCLCPP_PUBLIC
void
spin_once_impl(std::chrono::nanoseconds timeout);
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
std::list<const rcl_guard_condition_t *> guard_conditions_;
};
namespace executor

View File

@@ -66,12 +66,12 @@ using rclcpp::executors::SingleThreadedExecutor;
* If the time spent inside the blocking loop exceeds this timeout, return a `TIMEOUT` return code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const FutureT & future,
const std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
@@ -82,13 +82,13 @@ spin_node_until_future_complete(
return retcode;
}
template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = int64_t,
template<typename NodeT = rclcpp::Node, typename ResponseT, typename TimeRepT = int64_t,
typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
std::shared_ptr<NodeT> node_ptr,
const FutureT & future,
const std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::executors::spin_node_until_future_complete(
@@ -104,7 +104,7 @@ template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::mi
rclcpp::FutureReturnCode
spin_until_future_complete(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const FutureT & future,
const std::shared_future<FutureT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
rclcpp::executors::SingleThreadedExecutor executor;
@@ -116,7 +116,7 @@ template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = in
rclcpp::FutureReturnCode
spin_until_future_complete(
std::shared_ptr<NodeT> node_ptr,
const FutureT & future,
const std::shared_future<FutureT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::spin_until_future_complete(node_ptr->get_node_base_interface(), future, timeout);

View File

@@ -45,6 +45,7 @@ public:
StaticExecutorEntitiesCollector() = default;
// Destructor
RCLCPP_PUBLIC
~StaticExecutorEntitiesCollector();
/// Initialize StaticExecutorEntitiesCollector

View File

@@ -143,10 +143,10 @@ public:
* exec.add_node(node);
* exec.spin_until_future_complete(future);
*/
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
FutureT & future,
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
std::future_status status = future.wait_for(std::chrono::seconds(0));
@@ -162,7 +162,6 @@ public:
}
std::chrono::nanoseconds timeout_left = timeout_ns;
entities_collector_ = std::make_shared<StaticExecutorEntitiesCollector>();
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
while (rclcpp::ok(this->context_)) {

View File

@@ -26,6 +26,8 @@
#include <utility>
#include <vector>
#include "rcutils/macros.h"
#include "rcl/error_handling.h"
#include "rcl/node.h"
@@ -812,6 +814,7 @@ public:
* \throws std::bad_alloc if the allocation of the OnSetParametersCallbackHandle fails.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback);

View File

@@ -21,6 +21,8 @@
#include <string>
#include <vector>
#include "rcutils/macros.h"
#include "rcl_interfaces/msg/list_parameters_result.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcl_interfaces/msg/parameter_event.hpp"
@@ -160,6 +162,7 @@ public:
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) override;

View File

@@ -68,7 +68,7 @@ public:
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] topic Name of the topic to publish to.
* \param[in] qos QoS profile for Subcription.
* \param[in] options Options for the subscription.
* \param[in] options options for the subscription.
*/
Publisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,

View File

@@ -34,7 +34,6 @@ using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
using QOSMessageLostInfo = rmw_message_lost_status_t;
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
@@ -42,7 +41,6 @@ using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequeste
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
using QOSRequestedIncompatibleQoSCallbackType =
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
@@ -61,7 +59,6 @@ struct SubscriptionEventCallbacks
QOSDeadlineRequestedCallbackType deadline_callback;
QOSLivelinessChangedCallbackType liveliness_callback;
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
QOSMessageLostCallbackType message_lost_callback;
};
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error

View File

@@ -92,7 +92,7 @@ public:
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] qos QoS profile for Subcription.
* \param[in] callback User defined callback to call when a message is received.
* \param[in] options Options for the subscription.
* \param[in] options options for the subscription.
* \param[in] message_memory_strategy The memory strategy to be used for managing message memory.
* \param[in] subscription_topic_statistics Optional pointer to a topic statistics subcription.
* \throws std::invalid_argument if the QoS is uncompatible with intra-process (if one
@@ -144,11 +144,6 @@ public:
// pass
}
}
if (options.event_callbacks.message_lost_callback) {
this->add_event_handler(
options.event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
// Setup intra process publishing if requested.
if (rclcpp::detail::resolve_use_intra_process(options, *node_base)) {

View File

@@ -66,7 +66,7 @@ public:
* \param[in] node_base NodeBaseInterface pointer used in parts of the setup.
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] subscription_options Options for the subscription.
* \param[in] subscription_options options for the subscription.
* \param[in] is_serialized is true if the message will be delivered still serialized
*/
RCLCPP_PUBLIC

View File

@@ -48,10 +48,10 @@ public:
/// Time constructor
/**
* \param nanoseconds since time epoch
* \param clock clock type
* \param clock_type clock type
*/
RCLCPP_PUBLIC
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock = RCL_SYSTEM_TIME);
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
/// Copy constructor
RCLCPP_PUBLIC
@@ -60,13 +60,13 @@ public:
/// Time constructor
/**
* \param time_msg builtin_interfaces time message to copy
* \param ros_time clock type
* \param clock_type clock type
* \throws std::runtime_error if seconds are negative
*/
RCLCPP_PUBLIC
Time(
const builtin_interfaces::msg::Time & time_msg,
rcl_clock_type_t ros_time = RCL_ROS_TIME);
rcl_clock_type_t clock_type = RCL_ROS_TIME);
/// Time constructor
/**
@@ -90,6 +90,12 @@ public:
Time &
operator=(const Time & rhs);
/**
* Assign Time from a builtin_interfaces::msg::Time instance.
* The clock_type will be reset to RCL_ROS_TIME.
* Equivalent to *this = Time(time_msg, RCL_ROS_TIME).
* \throws std::runtime_error if seconds are negative
*/
RCLCPP_PUBLIC
Time &
operator=(const builtin_interfaces::msg::Time & time_msg);

View File

@@ -73,7 +73,17 @@ protected:
size_t services_from_waitables = 0;
size_t events_from_waitables = 0;
for (const auto & waitable_entry : waitables) {
rclcpp::Waitable & waitable = *waitable_entry.waitable.get();
auto waitable_ptr_pair = get_raw_pointer_from_smart_pointer(waitable_entry.waitable);
if (nullptr == waitable_ptr_pair.second) {
if (HasStrongOwnership) {
throw std::runtime_error("unexpected condition, fixed storage policy needs pruning");
}
// Flag for pruning.
needs_pruning_ = true;
continue;
}
rclcpp::Waitable & waitable = *waitable_ptr_pair.second;
subscriptions_from_waitables += waitable.get_number_of_ready_subscriptions();
guard_conditions_from_waitables += waitable.get_number_of_ready_guard_conditions();
timers_from_waitables += waitable.get_number_of_ready_timers();

View File

@@ -382,11 +382,13 @@ public:
return weak_ptr.expired();
};
// remove guard conditions which have been deleted
guard_conditions_.erase(std::remove_if(guard_conditions_.begin(), guard_conditions_.end(), p));
timers_.erase(std::remove_if(timers_.begin(), timers_.end(), p));
clients_.erase(std::remove_if(clients_.begin(), clients_.end(), p));
services_.erase(std::remove_if(services_.begin(), services_.end(), p));
waitables_.erase(std::remove_if(waitables_.begin(), waitables_.end(), p));
guard_conditions_.erase(
std::remove_if(guard_conditions_.begin(), guard_conditions_.end(), p),
guard_conditions_.end());
timers_.erase(std::remove_if(timers_.begin(), timers_.end(), p), timers_.end());
clients_.erase(std::remove_if(clients_.begin(), clients_.end(), p), clients_.end());
services_.erase(std::remove_if(services_.begin(), services_.end(), p), services_.end());
waitables_.erase(std::remove_if(waitables_.begin(), waitables_.end(), p), waitables_.end());
}
void

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>3.0.0</version>
<version>2.2.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>Apache License 2.0</license>

View File

@@ -32,7 +32,7 @@ public:
{
rcl_ret_t ret = rcl_clock_init(clock_type, &rcl_clock_, &allocator_);
if (ret != RCL_RET_OK) {
exceptions::throw_from_rcl_error(ret, "could not get current time stamp");
exceptions::throw_from_rcl_error(ret, "failed to initialize rcl clock");
}
}

View File

@@ -47,17 +47,14 @@ Duration::Duration(std::chrono::nanoseconds nanoseconds)
rcl_duration_.nanoseconds = nanoseconds.count();
}
Duration::Duration(const Duration & rhs)
{
rcl_duration_.nanoseconds = rhs.rcl_duration_.nanoseconds;
}
Duration::Duration(const Duration & rhs) = default;
Duration::Duration(
const builtin_interfaces::msg::Duration & duration_msg)
{
rcl_duration_.nanoseconds =
static_cast<rcl_duration_value_t>(RCL_S_TO_NS(duration_msg.sec));
rcl_duration_.nanoseconds += duration_msg.nanosec;
RCL_S_TO_NS(static_cast<rcl_duration_value_t>(duration_msg.sec));
rcl_duration_.nanoseconds += static_cast<rcl_duration_value_t>(duration_msg.nanosec);
}
Duration::Duration(const rcl_duration_t & duration)
@@ -69,24 +66,25 @@ Duration::Duration(const rcl_duration_t & duration)
Duration::operator builtin_interfaces::msg::Duration() const
{
builtin_interfaces::msg::Duration msg_duration;
msg_duration.sec = static_cast<std::int32_t>(RCL_NS_TO_S(rcl_duration_.nanoseconds));
msg_duration.nanosec =
static_cast<std::uint32_t>(rcl_duration_.nanoseconds % (1000 * 1000 * 1000));
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
const auto result = std::div(rcl_duration_.nanoseconds, kDivisor);
if (result.rem >= 0) {
msg_duration.sec = static_cast<std::int32_t>(result.quot);
msg_duration.nanosec = static_cast<std::uint32_t>(result.rem);
} else {
msg_duration.sec = static_cast<std::int32_t>(result.quot - 1);
msg_duration.nanosec = static_cast<std::uint32_t>(kDivisor + result.rem);
}
return msg_duration;
}
Duration &
Duration::operator=(const Duration & rhs)
{
rcl_duration_.nanoseconds = rhs.rcl_duration_.nanoseconds;
return *this;
}
Duration::operator=(const Duration & rhs) = default;
Duration &
Duration::operator=(const builtin_interfaces::msg::Duration & duration_msg)
{
rcl_duration_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(duration_msg.sec));
rcl_duration_.nanoseconds += duration_msg.nanosec;
*this = Duration(duration_msg);
return *this;
}
@@ -96,6 +94,12 @@ Duration::operator==(const rclcpp::Duration & rhs) const
return rcl_duration_.nanoseconds == rhs.rcl_duration_.nanoseconds;
}
bool
Duration::operator!=(const rclcpp::Duration & rhs) const
{
return rcl_duration_.nanoseconds != rhs.rcl_duration_.nanoseconds;
}
bool
Duration::operator<(const rclcpp::Duration & rhs) const
{
@@ -230,6 +234,10 @@ Duration::seconds() const
rmw_time_t
Duration::to_rmw_time() const
{
if (rcl_duration_.nanoseconds < 0) {
throw std::runtime_error("rmw_time_t cannot be negative");
}
// reuse conversion logic from msg creation
builtin_interfaces::msg::Duration msg = *this;
rmw_time_t result;

View File

@@ -28,8 +28,6 @@
#include "rcutils/logging_macros.h"
using namespace std::chrono_literals;
using rclcpp::exceptions::throw_from_rcl_error;
using rclcpp::AnyExecutable;
using rclcpp::Executor;
@@ -214,21 +212,8 @@ Executor::spin_node_some(std::shared_ptr<rclcpp::Node> node)
this->spin_node_some(node->get_node_base_interface());
}
void Executor::spin_some(std::chrono::nanoseconds max_duration)
{
return this->spin_some_impl(max_duration, false);
}
void Executor::spin_all(std::chrono::nanoseconds max_duration)
{
if (max_duration <= 0ns) {
throw std::invalid_argument("max_duration must be positive");
}
return this->spin_some_impl(max_duration, true);
}
void
Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
Executor::spin_some(std::chrono::nanoseconds max_duration)
{
auto start = std::chrono::steady_clock::now();
auto max_duration_not_elapsed = [max_duration, start]() {
@@ -247,20 +232,14 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
throw std::runtime_error("spin_some() called while already spinning");
}
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
bool work_available = false;
// non-blocking call to pre-load all available work
wait_for_work(std::chrono::milliseconds::zero());
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
AnyExecutable any_exec;
if (!work_available) {
wait_for_work(std::chrono::milliseconds::zero());
}
if (get_next_ready_executable(any_exec)) {
execute_any_executable(any_exec);
work_available = true;
} else {
if (!work_available || !exhaustive) {
break;
}
work_available = false;
break;
}
}
}

View File

@@ -159,7 +159,7 @@ __lockless_has_parameter(
// see https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
RCLCPP_LOCAL
bool
__are_doubles_equal(double x, double y, size_t ulp = 100)
__are_doubles_equal(double x, double y, double ulp = 100.0)
{
return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * ulp;
}

View File

@@ -176,7 +176,7 @@ NodeOptions::parameter_overrides(const std::vector<rclcpp::Parameter> & paramete
bool
NodeOptions::use_global_arguments() const
{
return this->node_options_->use_global_arguments;
return this->use_global_arguments_;
}
NodeOptions &
@@ -338,7 +338,7 @@ NodeOptions::get_domain_id_from_env() const
_dupenv_s(&ros_domain_id, &ros_domain_id_size, env_var);
#endif
if (ros_domain_id) {
uint32_t number = strtoul(ros_domain_id, NULL, 0);
uint32_t number = static_cast<uint32_t>(strtoul(ros_domain_id, NULL, 0));
if (number == (std::numeric_limits<uint32_t>::max)()) {
#ifdef _WIN32
// free the ros_domain_id before throwing, if getenv was used on Windows

View File

@@ -63,17 +63,13 @@ Time::Time(int64_t nanoseconds, rcl_clock_type_t clock_type)
rcl_time_.nanoseconds = nanoseconds;
}
Time::Time(const Time & rhs)
: rcl_time_(rhs.rcl_time_)
{
rcl_time_.nanoseconds = rhs.rcl_time_.nanoseconds;
}
Time::Time(const Time & rhs) = default;
Time::Time(
const builtin_interfaces::msg::Time & time_msg,
rcl_clock_type_t ros_time)
rcl_clock_type_t clock_type)
: rcl_time_(init_time_point(clock_type))
{
rcl_time_ = init_time_point(ros_time);
if (time_msg.sec < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
@@ -95,31 +91,25 @@ Time::~Time()
Time::operator builtin_interfaces::msg::Time() const
{
builtin_interfaces::msg::Time msg_time;
msg_time.sec = static_cast<std::int32_t>(RCL_NS_TO_S(rcl_time_.nanoseconds));
msg_time.nanosec = static_cast<std::uint32_t>(rcl_time_.nanoseconds % (1000 * 1000 * 1000));
constexpr rcl_time_point_value_t kRemainder = RCL_S_TO_NS(1);
const auto result = std::div(rcl_time_.nanoseconds, kRemainder);
if (result.rem >= 0) {
msg_time.sec = static_cast<std::int32_t>(result.quot);
msg_time.nanosec = static_cast<std::uint32_t>(result.rem);
} else {
msg_time.sec = static_cast<std::int32_t>(result.quot - 1);
msg_time.nanosec = static_cast<std::uint32_t>(kRemainder + result.rem);
}
return msg_time;
}
Time &
Time::operator=(const Time & rhs)
{
rcl_time_ = rhs.rcl_time_;
return *this;
}
Time::operator=(const Time & rhs) = default;
Time &
Time::operator=(const builtin_interfaces::msg::Time & time_msg)
{
if (time_msg.sec < 0) {
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
}
rcl_clock_type_t ros_time = RCL_ROS_TIME;
rcl_time_ = init_time_point(ros_time); // TODO(tfoote) hard coded ROS here
rcl_time_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(time_msg.sec));
rcl_time_.nanoseconds += time_msg.nanosec;
*this = Time(time_msg);
return *this;
}

View File

@@ -83,7 +83,7 @@ TEST_F(TestMultiThreadedExecutor, timer_over_take) {
{
std::lock_guard<std::mutex> lock(last_mutex);
double diff = std::abs((now - last).nanoseconds()) / 1.0e9;
double diff = static_cast<double>(std::abs((now - last).nanoseconds())) / 1.0e9;
last = now;
if (diff < PERIOD - TOLERANCE) {

View File

@@ -18,10 +18,10 @@
#include <chrono>
#include <memory>
#include "node_interfaces/node_wrapper.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node.hpp"
#include "node_interfaces/node_wrapper.hpp"
using namespace std::chrono_literals;
@@ -61,58 +61,3 @@ TEST(TestCreateTimer, call_with_node_wrapper_compiles)
[]() {});
rclcpp::shutdown();
}
TEST(TestCreateTimer, call_wall_timer_with_bad_arguments)
{
rclcpp::init(0, nullptr);
NodeWrapper node("test_create_wall_timers_with_bad_arguments");
auto callback = []() {};
rclcpp::CallbackGroup::SharedPtr group = nullptr;
auto node_interface =
rclcpp::node_interfaces::get_node_base_interface(node).get();
auto timers_interface =
rclcpp::node_interfaces::get_node_timers_interface(node).get();
// Negative period
EXPECT_THROW(
rclcpp::create_wall_timer(-1ms, callback, group, node_interface, timers_interface),
std::invalid_argument);
// Very negative period
constexpr auto nanoseconds_min = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::create_wall_timer(
nanoseconds_min, callback, group, node_interface, timers_interface),
std::invalid_argument);
// Period must be less than nanoseconds::max()
constexpr auto nanoseconds_max = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::create_wall_timer(
nanoseconds_max, callback, group, node_interface, timers_interface),
std::invalid_argument);
EXPECT_NO_THROW(
rclcpp::create_wall_timer(
nanoseconds_max - 1us, callback, group, node_interface, timers_interface));
EXPECT_NO_THROW(
rclcpp::create_wall_timer(0ms, callback, group, node_interface, timers_interface));
// Period must be less than nanoseconds::max()
constexpr auto hours_max = std::chrono::hours::max();
EXPECT_THROW(
rclcpp::create_wall_timer(hours_max, callback, group, node_interface, timers_interface),
std::invalid_argument);
// node_interface is null
EXPECT_THROW(
rclcpp::create_wall_timer(1ms, callback, group, nullptr, timers_interface),
std::invalid_argument);
// timers_interface is null
EXPECT_THROW(
rclcpp::create_wall_timer(1ms, callback, group, node_interface, nullptr),
std::invalid_argument);
rclcpp::shutdown();
}

View File

@@ -32,11 +32,7 @@ class TestDuration : public ::testing::Test
{
};
// TEST(TestDuration, conversions) {
// TODO(tfoote) Implement conversion methods
// }
TEST(TestDuration, operators) {
TEST_F(TestDuration, operators) {
rclcpp::Duration old(1, 0);
rclcpp::Duration young(2, 0);
@@ -45,6 +41,7 @@ TEST(TestDuration, operators) {
EXPECT_TRUE(old <= young);
EXPECT_TRUE(young >= old);
EXPECT_FALSE(young == old);
EXPECT_TRUE(young != old);
rclcpp::Duration add = old + young;
EXPECT_EQ(add.nanoseconds(), old.nanoseconds() + young.nanoseconds());
@@ -67,7 +64,7 @@ TEST(TestDuration, operators) {
EXPECT_TRUE(time == assignment_op_duration);
}
TEST(TestDuration, chrono_overloads) {
TEST_F(TestDuration, chrono_overloads) {
int64_t ns = 123456789l;
auto chrono_ns = std::chrono::nanoseconds(ns);
auto d1 = rclcpp::Duration(ns);
@@ -86,7 +83,7 @@ TEST(TestDuration, chrono_overloads) {
EXPECT_EQ(chrono_float_seconds, d5.to_chrono<decltype(chrono_float_seconds)>());
}
TEST(TestDuration, overflows) {
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());
@@ -107,7 +104,7 @@ TEST(TestDuration, overflows) {
EXPECT_THROW(base_d_neg * 4, std::underflow_error);
}
TEST(TestDuration, negative_duration) {
TEST_F(TestDuration, negative_duration) {
rclcpp::Duration assignable_duration = rclcpp::Duration(0) - rclcpp::Duration(5, 0);
{
@@ -130,7 +127,7 @@ TEST(TestDuration, negative_duration) {
}
}
TEST(TestDuration, maximum_duration) {
TEST_F(TestDuration, maximum_duration) {
rclcpp::Duration max_duration = rclcpp::Duration::max();
rclcpp::Duration max(std::numeric_limits<int32_t>::max(), 999999999);
@@ -138,18 +135,105 @@ TEST(TestDuration, maximum_duration) {
}
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
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(TestDuration, from_seconds) {
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(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));
}
TEST(TestDuration, std_chrono_constructors) {
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(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);
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);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), HALF_SEC_IN_NS);
const auto rmw_time = duration.to_rmw_time();
EXPECT_EQ(rmw_time.sec, 0u);
EXPECT_EQ(rmw_time.nsec, static_cast<uint64_t>(HALF_SEC_IN_NS));
const auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), HALF_SEC_IN_NS);
}
{
const rclcpp::Duration duration(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);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), ONE_SEC_IN_NS);
const auto rmw_time = duration.to_rmw_time();
EXPECT_EQ(rmw_time.sec, 1u);
EXPECT_EQ(rmw_time.nsec, 0u);
const auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), ONE_SEC_IN_NS);
}
{
const rclcpp::Duration duration(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);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), ONE_AND_HALF_SEC_IN_NS);
auto rmw_time = duration.to_rmw_time();
EXPECT_EQ(rmw_time.sec, 1u);
EXPECT_EQ(rmw_time.nsec, static_cast<uint64_t>(HALF_SEC_IN_NS));
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), ONE_AND_HALF_SEC_IN_NS);
}
{
rclcpp::Duration duration(-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);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -HALF_SEC_IN_NS);
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), -HALF_SEC_IN_NS);
}
{
rclcpp::Duration duration(-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);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -ONE_SEC_IN_NS);
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), -ONE_SEC_IN_NS);
}
{
rclcpp::Duration duration(-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);
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -ONE_AND_HALF_SEC_IN_NS);
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
EXPECT_EQ(chrono_duration.count(), -ONE_AND_HALF_SEC_IN_NS);
}
}

View File

@@ -67,133 +67,3 @@ TEST_F(TestExecutors, addTemporaryNode) {
executor.add_node(std::make_shared<rclcpp::Node>("temporary_node"));
EXPECT_NO_THROW(executor.spin_some());
}
// Make sure that the spin_until_future_complete works correctly with std::future
TEST_F(TestExecutors, testSpinUntilFutureComplete) {
rclcpp::executors::SingleThreadedExecutor executor;
std::future<void> future;
rclcpp::FutureReturnCode ret;
// test success
future = std::async(
[]() {
return;
});
ret = executor.spin_until_future_complete(future, 1s);
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
// test timeout
future = std::async(
[]() {
std::this_thread::sleep_for(1s);
return;
});
ret = executor.spin_until_future_complete(future, 100ms);
EXPECT_EQ(rclcpp::FutureReturnCode::TIMEOUT, ret);
}
// Make sure that the spin_until_future_complete works correctly with std::shared_future
TEST_F(TestExecutors, testSpinUntilFutureCompleteSharedFuture) {
rclcpp::executors::SingleThreadedExecutor executor;
std::future<void> future;
rclcpp::FutureReturnCode ret;
// test success
future = std::async(
[]() {
return;
});
ret = executor.spin_until_future_complete(future.share(), 1s);
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
// test timeout
future = std::async(
[]() {
std::this_thread::sleep_for(1s);
return;
});
ret = executor.spin_until_future_complete(future.share(), 100ms);
EXPECT_EQ(rclcpp::FutureReturnCode::TIMEOUT, ret);
}
class TestWaitable : public rclcpp::Waitable
{
public:
TestWaitable()
{
rcl_guard_condition_options_t guard_condition_options =
rcl_guard_condition_get_default_options();
gc_ = rcl_get_zero_initialized_guard_condition();
rcl_ret_t ret = rcl_guard_condition_init(
&gc_,
rclcpp::contexts::get_global_default_context()->get_rcl_context().get(),
guard_condition_options);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
bool
add_to_wait_set(rcl_wait_set_t * wait_set) override
{
rcl_ret_t ret = rcl_wait_set_add_guard_condition(wait_set, &gc_, NULL);
if (RCL_RET_OK != ret) {
return false;
}
ret = rcl_trigger_guard_condition(&gc_);
return RCL_RET_OK == ret;
}
bool
is_ready(rcl_wait_set_t * wait_set) override
{
(void)wait_set;
return true;
}
void
execute() override
{
count_++;
std::this_thread::sleep_for(100ms);
}
size_t
get_number_of_ready_guard_conditions() override {return 1;}
size_t
get_count()
{
return count_;
}
private:
size_t count_ = 0;
rcl_guard_condition_t gc_;
};
TEST_F(TestExecutors, testSpinAllvsSpinSome) {
{
rclcpp::executors::SingleThreadedExecutor executor;
auto waitable_interfaces = node->get_node_waitables_interface();
auto my_waitable = std::make_shared<TestWaitable>();
waitable_interfaces->add_waitable(my_waitable, nullptr);
executor.add_node(node);
executor.spin_all(1s);
executor.remove_node(node);
EXPECT_GT(my_waitable->get_count(), 1u);
waitable_interfaces->remove_waitable(my_waitable, nullptr);
}
{
rclcpp::executors::SingleThreadedExecutor executor;
auto waitable_interfaces = node->get_node_waitables_interface();
auto my_waitable = std::make_shared<TestWaitable>();
waitable_interfaces->add_waitable(my_waitable, nullptr);
executor.add_node(node);
executor.spin_some(1s);
executor.remove_node(node);
EXPECT_EQ(my_waitable->get_count(), 1u);
waitable_interfaces->remove_waitable(my_waitable, nullptr);
}
}

View File

@@ -105,6 +105,38 @@ TEST(TestNodeOptions, bad_ros_args) {
rclcpp::exceptions::UnknownROSArgsError);
}
TEST(TestNodeOptions, use_global_arguments) {
{
auto options = rclcpp::NodeOptions();
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
}
{
auto options = rclcpp::NodeOptions().use_global_arguments(false);
EXPECT_FALSE(options.use_global_arguments());
EXPECT_FALSE(options.get_rcl_node_options()->use_global_arguments);
}
{
auto options = rclcpp::NodeOptions().use_global_arguments(true);
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
}
{
auto options = rclcpp::NodeOptions();
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
options.use_global_arguments(false);
EXPECT_FALSE(options.use_global_arguments());
EXPECT_FALSE(options.get_rcl_node_options()->use_global_arguments);
options.use_global_arguments(true);
EXPECT_TRUE(options.use_global_arguments());
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
}
}
TEST(TestNodeOptions, enable_rosout) {
{
auto options = rclcpp::NodeOptions();

View File

@@ -32,7 +32,7 @@ protected:
}
};
TEST(TestParameter, not_set_variant) {
TEST_F(TestParameter, not_set_variant) {
// Direct instantiation
rclcpp::Parameter not_set_variant;
EXPECT_EQ(rclcpp::PARAMETER_NOT_SET, not_set_variant.get_type());
@@ -58,7 +58,7 @@ TEST(TestParameter, not_set_variant) {
rclcpp::Parameter::from_parameter_msg(not_set_param).get_type());
}
TEST(TestParameter, bool_variant) {
TEST_F(TestParameter, bool_variant) {
// Direct instantiation
rclcpp::Parameter bool_variant_true("bool_param", true);
EXPECT_EQ("bool_param", bool_variant_true.get_name());
@@ -116,7 +116,7 @@ TEST(TestParameter, bool_variant) {
bool_variant_false.get_value_message().type);
}
TEST(TestParameter, integer_variant) {
TEST_F(TestParameter, integer_variant) {
const int TEST_VALUE {42};
// Direct instantiation
@@ -164,7 +164,7 @@ TEST(TestParameter, integer_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, long_integer_variant) {
TEST_F(TestParameter, long_integer_variant) {
const int64_t TEST_VALUE {std::numeric_limits<int64_t>::max()};
// Direct instantiation
@@ -212,7 +212,7 @@ TEST(TestParameter, long_integer_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, float_variant) {
TEST_F(TestParameter, float_variant) {
const float TEST_VALUE {42.0f};
// Direct instantiation
@@ -260,7 +260,7 @@ TEST(TestParameter, float_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, double_variant) {
TEST_F(TestParameter, double_variant) {
const double TEST_VALUE {-42.1};
// Direct instantiation
@@ -308,7 +308,7 @@ TEST(TestParameter, double_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, string_variant) {
TEST_F(TestParameter, string_variant) {
const std::string TEST_VALUE {"ROS2"};
// Direct instantiation
@@ -354,7 +354,7 @@ TEST(TestParameter, string_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, byte_array_variant) {
TEST_F(TestParameter, byte_array_variant) {
const std::vector<uint8_t> TEST_VALUE {0x52, 0x4f, 0x53, 0x32};
// Direct instantiation
@@ -402,7 +402,7 @@ TEST(TestParameter, byte_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, bool_array_variant) {
TEST_F(TestParameter, bool_array_variant) {
const std::vector<bool> TEST_VALUE {false, true, true, false, false, true};
// Direct instantiation
@@ -450,7 +450,7 @@ TEST(TestParameter, bool_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, integer_array_variant) {
TEST_F(TestParameter, integer_array_variant) {
const std::vector<int> TEST_VALUE
{42, -99, std::numeric_limits<int>::max(), std::numeric_limits<int>::lowest(), 0};
@@ -529,7 +529,7 @@ TEST(TestParameter, integer_array_variant) {
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY);
}
TEST(TestParameter, long_integer_array_variant) {
TEST_F(TestParameter, long_integer_array_variant) {
const std::vector<int64_t> TEST_VALUE
{42, -99, std::numeric_limits<int64_t>::max(), std::numeric_limits<int64_t>::lowest(), 0};
@@ -583,7 +583,7 @@ TEST(TestParameter, long_integer_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, float_array_variant) {
TEST_F(TestParameter, float_array_variant) {
const std::vector<float> TEST_VALUE
{42.1f, -99.1f, std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest(), 0.1f};
@@ -662,7 +662,7 @@ TEST(TestParameter, float_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, double_array_variant) {
TEST_F(TestParameter, double_array_variant) {
const std::vector<double> TEST_VALUE
{42.1, -99.1, std::numeric_limits<double>::max(), std::numeric_limits<double>::lowest(), 0.1};
@@ -716,7 +716,7 @@ TEST(TestParameter, double_array_variant) {
from_msg.get_value_message().type);
}
TEST(TestParameter, string_array_variant) {
TEST_F(TestParameter, string_array_variant) {
const std::vector<std::string> TEST_VALUE {"R", "O", "S2"};
// Direct instantiation

View File

@@ -24,27 +24,92 @@
#include "test_msgs/msg/empty.hpp"
using test_msgs::msg::Empty;
/**
* Parameterized test.
* The first param are the NodeOptions used to create the nodes.
* The second param are the expect intraprocess count results.
*/
struct TestParameters
namespace
{
rclcpp::NodeOptions node_options[2];
uint64_t intraprocess_count_results[2];
std::string description;
template<typename ... Ts>
class NodeCreationPolicy
{
public:
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
rclcpp::NodeOptions options_;
};
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
template<typename T, typename ... Ts>
class NodeCreationPolicy<T, Ts...>
{
out << params.description;
return out;
}
public:
NodeCreationPolicy()
{
gather<T, Ts...>(options_);
}
class TestPublisherSubscriptionCount : public ::testing::TestWithParam<TestParameters>
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
template<typename U>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return U::gather(options);
}
template<typename U, typename V, typename ... Ws>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return gather<V, Ws...>(U::gather(options));
}
rclcpp::NodeOptions options_;
};
template<bool value>
struct ShouldUseIntraprocess
{
static rclcpp::NodeOptions & gather(rclcpp::NodeOptions & options)
{
return options.use_intra_process_comms(value);
}
};
using UseIntraprocess = ShouldUseIntraprocess<true>;
using DoNotUseIntraprocess = ShouldUseIntraprocess<false>;
struct UseCustomContext
{
static rclcpp::NodeOptions & gather(rclcpp::NodeOptions & options)
{
auto context = rclcpp::Context::make_shared();
context->init(0, nullptr);
return options.context(context);
}
};
struct PrintTestDescription
{
template<typename T>
static std::string GetName(int i)
{
static_cast<void>(i);
return T::description;
}
};
} // namespace
template<typename TestDescription>
class TestPublisherSubscriptionCount : public ::testing::Test
{
public:
static void SetUpTestCase()
@@ -57,126 +122,128 @@ public:
}
protected:
void SetUp() {}
static void OnMessage(const test_msgs::msg::Empty::SharedPtr msg)
{
(void)msg;
}
void TearDown() {}
static std::chrono::milliseconds offset;
std::chrono::milliseconds offset{2000};
};
std::chrono::milliseconds TestPublisherSubscriptionCount::offset = std::chrono::milliseconds(2000);
void OnMessage(const test_msgs::msg::Empty::SharedPtr msg)
/* Testing publisher subscription count api and internal process subscription count.
* Two subscriptions in the same topic, both using intraprocess comm.
*/
struct TwoSubscriptionsIntraprocessComm
{
(void)msg;
}
static constexpr const char * description =
"two_subscriptions_intraprocess_comm";
using FirstNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
using SecondNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
TEST_P(TestPublisherSubscriptionCount, increasing_and_decreasing_counts)
static constexpr bool first_node_talks_intraprocess{true};
static constexpr bool both_nodes_talk_intraprocess{true};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two subscriptions, one using intra-process comm and the other not using it.
*/
struct TwoSubscriptionsOneIntraprocessOneNot
{
TestParameters parameters = GetParam();
static constexpr const char * description =
"two_subscriptions_one_intraprocess_one_not";
using FirstNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
using SecondNodeCreationPolicy = NodeCreationPolicy<>;
static constexpr bool first_node_talks_intraprocess{true};
static constexpr bool both_nodes_talk_intraprocess{false};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two contexts, both using intra-process.
*/
struct TwoSubscriptionsInTwoContextsWithIntraprocessComm
{
static constexpr const char * description =
"two_subscriptions_in_two_contexts_with_intraprocess_comm";
using FirstNodeCreationPolicy = NodeCreationPolicy<UseIntraprocess>;
using SecondNodeCreationPolicy = NodeCreationPolicy<UseCustomContext, UseIntraprocess>;
static constexpr bool first_node_talks_intraprocess{true};
static constexpr bool both_nodes_talk_intraprocess{false};
};
/* Testing publisher subscription count api and internal process subscription count.
* Two contexts, both of them not using intra-process comm.
*/
struct TwoSubscriptionsInTwoContextsWithoutIntraprocessComm
{
static constexpr const char * description =
"two_subscriptions_in_two_contexts_without_intraprocess_comm";
using FirstNodeCreationPolicy = NodeCreationPolicy<>;
using SecondNodeCreationPolicy = NodeCreationPolicy<UseCustomContext>;
static constexpr bool first_node_talks_intraprocess{false};
static constexpr bool both_nodes_talk_intraprocess{false};
};
using AllTestDescriptions = ::testing::Types<
TwoSubscriptionsIntraprocessComm,
TwoSubscriptionsOneIntraprocessOneNot,
TwoSubscriptionsInTwoContextsWithIntraprocessComm,
TwoSubscriptionsInTwoContextsWithoutIntraprocessComm
>;
TYPED_TEST_CASE(TestPublisherSubscriptionCount, AllTestDescriptions, PrintTestDescription);
using test_msgs::msg::Empty;
TYPED_TEST(TestPublisherSubscriptionCount, increasing_and_decreasing_counts)
{
using TestDescription = TypeParam;
typename TestDescription::FirstNodeCreationPolicy my_node_creation_policy;
rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(
"my_node",
"/ns",
parameters.node_options[0]);
my_node_creation_policy.node_options());
auto publisher = node->create_publisher<Empty>("/topic", 10);
EXPECT_EQ(publisher->get_subscription_count(), 0u);
EXPECT_EQ(publisher->get_intra_process_subscription_count(), 0u);
{
auto sub = node->create_subscription<Empty>("/topic", 10, &OnMessage);
rclcpp::sleep_for(offset);
auto sub = node->create_subscription<Empty>(
"/topic", 10, &TestPublisherSubscriptionCount<TestDescription>::OnMessage);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 1u);
EXPECT_EQ(
publisher->get_intra_process_subscription_count(),
parameters.intraprocess_count_results[0]);
(TestDescription::first_node_talks_intraprocess ? 1u : 0u));
{
typename TestDescription::SecondNodeCreationPolicy another_node_creation_policy;
rclcpp::Node::SharedPtr another_node = std::make_shared<rclcpp::Node>(
"another_node",
"/ns",
parameters.node_options[1]);
auto another_sub =
another_node->create_subscription<Empty>("/topic", 10, &OnMessage);
another_node_creation_policy.node_options());
auto another_sub = another_node->create_subscription<Empty>(
"/topic", 10, &TestPublisherSubscriptionCount<TestDescription>::OnMessage);
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 2u);
EXPECT_EQ(
publisher->get_intra_process_subscription_count(),
parameters.intraprocess_count_results[1]);
(TestDescription::first_node_talks_intraprocess ? 1u : 0u) +
(TestDescription::both_nodes_talk_intraprocess ? 1u : 0u));
}
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 1u);
EXPECT_EQ(
publisher->get_intra_process_subscription_count(),
parameters.intraprocess_count_results[0]);
(TestDescription::first_node_talks_intraprocess ? 1u : 0u));
}
/**
* Counts should be zero here, as all are subscriptions are out of scope.
* Subscriptions count checking is always preceeded with an sleep, as random failures had been
* detected without it. */
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(publisher->get_subscription_count(), 0u);
EXPECT_EQ(publisher->get_intra_process_subscription_count(), 0u);
}
auto get_new_context()
{
auto context = rclcpp::Context::make_shared();
context->init(0, nullptr);
return context;
}
TestParameters parameters[] = {
/*
Testing publisher subscription count api and internal process subscription count.
Two subscriptions in the same topic, both using intraprocess comm.
*/
{
{
rclcpp::NodeOptions().use_intra_process_comms(true),
rclcpp::NodeOptions().use_intra_process_comms(true)
},
{1u, 2u},
"two_subscriptions_intraprocess_comm"
},
/*
Testing publisher subscription count api and internal process subscription count.
Two subscriptions, one using intra-process comm and the other not using it.
*/
{
{
rclcpp::NodeOptions().use_intra_process_comms(true),
rclcpp::NodeOptions().use_intra_process_comms(false)
},
{1u, 1u},
"two_subscriptions_one_intraprocess_one_not"
},
/*
Testing publisher subscription count api and internal process subscription count.
Two contexts, both using intra-process.
*/
{
{
rclcpp::NodeOptions().use_intra_process_comms(true),
rclcpp::NodeOptions().context(get_new_context()).use_intra_process_comms(true)
},
{1u, 1u},
"two_subscriptions_in_two_contexts_with_intraprocess_comm"
},
/*
Testing publisher subscription count api and internal process subscription count.
Two contexts, both of them not using intra-process comm.
*/
{
{
rclcpp::NodeOptions().use_intra_process_comms(false),
rclcpp::NodeOptions().context(get_new_context()).use_intra_process_comms(false)
},
{0u, 0u},
"two_subscriptions_in_two_contexts_without_intraprocess_comm"
}
};
INSTANTIATE_TEST_CASE_P(
TestWithDifferentNodeOptions, TestPublisherSubscriptionCount,
::testing::ValuesIn(parameters),
::testing::PrintToStringParamName());

View File

@@ -1,4 +1,4 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
// Copyright 2019-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.
@@ -23,21 +23,79 @@
#include "test_msgs/msg/empty.hpp"
using test_msgs::msg::Empty;
struct TestParameters
namespace
{
rclcpp::NodeOptions node_options;
std::string description;
template<typename ... Ts>
class NodeCreationPolicy
{
public:
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
rclcpp::NodeOptions options_;
};
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
template<typename T, typename ... Ts>
class NodeCreationPolicy<T, Ts...>
{
out << params.description;
return out;
}
public:
NodeCreationPolicy()
{
gather<T, Ts...>(options_);
}
class TestSubscriptionPublisherCount : public ::testing::TestWithParam<TestParameters>
rclcpp::NodeOptions & node_options()
{
return options_;
}
private:
template<typename U>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return U::gather(options);
}
template<typename U, typename V, typename ... Ws>
static rclcpp::NodeOptions &
gather(rclcpp::NodeOptions & options)
{
return gather<V, Ws...>(U::gather(options));
}
rclcpp::NodeOptions options_;
};
struct UseCustomContext
{
static rclcpp::NodeOptions & gather(rclcpp::NodeOptions & options)
{
auto context = rclcpp::Context::make_shared();
context->init(0, nullptr);
return options.context(context);
}
};
struct PrintTestDescription
{
template<typename T>
static std::string GetName(int i)
{
static_cast<void>(i);
return T::description;
}
};
} // namespace
template<typename TestDescription>
class TestSubscriptionPublisherCount : public ::testing::Test
{
public:
static void SetUpTestCase()
@@ -50,78 +108,59 @@ public:
}
protected:
void SetUp() {}
void TearDown() {}
static std::chrono::milliseconds offset;
static void OnMessage(const test_msgs::msg::Empty::SharedPtr msg)
{
(void)msg;
}
std::chrono::milliseconds offset{2000};
};
std::chrono::milliseconds TestSubscriptionPublisherCount::offset = std::chrono::milliseconds(2000);
void OnMessage(const test_msgs::msg::Empty::SharedPtr msg)
struct OneContextPerTest
{
(void)msg;
}
static constexpr const char * description = "one_context_test";
using NodeCreationPolicy = ::NodeCreationPolicy<>;
};
TEST_P(TestSubscriptionPublisherCount, increasing_and_decreasing_counts)
struct TwoContextsPerTest
{
rclcpp::NodeOptions node_options = GetParam().node_options;
rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>(
"my_node",
"/ns",
node_options);
auto subscription = node->create_subscription<Empty>("/topic", 10, &OnMessage);
static constexpr const char * description = "two_contexts_test";
using NodeCreationPolicy = ::NodeCreationPolicy<UseCustomContext>;
};
using AllTestDescriptions = ::testing::Types<OneContextPerTest, TwoContextsPerTest>;
TYPED_TEST_CASE(TestSubscriptionPublisherCount, AllTestDescriptions, PrintTestDescription);
using test_msgs::msg::Empty;
TYPED_TEST(TestSubscriptionPublisherCount, increasing_and_decreasing_counts)
{
using TestDescription = TypeParam;
rclcpp::Node::SharedPtr node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto subscription = node->create_subscription<Empty>(
"/topic", 10, &TestSubscriptionPublisherCount<TestDescription>::OnMessage);
EXPECT_EQ(subscription->get_publisher_count(), 0u);
{
auto pub = node->create_publisher<Empty>("/topic", 10);
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 1u);
{
typename TestDescription::NodeCreationPolicy node_creation_policy;
rclcpp::Node::SharedPtr another_node = std::make_shared<rclcpp::Node>(
"another_node",
"/ns",
node_options);
node_creation_policy.node_options());
auto another_pub =
another_node->create_publisher<Empty>("/topic", 10);
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 2u);
}
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 1u);
}
rclcpp::sleep_for(offset);
rclcpp::sleep_for(this->offset);
EXPECT_EQ(subscription->get_publisher_count(), 0u);
}
auto get_new_context()
{
auto context = rclcpp::Context::make_shared();
context->init(0, nullptr);
return context;
}
TestParameters parameters[] = {
/*
Testing subscription publisher count api.
One context.
*/
{
rclcpp::NodeOptions(),
"one_context_test"
},
/*
Testing subscription publisher count api.
Two contexts.
*/
{
rclcpp::NodeOptions().context(get_new_context()),
"two_contexts_test"
}
};
INSTANTIATE_TEST_CASE_P(
TestWithDifferentNodeOptions,
TestSubscriptionPublisherCount,
testing::ValuesIn(parameters),
testing::PrintToStringParamName());

View File

@@ -45,7 +45,7 @@ protected:
}
};
TEST(TestTime, clock_type_access) {
TEST_F(TestTime, clock_type_access) {
rclcpp::Clock ros_clock(RCL_ROS_TIME);
EXPECT_EQ(RCL_ROS_TIME, ros_clock.get_clock_type());
@@ -57,7 +57,7 @@ TEST(TestTime, clock_type_access) {
}
// Check that the clock may go out of the scope before the jump callback without leading in UB.
TEST(TestTime, clock_jump_callback_destruction_order) {
TEST_F(TestTime, clock_jump_callback_destruction_order) {
rclcpp::JumpHandler::SharedPtr handler;
{
rclcpp::Clock ros_clock(RCL_ROS_TIME);
@@ -68,7 +68,7 @@ TEST(TestTime, clock_jump_callback_destruction_order) {
}
}
TEST(TestTime, time_sources) {
TEST_F(TestTime, time_sources) {
using builtin_interfaces::msg::Time;
rclcpp::Clock ros_clock(RCL_ROS_TIME);
Time ros_now = ros_clock.now();
@@ -86,44 +86,124 @@ TEST(TestTime, time_sources) {
EXPECT_NE(0u, steady_now.nanosec);
}
TEST(TestTime, conversions) {
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
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(TestTime, conversions) {
rclcpp::Clock system_clock(RCL_SYSTEM_TIME);
rclcpp::Time now = system_clock.now();
builtin_interfaces::msg::Time now_msg = now;
rclcpp::Time now_again = now_msg;
EXPECT_EQ(now.nanoseconds(), now_again.nanoseconds());
builtin_interfaces::msg::Time msg;
msg.sec = 12345;
msg.nanosec = 67890;
rclcpp::Time time = msg;
EXPECT_EQ(
RCL_S_TO_NS(static_cast<int64_t>(msg.sec)) + static_cast<int64_t>(msg.nanosec),
time.nanoseconds());
EXPECT_EQ(static_cast<int64_t>(msg.sec), RCL_NS_TO_S(time.nanoseconds()));
builtin_interfaces::msg::Time negative_time_msg;
negative_time_msg.sec = -1;
negative_time_msg.nanosec = 1;
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time = negative_time_msg;
});
rclcpp::Time now = system_clock.now();
builtin_interfaces::msg::Time now_msg = now;
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
rclcpp::Time now_again = now_msg;
EXPECT_EQ(now.nanoseconds(), now_again.nanoseconds());
}
EXPECT_ANY_THROW(
{
rclcpp::Time assignment(1, 2);
assignment = negative_time_msg;
});
rclcpp::Time positive_time = rclcpp::Time(12345, 67890u);
builtin_interfaces::msg::Time msg = positive_time;
EXPECT_EQ(msg.sec, 12345);
EXPECT_EQ(msg.nanosec, 67890u);
rclcpp::Time time = msg;
EXPECT_EQ(time.nanoseconds(), positive_time.nanoseconds());
EXPECT_EQ(
RCL_S_TO_NS(static_cast<int64_t>(msg.sec)) + static_cast<int64_t>(msg.nanosec),
time.nanoseconds());
EXPECT_EQ(static_cast<int64_t>(msg.sec), RCL_NS_TO_S(time.nanoseconds()));
}
// throw on construction/assignment of negative times
{
builtin_interfaces::msg::Time negative_time_msg;
negative_time_msg.sec = -1;
negative_time_msg.nanosec = 1;
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time = negative_time_msg;
});
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
EXPECT_ANY_THROW(
{
rclcpp::Time assignment(1, 2);
assignment = negative_time_msg;
});
}
{
const rclcpp::Time time(HALF_SEC_IN_NS);
const auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, 0);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), HALF_SEC_IN_NS);
}
{
const rclcpp::Time time(ONE_SEC_IN_NS);
const auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, 1);
EXPECT_EQ(time_msg.nanosec, 0u);
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), ONE_SEC_IN_NS);
}
{
const rclcpp::Time time(ONE_AND_HALF_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, 1);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), ONE_AND_HALF_SEC_IN_NS);
}
{
// Can rclcpp::Time be negative or not? The following constructor works:
rclcpp::Time time(-HALF_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, -1);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
// The opposite conversion throws...
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time(time_msg);
});
}
{
// Can rclcpp::Time be negative or not? The following constructor works:
rclcpp::Time time(-ONE_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, -1);
EXPECT_EQ(time_msg.nanosec, 0u);
// The opposite conversion throws...
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time(time_msg);
});
}
{
// Can rclcpp::Time be negative or not? The following constructor works:
rclcpp::Time time(-ONE_AND_HALF_SEC_IN_NS);
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
EXPECT_EQ(time_msg.sec, -2);
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
// The opposite conversion throws...
EXPECT_ANY_THROW(
{
rclcpp::Time negative_time(time_msg);
});
}
}
TEST(TestTime, operators) {
TEST_F(TestTime, operators) {
rclcpp::Time old(1, 0);
rclcpp::Time young(2, 0);
@@ -178,7 +258,7 @@ TEST(TestTime, operators) {
}
}
TEST(TestTime, overflow_detectors) {
TEST_F(TestTime, overflow_detectors) {
/////////////////////////////////////////////////////////////////////////////
// Test logical_eq call first:
EXPECT_TRUE(logical_eq(false, false));
@@ -198,8 +278,8 @@ TEST(TestTime, overflow_detectors) {
// 256 * 256 = 64K total loops, should be pretty fast on everything
for (big_type_t y = min_val; y <= max_val; ++y) {
for (big_type_t x = min_val; x <= max_val; ++x) {
const big_type_t sum = x + y;
const big_type_t diff = x - y;
const big_type_t sum = static_cast<big_type_t>(x + y);
const big_type_t diff = static_cast<big_type_t>(x - y);
const bool add_will_overflow =
rclcpp::add_will_overflow(test_type_t(x), test_type_t(y));
@@ -235,7 +315,7 @@ TEST(TestTime, overflow_detectors) {
EXPECT_TRUE(rclcpp::sub_will_underflow<int64_t>(INT64_MIN, 1));
}
TEST(TestTime, overflows) {
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);
@@ -267,7 +347,7 @@ TEST(TestTime, overflows) {
EXPECT_NO_THROW(one_time - two_time);
}
TEST(TestTime, seconds) {
TEST_F(TestTime, seconds) {
EXPECT_DOUBLE_EQ(0.0, rclcpp::Time(0, 0).seconds());
EXPECT_DOUBLE_EQ(4.5, rclcpp::Time(4, 500000000).seconds());
EXPECT_DOUBLE_EQ(2.5, rclcpp::Time(0, 2500000000).seconds());

View File

@@ -3,12 +3,19 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3.0.0 (2020-06-18)
2.2.0 (2020-10-07)
------------------
* Add rcl_action_client_options when creating action client. (`#1133 <https://github.com/ros2/rclcpp/issues/1133>`_)
* Fix doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_)
* Increase rclcpp_action test coverage (`#1153 <https://github.com/ros2/rclcpp/issues/1153>`_)
* Contributors: Alejandro Hernández Cordero, Michel Hidalgo, tomoya
2.1.0 (2020-08-03)
------------------
2.0.2 (2020-07-07)
------------------
2.0.1 (2020-06-23)
------------------
* Fixed doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_) (`#1191 <https://github.com/ros2/rclcpp/issues/1191>`_)
* Contributors: Alejandro Hernández Cordero
2.0.0 (2020-06-01)
------------------

View File

@@ -317,7 +317,7 @@ public:
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
const std::string & action_name,
const rcl_action_client_options_t & client_options = rcl_action_client_get_default_options()
const rcl_action_client_options_t client_options = rcl_action_client_get_default_options()
)
: ClientBase(
node_base, node_graph, node_logging, action_name,

View File

@@ -37,7 +37,6 @@ namespace rclcpp_action
* \param[in] name The action name.
* \param[in] group The action client will be added to this callback group.
* If `nullptr`, then the action client is added to the default callback group.
* \param[in] options Options to pass to the underlying `rcl_action_client_t`.
*/
template<typename ActionT>
typename Client<ActionT>::SharedPtr
@@ -47,8 +46,7 @@ create_client(
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_interface,
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_interface,
const std::string & name,
rclcpp::CallbackGroup::SharedPtr group = nullptr,
const rcl_action_client_options_t & options = rcl_action_client_get_default_options())
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
std::weak_ptr<rclcpp::node_interfaces::NodeWaitablesInterface> weak_node =
node_waitables_interface;
@@ -61,19 +59,20 @@ create_client(
return;
}
auto shared_node = weak_node.lock();
if (shared_node) {
// API expects a shared pointer, give it one with a deleter that does nothing.
std::shared_ptr<Client<ActionT>> fake_shared_ptr(ptr, [](Client<ActionT> *) {});
if (!shared_node) {
return;
}
// API expects a shared pointer, give it one with a deleter that does nothing.
std::shared_ptr<Client<ActionT>> fake_shared_ptr(ptr, [](Client<ActionT> *) {});
if (group_is_null) {
// Was added to default group
shared_node->remove_waitable(fake_shared_ptr, nullptr);
} else {
// Was added to a specific group
auto shared_group = weak_group.lock();
if (shared_group) {
shared_node->remove_waitable(fake_shared_ptr, shared_group);
}
if (group_is_null) {
// Was added to default group
shared_node->remove_waitable(fake_shared_ptr, nullptr);
} else {
// Was added to a specfic group
auto shared_group = weak_group.lock();
if (shared_group) {
shared_node->remove_waitable(fake_shared_ptr, shared_group);
}
}
delete ptr;
@@ -84,8 +83,7 @@ create_client(
node_base_interface,
node_graph_interface,
node_logging_interface,
name,
options),
name),
deleter);
node_waitables_interface->add_waitable(action_client, group);
@@ -98,15 +96,13 @@ create_client(
* \param[in] name The action name.
* \param[in] group The action client will be added to this callback group.
* If `nullptr`, then the action client is added to the default callback group.
* \param[in] options Options to pass to the underlying `rcl_action_client_t`.
*/
template<typename ActionT, typename NodeT>
typename Client<ActionT>::SharedPtr
create_client(
NodeT node,
const std::string & name,
rclcpp::CallbackGroup::SharedPtr group = nullptr,
const rcl_action_client_options_t & options = rcl_action_client_get_default_options())
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return rclcpp_action::create_client<ActionT>(
node->get_node_base_interface(),
@@ -114,8 +110,7 @@ create_client(
node->get_node_logging_interface(),
node->get_node_waitables_interface(),
name,
group,
options);
group);
}
} // namespace rclcpp_action

View File

@@ -49,7 +49,7 @@ namespace rclcpp_action
* The return from this callback only indicates if the server will try to cancel a goal.
* It does not indicate if the goal was actually canceled.
* \param[in] handle_accepted A callback that is called to give the user a handle to the goal.
* \param[in] options Options to pass to the underlying `rcl_action_server_t`.
* \param[in] options options to pass to the underlying `rcl_action_server_t`.
* \param[in] group The action server will be added to this callback group.
* If `nullptr`, then the action server is added to the default callback group.
*/
@@ -78,19 +78,20 @@ create_server(
return;
}
auto shared_node = weak_node.lock();
if (shared_node) {
// API expects a shared pointer, give it one with a deleter that does nothing.
std::shared_ptr<Server<ActionT>> fake_shared_ptr(ptr, [](Server<ActionT> *) {});
if (!shared_node) {
return;
}
// API expects a shared pointer, give it one with a deleter that does nothing.
std::shared_ptr<Server<ActionT>> fake_shared_ptr(ptr, [](Server<ActionT> *) {});
if (group_is_null) {
// Was added to default group
shared_node->remove_waitable(fake_shared_ptr, nullptr);
} else {
// Was added to a specific group
auto shared_group = weak_group.lock();
if (shared_group) {
shared_node->remove_waitable(fake_shared_ptr, shared_group);
}
if (group_is_null) {
// Was added to default group
shared_node->remove_waitable(fake_shared_ptr, nullptr);
} else {
// Was added to a specfic group
auto shared_group = weak_group.lock();
if (shared_group) {
shared_node->remove_waitable(fake_shared_ptr, shared_group);
}
}
delete ptr;
@@ -123,7 +124,7 @@ create_server(
* The return from this callback only indicates if the server will try to cancel a goal.
* It does not indicate if the goal was actually canceled.
* \param[in] handle_accepted A callback that is called to give the user a handle to the goal.
* \param[in] options Options to pass to the underlying `rcl_action_server_t`.
* \param[in] options options to pass to the underlying `rcl_action_server_t`.
* \param[in] group The action server will be added to this callback group.
* If `nullptr`, then the action server is added to the default callback group.
*/

View File

@@ -296,7 +296,7 @@ public:
* \param[in] name the name of an action.
* The same name and type must be used by both the action client and action server to
* communicate.
* \param[in] options Options to pass to the underlying `rcl_action_server_t`.
* \param[in] options options to pass to the underlying `rcl_action_server_t`.
* \param[in] handle_goal a callback that decides if a goal should be accepted or rejected.
* \param[in] handle_cancel a callback that decides if a goal should be attemted to be canceled.
* The return from this callback only indicates if the server will try to cancel a goal.

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>3.0.0</version>
<version>2.2.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>Apache License 2.0</license>

View File

@@ -32,7 +32,6 @@
#include <test_msgs/action/fibonacci.hpp>
#include <future>
#include <map>
#include <memory>
#include <string>
@@ -74,7 +73,7 @@ protected:
rclcpp::init(0, nullptr);
}
void SetUpServer()
void SetUp()
{
rcl_allocator_t allocator = rcl_get_default_allocator();
@@ -212,10 +211,7 @@ protected:
ASSERT_TRUE(status_publisher != nullptr);
allocator.deallocate(status_topic_name, allocator.state);
server_executor.add_node(server_node);
}
void SetUp() override
{
client_node = std::make_shared<rclcpp::Node>(client_node_name, namespace_name);
client_executor.add_node(client_node);
@@ -223,12 +219,7 @@ protected:
ASSERT_EQ(RCL_RET_OK, rcl_set_ros_time_override(clock.get_clock_handle(), RCL_S_TO_NS(1)));
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void TearDownServer()
void TearDown()
{
status_publisher.reset();
feedback_publisher.reset();
@@ -236,10 +227,6 @@ protected:
result_service.reset();
goal_service.reset();
server_node.reset();
}
void TearDown() override
{
client_node.reset();
}
@@ -278,42 +265,15 @@ protected:
typename rclcpp::Publisher<ActionStatusMessage>::SharedPtr status_publisher;
};
class TestClientAgainstServer : public TestClient
{
protected:
void SetUp() override
{
SetUpServer();
TestClient::SetUp();
}
void TearDown() override
{
TestClient::TearDown();
TearDownServer();
}
};
TEST_F(TestClient, construction_and_destruction)
{
ASSERT_NO_THROW(rclcpp_action::create_client<ActionType>(client_node, action_name).reset());
}
TEST_F(TestClient, construction_and_destruction_after_node)
{
ASSERT_NO_THROW(
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
client_node.reset();
});
}
TEST_F(TestClient, construction_and_destruction_callback_group)
{
auto group = client_node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
const rcl_action_client_options_t & options = rcl_action_client_get_default_options();
ASSERT_NO_THROW(
rclcpp_action::create_client<ActionType>(
client_node->get_node_base_interface(),
@@ -321,29 +281,11 @@ TEST_F(TestClient, construction_and_destruction_callback_group)
client_node->get_node_logging_interface(),
client_node->get_node_waitables_interface(),
action_name,
group,
options
group
).reset());
}
TEST_F(TestClient, wait_for_action_server)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
EXPECT_FALSE(action_client->wait_for_action_server(0ms));
EXPECT_FALSE(action_client->wait_for_action_server(100ms));
auto future = std::async(
std::launch::async, [&action_client]() {
return action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT);
});
SetUpServer();
EXPECT_TRUE(future.get());
TearDownServer();
client_node.reset(); // Drop node before action client
EXPECT_THROW(action_client->wait_for_action_server(0ms), rclcpp::exceptions::InvalidNodeError);
}
TEST_F(TestClientAgainstServer, async_send_goal_no_callbacks)
TEST_F(TestClient, async_send_goal_no_callbacks)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -364,24 +306,7 @@ TEST_F(TestClientAgainstServer, async_send_goal_no_callbacks)
EXPECT_FALSE(goal_handle->is_result_aware());
}
TEST_F(TestClientAgainstServer, bad_goal_handles)
{
auto action_client0 = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client0->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
ActionGoal goal;
goal.order = 0;
auto future_goal_handle = action_client0->async_send_goal(goal);
dual_spin_until_future_complete(future_goal_handle);
auto goal_handle = future_goal_handle.get();
auto action_client1 = rclcpp_action::create_client<ActionType>(client_node, action_name);
using rclcpp_action::exceptions::UnknownGoalHandleError;
EXPECT_THROW(action_client1->async_get_result(goal_handle), UnknownGoalHandleError);
EXPECT_THROW(action_client1->async_cancel_goal(goal_handle), UnknownGoalHandleError);
}
TEST_F(TestClientAgainstServer, async_send_goal_no_callbacks_wait_for_result)
TEST_F(TestClient, async_send_goal_no_callbacks_wait_for_result)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -404,33 +329,13 @@ TEST_F(TestClientAgainstServer, async_send_goal_no_callbacks_wait_for_result)
EXPECT_EQ(5, wrapped_result.result->sequence[5]);
}
TEST_F(TestClientAgainstServer, async_send_goal_no_callbacks_then_invalidate)
TEST_F(TestClient, async_send_goal_with_goal_response_callback_wait_for_result)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
ActionGoal goal;
goal.order = 5;
auto future_goal_handle = action_client->async_send_goal(goal);
dual_spin_until_future_complete(future_goal_handle);
auto goal_handle = future_goal_handle.get();
ASSERT_NE(nullptr, goal_handle);
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_ACCEPTED, goal_handle->get_status());
auto future_result = action_client->async_get_result(goal_handle);
EXPECT_TRUE(goal_handle->is_result_aware());
action_client.reset(); // Ensure goal handle is invalidated once client goes out of scope
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_UNKNOWN, goal_handle->get_status());
using rclcpp_action::exceptions::UnawareGoalHandleError;
EXPECT_THROW(future_result.get(), UnawareGoalHandleError);
}
TEST_F(TestClientAgainstServer, async_send_goal_with_goal_response_callback_wait_for_result)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
goal.order = 4;
bool goal_response_received = false;
auto send_goal_ops = rclcpp_action::Client<ActionType>::SendGoalOptions();
send_goal_ops.goal_response_callback =
@@ -442,37 +347,23 @@ TEST_F(TestClientAgainstServer, async_send_goal_with_goal_response_callback_wait
goal_response_received = true;
}
};
auto future_goal_handle = action_client->async_send_goal(goal, send_goal_ops);
dual_spin_until_future_complete(future_goal_handle);
auto goal_handle = future_goal_handle.get();
EXPECT_TRUE(goal_response_received);
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_ACCEPTED, goal_handle->get_status());
EXPECT_FALSE(goal_handle->is_feedback_aware());
EXPECT_FALSE(goal_handle->is_result_aware());
auto future_result = action_client->async_get_result(goal_handle);
EXPECT_TRUE(goal_handle->is_result_aware());
dual_spin_until_future_complete(future_result);
auto wrapped_result = future_result.get();
{
ActionGoal bad_goal;
bad_goal.order = -1;
auto future_goal_handle = action_client->async_send_goal(bad_goal, send_goal_ops);
dual_spin_until_future_complete(future_goal_handle);
auto goal_handle = future_goal_handle.get();
EXPECT_FALSE(goal_response_received);
EXPECT_EQ(nullptr, goal_handle);
}
{
ActionGoal goal;
goal.order = 4;
auto future_goal_handle = action_client->async_send_goal(goal, send_goal_ops);
dual_spin_until_future_complete(future_goal_handle);
auto goal_handle = future_goal_handle.get();
EXPECT_TRUE(goal_response_received);
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_ACCEPTED, goal_handle->get_status());
EXPECT_FALSE(goal_handle->is_feedback_aware());
EXPECT_FALSE(goal_handle->is_result_aware());
auto future_result = action_client->async_get_result(goal_handle);
EXPECT_TRUE(goal_handle->is_result_aware());
dual_spin_until_future_complete(future_result);
auto wrapped_result = future_result.get();
ASSERT_EQ(5u, wrapped_result.result->sequence.size());
EXPECT_EQ(3, wrapped_result.result->sequence.back());
}
ASSERT_EQ(5u, wrapped_result.result->sequence.size());
EXPECT_EQ(3, wrapped_result.result->sequence.back());
}
TEST_F(TestClientAgainstServer, async_send_goal_with_feedback_callback_wait_for_result)
TEST_F(TestClient, async_send_goal_with_feedback_callback_wait_for_result)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -506,7 +397,7 @@ TEST_F(TestClientAgainstServer, async_send_goal_with_feedback_callback_wait_for_
EXPECT_EQ(5, feedback_count);
}
TEST_F(TestClientAgainstServer, async_send_goal_with_result_callback_wait_for_result)
TEST_F(TestClient, async_send_goal_with_result_callback_wait_for_result)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -541,7 +432,7 @@ TEST_F(TestClientAgainstServer, async_send_goal_with_result_callback_wait_for_re
EXPECT_EQ(3, wrapped_result.result->sequence.back());
}
TEST_F(TestClientAgainstServer, async_get_result_with_callback)
TEST_F(TestClient, async_get_result_with_callback)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -576,7 +467,7 @@ TEST_F(TestClientAgainstServer, async_get_result_with_callback)
EXPECT_EQ(3, wrapped_result.result->sequence.back());
}
TEST_F(TestClientAgainstServer, async_cancel_one_goal)
TEST_F(TestClient, async_cancel_one_goal)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -594,7 +485,7 @@ TEST_F(TestClientAgainstServer, async_cancel_one_goal)
EXPECT_EQ(ActionCancelGoalResponse::ERROR_NONE, cancel_response->return_code);
}
TEST_F(TestClientAgainstServer, async_cancel_one_goal_with_callback)
TEST_F(TestClient, async_cancel_one_goal_with_callback)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -628,7 +519,7 @@ TEST_F(TestClientAgainstServer, async_cancel_one_goal_with_callback)
EXPECT_TRUE(cancel_response_received);
}
TEST_F(TestClientAgainstServer, async_cancel_all_goals)
TEST_F(TestClient, async_cancel_all_goals)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -664,7 +555,7 @@ TEST_F(TestClientAgainstServer, async_cancel_all_goals)
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_CANCELED, goal_handle1->get_status());
}
TEST_F(TestClientAgainstServer, async_cancel_all_goals_with_callback)
TEST_F(TestClient, async_cancel_all_goals_with_callback)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -714,7 +605,7 @@ TEST_F(TestClientAgainstServer, async_cancel_all_goals_with_callback)
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_CANCELED, goal_handle1->get_status());
}
TEST_F(TestClientAgainstServer, async_cancel_some_goals)
TEST_F(TestClient, async_cancel_some_goals)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
@@ -745,7 +636,7 @@ TEST_F(TestClientAgainstServer, async_cancel_some_goals)
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_CANCELED, goal_handle0->get_status());
}
TEST_F(TestClientAgainstServer, async_cancel_some_goals_with_callback)
TEST_F(TestClient, async_cancel_some_goals_with_callback)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));

View File

@@ -82,42 +82,17 @@ TEST_F(TestServer, construction_and_destruction)
{
auto node = std::make_shared<rclcpp::Node>("construct_node", "/rclcpp_action/construct");
ASSERT_NO_THROW(
{
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
auto as = rclcpp_action::create_server<Fibonacci>(
node, "fibonacci",
[](const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>) {
return rclcpp_action::GoalResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {
return rclcpp_action::CancelResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {});
(void)as;
});
}
TEST_F(TestServer, construction_and_destruction_after_node)
{
auto node = std::make_shared<rclcpp::Node>("construct_node", "/rclcpp_action/construct");
ASSERT_NO_THROW(
{
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
auto as = rclcpp_action::create_server<Fibonacci>(
node, "fibonacci",
[](const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>) {
return rclcpp_action::GoalResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {
return rclcpp_action::CancelResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {});
(void)as;
node.reset();
});
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
auto as = rclcpp_action::create_server<Fibonacci>(
node, "fibonacci",
[](const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>) {
return rclcpp_action::GoalResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {
return rclcpp_action::CancelResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {});
(void)as;
}
TEST_F(TestServer, construction_and_destruction_callback_group)
@@ -758,84 +733,6 @@ TEST_F(TestServer, get_result)
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
auto handle_cancel = [](std::shared_ptr<GoalHandle>)
{
return rclcpp_action::CancelResponse::REJECT;
};
std::shared_ptr<GoalHandle> received_handle;
auto handle_accepted = [&received_handle](std::shared_ptr<GoalHandle> handle)
{
received_handle = handle;
};
const std::chrono::milliseconds result_timeout{50};
rcl_action_server_options_t options = rcl_action_server_get_default_options();
options.result_timeout.nanoseconds = RCL_MS_TO_NS(result_timeout.count());
auto as = rclcpp_action::create_server<Fibonacci>(
node, "fibonacci",
handle_goal,
handle_cancel,
handle_accepted,
options);
(void)as;
send_goal_request(node, uuid);
// Send result request
auto result_client = node->create_client<Fibonacci::Impl::GetResultService>(
"fibonacci/_action/get_result");
if (!result_client->wait_for_service(std::chrono::seconds(20))) {
throw std::runtime_error("get result service didn't become available");
}
auto request = std::make_shared<Fibonacci::Impl::GetResultService::Request>();
request->goal_id.uuid = uuid;
auto future = result_client->async_send_request(request);
// Send a result
auto result = std::make_shared<Fibonacci::Result>();
result->sequence = {5, 8, 13, 21};
received_handle->succeed(result);
// Wait for the result request to be received
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
rclcpp::spin_until_future_complete(node, future));
auto response = future.get();
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
EXPECT_EQ(result->sequence, response->result.sequence);
// Wait for goal expiration
rclcpp::sleep_for(2 * result_timeout);
// Allow for expiration to take place
rclcpp::spin_some(node);
// Send and wait for another result request
future = result_client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
rclcpp::spin_until_future_complete(node, future));
response = future.get();
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_UNKNOWN, response->status);
}
TEST_F(TestServer, get_result_deferred)
{
auto node = std::make_shared<rclcpp::Node>("get_result", "/rclcpp_action/get_result");
const GoalUUID uuid{{1, 2, 3, 4, 5, 6, 7, 80, 90, 10, 11, 12, 13, 14, 15, 160}};
auto handle_goal = [](
const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>)
{
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
};
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
auto handle_cancel = [](std::shared_ptr<GoalHandle>)
{
return rclcpp_action::CancelResponse::REJECT;
@@ -866,10 +763,6 @@ TEST_F(TestServer, get_result_deferred)
request->goal_id.uuid = uuid;
auto future = result_client->async_send_request(request);
// Process request first
rclcpp::sleep_for(std::chrono::milliseconds(10)); // Give a chance for the request to be served
rclcpp::spin_some(node);
// Send a result
auto result = std::make_shared<Fibonacci::Result>();
result->sequence = {5, 8, 13, 21};

View File

@@ -2,13 +2,24 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3.0.0 (2020-06-18)
2.2.0 (2020-10-07)
------------------
* Include original exception in ComponentManagerException (`#1157 <https://github.com/ros2/rclcpp/issues/1157>`_) (`#1223 <https://github.com/ros2/rclcpp/issues/1223>`_)
* Contributors: Dereck Wonnacott
2.1.0 (2020-08-03)
------------------
2.0.2 (2020-07-07)
------------------
2.0.1 (2020-06-23)
------------------
2.0.0 (2020-06-01)
------------------
* Added missing virtual destructors. (`#1149 <https://github.com/ros2/rclcpp/issues/1149>`_)
* Add Security Vulnerability Policy pointing to REP-2006. (`#1130 <https://github.com/ros2/rclcpp/issues/1130>`_)
* Added missing virtual destructors (`#1149 <https://github.com/ros2/rclcpp/issues/1149>`_)
* Add Security Vulnerability Policy pointing to REP-2006 (`#1130 <https://github.com/ros2/rclcpp/issues/1130>`_)
* Contributors: Chris Lalancette, Ivan Santiago Paunovic
1.1.0 (2020-05-26)

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_components</name>
<version>3.0.0</version>
<version>2.2.0</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="michael@openrobotics.org">Michael Carroll</maintainer>
<license>Apache License 2.0</license>

View File

@@ -196,6 +196,11 @@ ComponentManager::OnLoadNode(
try {
node_wrappers_[node_id] = factory->create_node_instance(options);
} catch (const std::exception & ex) {
// In the case that the component constructor throws an exception,
// rethrow into the following catch block.
throw ComponentManagerException(
"Component constructor threw an exception: " + std::string(ex.what()));
} catch (...) {
// In the case that the component constructor throws an exception,
// rethrow into the following catch block.

View File

@@ -3,9 +3,23 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3.0.0 (2020-06-18)
2.2.0 (2020-10-07)
------------------
* Fix doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_)
* Log error instead of throwing exception in Transition and State reset() mark no except (`#1297 <https://github.com/ros2/rclcpp/issues/1297>`_) (`#1378 <https://github.com/ros2/rclcpp/issues/1378>`_)
* Remove rmw-dependent unit-test checks (`#1293 <https://github.com/ros2/rclcpp/issues/1293>`_) (`#1377 <https://github.com/ros2/rclcpp/issues/1377>`_)
* Contributors: Stephen Brawner
2.1.0 (2020-08-03)
------------------
* Warn about unused result of add_on_set_parameters_callback (`#1238 <https://github.com/ros2/rclcpp/issues/1238>`_) (`#1244 <https://github.com/ros2/rclcpp/issues/1244>`_)
* Contributors: Jacob Perron
2.0.2 (2020-07-07)
------------------
2.0.1 (2020-06-23)
------------------
* Fixed doxygen warnings (`#1163 <https://github.com/ros2/rclcpp/issues/1163>`_) (`#1191 <https://github.com/ros2/rclcpp/issues/1191>`_)
* Contributors: Alejandro Hernández Cordero
2.0.0 (2020-06-01)

View File

@@ -42,6 +42,8 @@
#include <utility>
#include <vector>
#include "rcutils/macros.h"
#include "rcl/error_handling.h"
#include "rcl/node.h"
@@ -456,6 +458,7 @@ public:
* \sa rclcpp::Node::add_on_set_parameters_callback
*/
RCLCPP_LIFECYCLE_PUBLIC
RCUTILS_WARN_UNUSED
rclcpp_lifecycle::LifecycleNode::OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(
rclcpp_lifecycle::LifecycleNode::OnParametersSetCallbackType callback);

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_lifecycle</name>
<version>3.0.0</version>
<version>2.2.0</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="karsten@osrfoundation.org">Karsten Knese</maintainer>
<license>Apache License 2.0</license>

View File

@@ -21,6 +21,7 @@
#include "rcl_lifecycle/rcl_lifecycle.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rcutils/allocator.h"
@@ -157,7 +158,9 @@ State::reset()
allocator_.deallocate(state_handle_, allocator_.state);
state_handle_ = nullptr;
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret);
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp_lifecycle"),
"rcl_lifecycle_transition_fini did not complete successfully, leaking memory");
}
}

View File

@@ -21,6 +21,7 @@
#include "rcl_lifecycle/rcl_lifecycle.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rcutils/allocator.h"
@@ -261,7 +262,9 @@ Transition::reset()
allocator_.deallocate(transition_handle_, allocator_.state);
transition_handle_ = nullptr;
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret);
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp_lifecycle"),
"rcl_lifecycle_transition_fini did not complete successfully, leaking memory");
}
}
} // namespace rclcpp_lifecycle

View File

@@ -492,31 +492,51 @@ TEST_F(TestDefaultStateMachine, test_getters) {
TEST_F(TestDefaultStateMachine, test_graph) {
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
auto names = test_node->get_node_names();
EXPECT_EQ(names.size(), 1u);
EXPECT_STREQ(names[0].c_str(), "/testnode");
// parameter_events, rosout, /testnode/transition_event
ASSERT_NE(names.end(), std::find(names.begin(), names.end(), std::string("/testnode")));
// Other topics may exist for an rclcpp::Node, but just checking the lifecycle one exists
auto topic_names_and_types = test_node->get_topic_names_and_types();
EXPECT_EQ(topic_names_and_types.size(), 3u);
ASSERT_NE(
topic_names_and_types.end(),
topic_names_and_types.find(std::string("/testnode/transition_event")));
EXPECT_STREQ(
topic_names_and_types["/testnode/transition_event"][0].c_str(),
"lifecycle_msgs/msg/TransitionEvent");
auto service_names_and_types = test_node->get_service_names_and_types();
EXPECT_EQ(service_names_and_types.size(), 11u);
// These are specific to lifecycle nodes, other services are provided by rclcpp::Node
ASSERT_NE(
service_names_and_types.end(),
service_names_and_types.find(std::string("/testnode/change_state")));
EXPECT_STREQ(
service_names_and_types["/testnode/change_state"][0].c_str(),
"lifecycle_msgs/srv/ChangeState");
ASSERT_NE(
service_names_and_types.end(),
service_names_and_types.find(std::string("/testnode/get_available_states")));
EXPECT_STREQ(
service_names_and_types["/testnode/get_available_states"][0].c_str(),
"lifecycle_msgs/srv/GetAvailableStates");
ASSERT_NE(
service_names_and_types.end(),
service_names_and_types.find(std::string("/testnode/get_available_transitions")));
EXPECT_STREQ(
service_names_and_types["/testnode/get_available_transitions"][0].c_str(),
"lifecycle_msgs/srv/GetAvailableTransitions");
ASSERT_NE(
service_names_and_types.end(),
service_names_and_types.find(std::string("/testnode/get_state")));
EXPECT_STREQ(
service_names_and_types["/testnode/get_state"][0].c_str(),
"lifecycle_msgs/srv/GetState");
ASSERT_NE(
service_names_and_types.end(),
service_names_and_types.find(std::string("/testnode/get_transition_graph")));
EXPECT_STREQ(
service_names_and_types["/testnode/get_transition_graph"][0].c_str(),
"lifecycle_msgs/srv/GetAvailableTransitions");