Compare commits

...

24 Commits

Author SHA1 Message Date
Pedro Pena
a4fe5a5c8c changed type
Signed-off-by: Pedro Pena <peter.a.pena@gmail.com>
2020-07-06 17:05:37 -04:00
Pedro Pena
425a794eb1 fixing warnings
Signed-off-by: Pedro Pena <peter.a.pena@gmail.com>
2020-07-06 17:05:37 -04:00
Pedro Pena
c0f7eb3c45 fixed conversion
Signed-off-by: Pedro Pena <peter.a.pena@gmail.com>
2020-07-06 17:05:37 -04:00
Pedro Pena
39c7ca3b69 uncrustify fixes
Signed-off-by: Pedro Pena <peter.a.pena@gmail.com>
2020-07-06 17:05:37 -04:00
Pedro Pena
44efcf7744 fixed test results (uncrustify)
Signed-off-by: Pedro Pena <peter.a.pena@gmail.com>
2020-07-06 17:05:37 -04:00
Pedro Pena
7b1335dd1d scheduled timer mutex
Signed-off-by: Pedro Pena <peter.a.pena@gmail.com>
2020-07-06 17:05:37 -04:00
Michel Hidalgo
84ae5a1897 Fix rclcpp::NodeOptions::operator= (#1211)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-07-02 16:08:40 -03:00
Dirk Thomas
05e6b96847 link against thread library where necessary (#1210)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-07-01 13:22:33 -07:00
brawner
860a9e0e4d Unit tests for node interfaces (#1202)
* Unit tests for node interfaces

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

* Address PR Feedback

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

* Address PR feedback

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

* Adjusting comment

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-07-01 12:48:41 -07:00
Ivan Santiago Paunovic
f125c78fa8 Remove usage of domain id in node options (#1205)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-07-01 13:16:56 -03:00
Claire Wang
a8cd936239 remove deprecated set_on_parameters_set_callback function (#1199)
Signed-off-by: claireyywang <22240514+claireyywang@users.noreply.github.com>
2020-06-29 15:24:12 -07:00
Johannes Meyer
c92f3b7ff9 Fix conversion of negative durations to messages (#1188)
* 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>
2020-06-29 12:44:19 -03:00
Johannes Meyer
c0b96616bb Fix implementation of NodeOptions::use_global_arguments() (#1176)
`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>
2020-06-29 10:47:23 -03:00
Alejandro Hernández Cordero
55fccffc89 Bump to QD to level 3 and fixed links (#1158)
* Update quality level and links to doc

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

* Added feedback

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

* Fixed wording and links

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

* Bump QD to level 3 and fixed links

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

* Added missing dependency rcpputils to rclcpp_components

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

* Added missing dependency rmw to rclcpp_lifecycle

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

* Added feedback

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

* changed ci_linux_coverage to nightly_linux_coverage

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-06-29 08:43:34 +02:00
Dirk Thomas
873a3d5cd0 fix race in test_lifecycle_service_client (#1204)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-06-26 16:00:31 -07:00
Michel Hidalgo
a9d5a3feb9 Fix pub/sub count API tests. (#1203)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-06-26 20:00:14 -03:00
Martijn Buijs
c23572fa14 Include original exception in ComponentManagerException (#1157)
* 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>
2020-06-26 10:41:23 -05:00
Christophe Bedard
8245808c0e Update tracetools' QL to 2 in rclcpp's QD (#1187)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2020-06-25 15:52:19 +02:00
tomoya
35c27e8250 fix exception message on rcl_clock_init. (#1182)
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-06-23 13:42:35 -03:00
brawner
8a62104ea7 Throw exception if rcl_timer_init fails (#1179)
* Throw exception if rcl_timer_init fails

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

* Add bad-argument tests for GenericTimer

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

* Add comments

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

* Address feedback

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

* Address feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-22 14:25:51 -07:00
brawner
c63060c42d Unit tests for some header-only functions/classes (#1181)
* Unit tests for header-only functions/classes

Adds coverage for:
  * any_service_callback.hpp
  * any_subscription_callback.hpp
  * create_subscription.hpp
  * create_timer.hpp

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

* Address PR feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-22 13:37:54 -07:00
tomoya
2a7b722d5f callback should be perfectly-forwarded. (#1183)
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-06-22 15:25:59 -03:00
brawner
a6741a4f8e Add unit tests for logging functionality (#1184)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-19 13:22:06 -07:00
brawner
40f0040f0d Add create_publisher include to create_subscription (#1180)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-06-19 10:57:06 -07:00
53 changed files with 2085 additions and 697 deletions

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

@@ -1,8 +1,8 @@
This document is a declaration of software quality for the `rclcpp` package, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html).
# `rclcpp` Quality Declaration
# rclcpp Quality Declaration
The package `rclcpp` claims to be in the **Quality Level 4** category.
The package `rclcpp` claims to be in the **Quality Level 3** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -10,7 +10,7 @@ Below are the rationales, notes, and caveats for this claim, organized by each r
### Version Scheme [1.i]
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
### Version Stability [1.ii]
@@ -76,19 +76,19 @@ All pull requests must resolve related documentation changes before merging.
### Public API Documentation [3.ii]
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp/).
The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp/).
### License [3.iii]
The license for `rclcpp` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/copyright/).
## Testing [4]
@@ -121,6 +121,8 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
@@ -151,49 +153,49 @@ It also has several test dependencies, which do not affect the resulting quality
The `libstatistics_collector` package provides lightweight aggregation utilities to collect statistics and measure message metrics.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
#### `rcl`
`rcl` a library to support implementation of language specific ROS 2 Client Libraries.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
#### `rcl_yaml_param_parser`
The `rcl_yaml_param_parser` package provides an API that is used to parse YAML configuration files which may be used to configure ROS and specific nodes.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
#### `rcpputils`
The `rcpputils` package provides an API which contains common utilities and data structures useful when programming in C++.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
#### `rcutils`
The `rcutils` package provides an API which contains common utilities and data structures useful when programming in C.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
#### `rmw`
`rmw` is the ROS 2 middleware library.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
#### `statistics_msgs`
The `statistics_msgs` package contains ROS 2 message definitions for reporting statistics for topics and system resources.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
#### `tracetools`
The `tracetools` package provides utilities for instrumenting the code in `rclcpp` so that it may be traced for debugging and performance analysis.
It is **Quality Level 4**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
It is **Quality Level 2**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

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

View File

@@ -361,7 +361,8 @@ public:
SharedPromiseWithRequest promise = std::make_shared<PromiseWithRequest>();
SharedFutureWithRequest future_with_request(promise->get_future());
auto wrapping_cb = [future_with_request, promise, request, &cb](SharedFuture future) {
auto wrapping_cb = [future_with_request, promise, request,
cb = std::forward<CallbackWithRequestType>(cb)](SharedFuture future) {
auto response = future.get();
promise->set_value(std::make_pair(request, response));
cb(future_with_request);

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

@@ -72,7 +72,7 @@ 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;

View File

@@ -82,6 +82,7 @@ private:
RCLCPP_DISABLE_COPY(MultiThreadedExecutor)
std::mutex wait_mutex_;
std::mutex scheduled_timers_mutex_;
size_t number_of_threads_;
bool yield_before_execute_;
std::chrono::nanoseconds next_exec_timeout_;

View File

@@ -842,26 +842,6 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
/// Register a callback to be called anytime a parameter is about to be changed.
/**
* \deprecated Use add_on_set_parameters_callback instead.
* With this method, only one callback can be set at a time. The callback that was previously
* set by this method is returned or `nullptr` if no callback was previously set.
*
* The callbacks added with `add_on_set_parameters_callback` are stored in a different place.
* `remove_on_set_parameters_callback` can't be used with the callbacks registered with this
* method. For removing it, use `set_on_parameters_set_callback(nullptr)`.
*
* \param[in] callback The callback to be called when the value for a
* parameter is about to be set.
* \return The previous callback that was registered, if there was one,
* otherwise nullptr.
*/
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_PUBLIC
OnParametersSetCallbackType
set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback);
/// Get the fully-qualified names of all available nodes.
/**
* The fully-qualified name includes the local namespace and name of the node.

View File

@@ -167,11 +167,6 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_PUBLIC
OnParametersSetCallbackType
set_on_parameters_set_callback(OnParametersSetCallbackType callback) override;
RCLCPP_PUBLIC
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;

View File

@@ -191,17 +191,6 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
/// Register a callback for when parameters are being set, return an existing one.
/**
* \deprecated Use add_on_set_parameters_callback instead.
* \sa rclcpp::Node::set_on_parameters_set_callback
*/
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_PUBLIC
virtual
OnParametersSetCallbackType
set_on_parameters_set_callback(OnParametersSetCallbackType callback) = 0;
/// Return the initial parameter values used by the NodeParameters to override default values.
RCLCPP_PUBLIC
virtual

View File

@@ -327,11 +327,6 @@ public:
NodeOptions &
allocator(rcl_allocator_t allocator);
protected:
/// Retrieve the ROS_DOMAIN_ID environment variable and populate options.
size_t
get_domain_id_from_env() const;
private:
// This is mutable to allow for a const accessor which lazily creates the node options instance.
/// Underlying rcl_node_options structure.

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

@@ -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;
}
@@ -230,6 +228,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

@@ -83,19 +83,22 @@ MultiThreadedExecutor::run(size_t)
if (!get_next_executable(any_exec, next_exec_timeout_)) {
continue;
}
if (any_exec.timer) {
// Guard against multiple threads getting the same timer.
if (scheduled_timers_.count(any_exec.timer) != 0) {
// Make sure that any_exec's callback group is reset before
// the lock is released.
if (any_exec.callback_group) {
any_exec.callback_group->can_be_taken_from().store(true);
}
continue;
}
scheduled_timers_.insert(any_exec.timer);
}
}
if (any_exec.timer) {
std::lock_guard<std::mutex> wait_lock(scheduled_timers_mutex_);
// Guard against multiple threads getting the same timer.
if (scheduled_timers_.count(any_exec.timer) != 0) {
// Make sure that any_exec's callback group is reset before
// the lock is released.
if (any_exec.callback_group) {
any_exec.callback_group->can_be_taken_from().store(true);
}
continue;
}
scheduled_timers_.insert(any_exec.timer);
}
if (yield_before_execute_) {
std::this_thread::yield();
}
@@ -103,7 +106,7 @@ MultiThreadedExecutor::run(size_t)
execute_any_executable(any_exec);
if (any_exec.timer) {
std::lock_guard<std::mutex> wait_lock(wait_mutex_);
std::lock_guard<std::mutex> wait_lock(scheduled_timers_mutex_);
auto it = scheduled_timers_.find(any_exec.timer);
if (it != scheduled_timers_.end()) {
scheduled_timers_.erase(it);

View File

@@ -328,28 +328,6 @@ Node::remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * co
return node_parameters_->remove_on_set_parameters_callback(callback);
}
// suppress deprecated function warning
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rclcpp::Node::OnParametersSetCallbackType
Node::set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback)
{
return node_parameters_->set_on_parameters_set_callback(callback);
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::vector<std::string>
Node::get_node_names() const
{

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;
}
@@ -874,18 +874,6 @@ NodeParameters::add_on_set_parameters_callback(OnParametersSetCallbackType callb
return handle;
}
NodeParameters::OnParametersSetCallbackType
NodeParameters::set_on_parameters_set_callback(OnParametersSetCallbackType callback)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto existing_callback = on_parameters_set_callback_;
on_parameters_set_callback_ = callback;
return existing_callback;
}
const std::map<std::string, rclcpp::ParameterValue> &
NodeParameters::get_parameter_overrides() const
{

View File

@@ -79,6 +79,7 @@ NodeOptions::operator=(const NodeOptions & other)
this->allow_undeclared_parameters_ = other.allow_undeclared_parameters_;
this->automatically_declare_parameters_from_overrides_ =
other.automatically_declare_parameters_from_overrides_;
this->node_options_.reset();
}
return *this;
}
@@ -92,7 +93,6 @@ NodeOptions::get_rcl_node_options() const
*node_options_ = rcl_node_get_default_options();
node_options_->allocator = this->allocator_;
node_options_->use_global_arguments = this->use_global_arguments_;
node_options_->domain_id = this->get_domain_id_from_env();
node_options_->enable_rosout = this->enable_rosout_;
int c_argc = 0;
@@ -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 &
@@ -322,36 +322,4 @@ NodeOptions::allocator(rcl_allocator_t allocator)
return *this;
}
// TODO(wjwwood): reuse rcutils_get_env() to avoid code duplication.
// See also: https://github.com/ros2/rcl/issues/119
size_t
NodeOptions::get_domain_id_from_env() const
{
// Determine the domain id based on the options and the ROS_DOMAIN_ID env variable.
size_t domain_id = std::numeric_limits<size_t>::max();
char * ros_domain_id = nullptr;
const char * env_var = "ROS_DOMAIN_ID";
#ifndef _WIN32
ros_domain_id = getenv(env_var);
#else
size_t ros_domain_id_size;
_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);
if (number == (std::numeric_limits<uint32_t>::max)()) {
#ifdef _WIN32
// free the ros_domain_id before throwing, if getenv was used on Windows
free(ros_domain_id);
#endif
throw std::runtime_error("failed to interpret ROS_DOMAIN_ID as integral number");
}
domain_id = static_cast<size_t>(number);
#ifdef _WIN32
free(ros_domain_id);
#endif
}
return domain_id;
}
} // namespace rclcpp

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

@@ -61,15 +61,11 @@ TimerBase::TimerBase(
rcl_clock_t * clock_handle = clock_->get_clock_handle();
{
std::lock_guard<std::mutex> clock_guard(clock_->get_clock_mutex());
if (
rcl_timer_init(
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
rcl_get_default_allocator()) != RCL_RET_OK)
{
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't initialize rcl timer handle: %s\n", rcl_get_error_string().str);
rcl_reset_error();
rcl_ret_t ret = rcl_timer_init(
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
rcl_get_default_allocator());
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't initialize rcl timer handle");
}
}
}

View File

@@ -17,6 +17,20 @@ rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
SKIP_INSTALL
)
ament_add_gtest(test_any_service_callback rclcpp/test_any_service_callback.cpp)
if(TARGET test_any_service_callback)
ament_target_dependencies(test_any_service_callback
"test_msgs"
)
target_link_libraries(test_any_service_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_any_subscription_callback rclcpp/test_any_subscription_callback.cpp)
if(TARGET test_any_subscription_callback)
ament_target_dependencies(test_any_subscription_callback
"test_msgs"
)
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME})
endif()
ament_add_gtest(test_client rclcpp/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
@@ -39,6 +53,13 @@ if(TARGET test_create_timer)
target_link_libraries(test_create_timer ${PROJECT_NAME})
target_include_directories(test_create_timer PRIVATE rclcpp/)
endif()
ament_add_gtest(test_create_subscription rclcpp/test_create_subscription.cpp)
if(TARGET test_create_subscription)
target_link_libraries(test_create_subscription ${PROJECT_NAME})
ament_target_dependencies(test_create_subscription
"test_msgs"
)
endif()
ament_add_gtest(test_expand_topic_or_service_name rclcpp/test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
@@ -115,6 +136,52 @@ ament_add_gtest(test_node_interfaces__get_node_interfaces
if(TARGET test_node_interfaces__get_node_interfaces)
target_link_libraries(test_node_interfaces__get_node_interfaces ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_base
rclcpp/node_interfaces/test_node_base.cpp)
if(TARGET test_node_interfaces__node_base)
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_clock
rclcpp/node_interfaces/test_node_clock.cpp)
if(TARGET test_node_interfaces__node_clock)
target_link_libraries(test_node_interfaces__node_clock ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_graph
rclcpp/node_interfaces/test_node_graph.cpp)
if(TARGET test_node_interfaces__node_graph)
ament_target_dependencies(
test_node_interfaces__node_graph
"test_msgs")
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_parameters
rclcpp/node_interfaces/test_node_parameters.cpp)
if(TARGET test_node_interfaces__node_parameters)
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_services
rclcpp/node_interfaces/test_node_services.cpp)
if(TARGET test_node_interfaces__node_services)
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_timers
rclcpp/node_interfaces/test_node_timers.cpp)
if(TARGET test_node_interfaces__node_timers)
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_topics
rclcpp/node_interfaces/test_node_topics.cpp)
if(TARGET test_node_interfaces__node_topics)
ament_target_dependencies(
test_node_interfaces__node_topics
"test_msgs")
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__node_waitables
rclcpp/node_interfaces/test_node_waitables.cpp)
if(TARGET test_node_interfaces__node_waitables)
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME})
endif()
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
@@ -397,6 +464,12 @@ if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME})
endif()
ament_add_gtest(test_timer_count rclcpp/test_timer_call_count.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer_count)
target_link_libraries(test_timer_count ${PROJECT_NAME})
endif()
ament_add_gtest(test_wait_set rclcpp/test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)

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

@@ -0,0 +1,60 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rclcpp/rclcpp.hpp"
class TestNodeBase : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeBase, construct_from_node)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_base =
dynamic_cast<rclcpp::node_interfaces::NodeBase *>(node->get_node_base_interface().get());
ASSERT_NE(nullptr, node_base);
EXPECT_STREQ("node", node_base->get_name());
EXPECT_STREQ("/ns", node_base->get_namespace());
EXPECT_STREQ("/ns/node", node_base->get_fully_qualified_name());
EXPECT_NE(nullptr, node_base->get_context());
EXPECT_NE(nullptr, node_base->get_rcl_node_handle());
EXPECT_NE(nullptr, node_base->get_shared_rcl_node_handle());
const auto * const_node_base = node_base;
EXPECT_NE(nullptr, const_node_base->get_rcl_node_handle());
EXPECT_NE(nullptr, const_node_base->get_shared_rcl_node_handle());
}

View File

@@ -0,0 +1,49 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include "rclcpp/node_interfaces/node_clock.hpp"
#include "rclcpp/node.hpp"
class TestNodeClock : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeClock, construct_from_node)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_clock =
dynamic_cast<rclcpp::node_interfaces::NodeClock *>(node->get_node_clock_interface().get());
ASSERT_NE(nullptr, node_clock);
EXPECT_NE(nullptr, node_clock->get_clock());
const auto * const_node_clock = node_clock;
EXPECT_NE(nullptr, const_node_clock->get_clock());
}

View File

@@ -0,0 +1,186 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <utility>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rclcpp/node_interfaces/node_graph.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/msg/empty.hpp"
class TestNodeGraph : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeGraph, construct_from_node)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto topic_names_and_types = node_graph->get_topic_names_and_types(false);
EXPECT_LT(0u, topic_names_and_types.size());
auto service_names_and_types = node_graph->get_service_names_and_types();
EXPECT_LT(0u, service_names_and_types.size());
auto names = node_graph->get_node_names();
EXPECT_EQ(1u, names.size());
auto names_and_namespaces = node_graph->get_node_names_and_namespaces();
EXPECT_EQ(1u, names_and_namespaces.size());
EXPECT_EQ(0u, node_graph->count_publishers("not_a_topic"));
EXPECT_EQ(0u, node_graph->count_subscribers("not_a_topic"));
}
TEST_F(TestNodeGraph, get_topic_names_and_types)
{
auto node = std::make_shared<rclcpp::Node>("node2", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto topic_names_and_types = node_graph->get_topic_names_and_types();
EXPECT_LT(0u, topic_names_and_types.size());
}
TEST_F(TestNodeGraph, get_service_names_and_types)
{
auto node = std::make_shared<rclcpp::Node>("node2", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto service_names_and_types = node_graph->get_service_names_and_types();
EXPECT_LT(0u, service_names_and_types.size());
}
TEST_F(TestNodeGraph, get_service_names_and_types_by_node)
{
auto node1 = std::make_shared<rclcpp::Node>("node1", "ns");
auto node2 = std::make_shared<rclcpp::Node>("node2", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node1->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
EXPECT_THROW(
node_graph->get_service_names_and_types_by_node("not_a_node", "not_absolute_namespace"),
std::runtime_error);
auto service_names_and_types1 = node_graph->get_service_names_and_types_by_node("node1", "/ns");
auto service_names_and_types2 = node_graph->get_service_names_and_types_by_node("node2", "/ns");
EXPECT_EQ(service_names_and_types1.size(), service_names_and_types2.size());
}
TEST_F(TestNodeGraph, get_node_names_and_namespaces)
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto names_and_namespaces = node_graph->get_node_names_and_namespaces();
EXPECT_EQ(1u, names_and_namespaces.size());
}
TEST_F(TestNodeGraph, notify_shutdown)
{
auto node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
EXPECT_NO_THROW(node_graph->notify_shutdown());
}
TEST_F(TestNodeGraph, wait_for_graph_change)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
EXPECT_NO_THROW(node_graph->notify_graph_change());
EXPECT_THROW(
node_graph->wait_for_graph_change(nullptr, std::chrono::milliseconds(1)),
rclcpp::exceptions::InvalidEventError);
auto event = std::make_shared<rclcpp::Event>();
EXPECT_THROW(
node_graph->wait_for_graph_change(event, std::chrono::milliseconds(0)),
rclcpp::exceptions::EventNotRegisteredError);
}
TEST_F(TestNodeGraph, get_info_by_topic)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
const rclcpp::QoS publisher_qos(1);
auto publisher = node->create_publisher<test_msgs::msg::Empty>("topic", publisher_qos);
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
const rclcpp::QoS subscriber_qos(10);
auto subscription =
node->create_subscription<test_msgs::msg::Empty>(
"topic", subscriber_qos, std::move(callback));
const auto * node_graph =
dynamic_cast<rclcpp::node_interfaces::NodeGraph *>(node->get_node_graph_interface().get());
ASSERT_NE(nullptr, node_graph);
auto publishers = node_graph->get_publishers_info_by_topic("topic", false);
ASSERT_EQ(1u, publishers.size());
auto publisher_endpoint_info = publishers[0];
const auto const_publisher_endpoint_info = publisher_endpoint_info;
EXPECT_STREQ("node", publisher_endpoint_info.node_name().c_str());
EXPECT_STREQ("node", const_publisher_endpoint_info.node_name().c_str());
EXPECT_STREQ("/ns", publisher_endpoint_info.node_namespace().c_str());
EXPECT_STREQ("/ns", const_publisher_endpoint_info.node_namespace().c_str());
EXPECT_STREQ("test_msgs/msg/Empty", publisher_endpoint_info.topic_type().c_str());
EXPECT_STREQ("test_msgs/msg/Empty", const_publisher_endpoint_info.topic_type().c_str());
EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_endpoint_info.endpoint_type());
EXPECT_EQ(rclcpp::EndpointType::Publisher, const_publisher_endpoint_info.endpoint_type());
rclcpp::QoS actual_qos = publisher_endpoint_info.qos_profile();
EXPECT_EQ(0u, actual_qos.get_rmw_qos_profile().depth);
rclcpp::QoS const_actual_qos = const_publisher_endpoint_info.qos_profile();
EXPECT_EQ(0u, const_actual_qos.get_rmw_qos_profile().depth);
auto endpoint_gid = publisher_endpoint_info.endpoint_gid();
auto const_endpoint_gid = const_publisher_endpoint_info.endpoint_gid();
bool endpoint_gid_is_all_zeros = true;
for (size_t i = 0; i < RMW_GID_STORAGE_SIZE; ++i) {
endpoint_gid_is_all_zeros &= (endpoint_gid[i] == 0);
EXPECT_EQ(endpoint_gid[i], const_endpoint_gid[i]);
}
EXPECT_FALSE(endpoint_gid_is_all_zeros);
}

View File

@@ -0,0 +1,89 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* NodeParameters is a complicated interface with lots of code, but it is tested elsewhere
* very thoroughly. This currently just includes unittests for the currently uncovered
* functionality.
*/
#include <gtest/gtest.h>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_parameters.hpp"
class TestNodeParameters : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeParameters, list_parameters)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
std::vector<std::string> prefixes;
const auto list_result = node_parameters->list_parameters(prefixes, 1u);
// Currently the only default parameter is 'use_sim_time', but that may change.
size_t number_of_parameters = list_result.names.size();
EXPECT_GE(1u, number_of_parameters);
const std::string parameter_name = "new_parameter";
const rclcpp::ParameterValue value(true);
const rcl_interfaces::msg::ParameterDescriptor descriptor;
const auto added_parameter_value =
node_parameters->declare_parameter(parameter_name, value, descriptor, false);
EXPECT_EQ(value.get<bool>(), added_parameter_value.get<bool>());
auto list_result2 = node_parameters->list_parameters(prefixes, 1u);
EXPECT_EQ(number_of_parameters + 1u, list_result2.names.size());
EXPECT_NE(
std::find(list_result2.names.begin(), list_result2.names.end(), parameter_name),
list_result2.names.end());
}
TEST_F(TestNodeParameters, parameter_overrides)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(0u, parameter_overrides.size());
}

View File

@@ -0,0 +1,111 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_services.hpp"
#include "rclcpp/rclcpp.hpp"
class TestService : public rclcpp::ServiceBase
{
public:
explicit TestService(rclcpp::Node * node)
: rclcpp::ServiceBase(node->get_node_base_interface()->get_shared_rcl_node_handle()) {}
std::shared_ptr<void> create_request() override {return nullptr;}
std::shared_ptr<rmw_request_id_t> create_request_header() override {return nullptr;}
void handle_request(std::shared_ptr<rmw_request_id_t>, std::shared_ptr<void>) override {}
};
class TestClient : public rclcpp::ClientBase
{
public:
explicit TestClient(rclcpp::Node * node)
: rclcpp::ClientBase(node->get_node_base_interface().get(), node->get_node_graph_interface()) {}
std::shared_ptr<void> create_response() override {return nullptr;}
std::shared_ptr<rmw_request_id_t> create_request_header() override {return nullptr;}
void handle_response(
std::shared_ptr<rmw_request_id_t>, std::shared_ptr<void>) override {}
};
class TestNodeService : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeService, add_service)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_services =
dynamic_cast<rclcpp::node_interfaces::NodeServices *>(
node->get_node_services_interface().get());
ASSERT_NE(nullptr, node_services);
auto service = std::make_shared<TestService>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(
node_services->add_service(service, callback_group));
// Check that adding a service from node to a callback group of different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_services->add_service(service, callback_group_in_different_node),
std::runtime_error);
}
TEST_F(TestNodeService, add_client)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_services =
dynamic_cast<rclcpp::node_interfaces::NodeServices *>(
node->get_node_services_interface().get());
ASSERT_NE(nullptr, node_services);
auto client = std::make_shared<TestClient>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_services->add_client(client, callback_group));
// Check that adding a client from node to a callback group of different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_services->add_client(client, callback_group_in_different_node),
std::runtime_error);
}

View File

@@ -0,0 +1,71 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_timers.hpp"
#include "rclcpp/rclcpp.hpp"
class TestTimer : public rclcpp::TimerBase
{
public:
explicit TestTimer(rclcpp::Node * node)
: TimerBase(node->get_clock(), std::chrono::nanoseconds(1),
node->get_node_base_interface()->get_context()) {}
void execute_callback() override {}
bool is_steady() override {return false;}
};
class TestNodeTimers : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeTimers, add_timer)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto node_timers =
dynamic_cast<rclcpp::node_interfaces::NodeTimers *>(node->get_node_timers_interface().get());
ASSERT_NE(nullptr, node_timers);
auto timer = std::make_shared<TestTimer>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_timers->add_timer(timer, callback_group));
// Check that adding timer from node to callback group in different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_timers->add_timer(timer, callback_group_in_different_node),
std::runtime_error);
}

View File

@@ -0,0 +1,129 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <type_traits>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_topics.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/msg/empty.hpp"
namespace
{
const rosidl_message_type_support_t EmptyTypeSupport()
{
return *rosidl_typesupport_cpp::get_message_type_support_handle<test_msgs::msg::Empty>();
}
const rcl_publisher_options_t PublisherOptions()
{
return rclcpp::PublisherOptionsWithAllocator<std::allocator<void>>().template
to_rcl_publisher_options<test_msgs::msg::Empty>(rclcpp::QoS(10));
}
const rcl_subscription_options_t SubscriptionOptions()
{
return rclcpp::SubscriptionOptionsWithAllocator<std::allocator<void>>().template
to_rcl_subscription_options<test_msgs::msg::Empty>(rclcpp::QoS(10));
}
} // namespace
class TestPublisher : public rclcpp::PublisherBase
{
public:
explicit TestPublisher(rclcpp::Node * node)
: rclcpp::PublisherBase(
node->get_node_base_interface().get(), "topic", EmptyTypeSupport(), PublisherOptions()) {}
};
class TestSubscription : public rclcpp::SubscriptionBase
{
public:
explicit TestSubscription(rclcpp::Node * node)
: rclcpp::SubscriptionBase(
node->get_node_base_interface().get(), EmptyTypeSupport(), "topic", SubscriptionOptions()) {}
std::shared_ptr<void> create_message() override {return nullptr;}
std::shared_ptr<rclcpp::SerializedMessage>
create_serialized_message() override {return nullptr;}
void handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &) override {}
void handle_loaned_message(void *, const rclcpp::MessageInfo &) override {}
void return_message(std::shared_ptr<void> &) override {}
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> &) override {}
};
class TestNodeTopics : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeTopics, add_publisher)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
// This dynamic cast is not necessary for the unittest itself, but instead is used to ensure
// the proper type is being tested and covered.
auto * node_topics =
dynamic_cast<rclcpp::node_interfaces::NodeTopics *>(node->get_node_topics_interface().get());
ASSERT_NE(nullptr, node_topics);
auto publisher = std::make_shared<TestPublisher>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_topics->add_publisher(publisher, callback_group));
// Check that adding publisher from node to a callback group in different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_topics->add_publisher(publisher, callback_group_in_different_node),
std::runtime_error);
}
TEST_F(TestNodeTopics, add_subscription)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_topics =
dynamic_cast<rclcpp::node_interfaces::NodeTopics *>(node->get_node_topics_interface().get());
ASSERT_NE(nullptr, node_topics);
auto subscription = std::make_shared<TestSubscription>(node.get());
auto callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_NO_THROW(node_topics->add_subscription(subscription, callback_group));
// Check that adding subscription from node to callback group in different_node throws exception.
std::shared_ptr<rclcpp::Node> different_node = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group_in_different_node =
different_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
EXPECT_THROW(
node_topics->add_subscription(subscription, callback_group_in_different_node),
std::runtime_error);
}

View File

@@ -0,0 +1,68 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "rcl/node_options.h"
#include "rclcpp/node.hpp"
#include "rclcpp/node_interfaces/node_waitables.hpp"
#include "rclcpp/rclcpp.hpp"
class TestWaitable : public rclcpp::Waitable
{
public:
bool add_to_wait_set(rcl_wait_set_t *) override {return false;}
bool is_ready(rcl_wait_set_t *) override {return false;}
void execute() override {}
};
class TestNodeWaitables : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeWaitables, add_remove_waitable)
{
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node", "ns");
auto * node_waitables =
dynamic_cast<rclcpp::node_interfaces::NodeWaitables *>(
node->get_node_waitables_interface().get());
ASSERT_NE(nullptr, node_waitables);
std::shared_ptr<rclcpp::Node> node2 = std::make_shared<rclcpp::Node>("node2", "ns");
auto callback_group1 = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
auto callback_group2 = node2->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
auto waitable = std::make_shared<TestWaitable>();
EXPECT_NO_THROW(
node_waitables->add_waitable(waitable, callback_group1));
EXPECT_THROW(
node_waitables->add_waitable(waitable, callback_group2),
std::runtime_error);
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group1));
EXPECT_NO_THROW(node_waitables->remove_waitable(waitable, callback_group2));
}

View File

@@ -0,0 +1,78 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file includes basic API tests for the AnyServiceCallback class.
// It is also tested in test_externally_defined_services.cpp
#include <gtest/gtest.h>
#include <functional>
#include <memory>
#include <utility>
#include "rclcpp/any_service_callback.hpp"
#include "test_msgs/srv/empty.hpp"
#include "test_msgs/srv/empty.h"
class TestAnyServiceCallback : public ::testing::Test
{
public:
void SetUp()
{
request_header_ = std::make_shared<rmw_request_id_t>();
request_ = std::make_shared<test_msgs::srv::Empty::Request>();
response_ = std::make_shared<test_msgs::srv::Empty::Response>();
}
protected:
rclcpp::AnyServiceCallback<test_msgs::srv::Empty> any_service_callback_;
std::shared_ptr<rmw_request_id_t> request_header_;
std::shared_ptr<test_msgs::srv::Empty::Request> request_;
std::shared_ptr<test_msgs::srv::Empty::Response> response_;
};
TEST_F(TestAnyServiceCallback, no_set_and_dispatch_throw) {
EXPECT_THROW(
any_service_callback_.dispatch(request_header_, request_, response_),
std::runtime_error);
}
TEST_F(TestAnyServiceCallback, set_and_dispatch_no_header) {
int callback_calls = 0;
auto callback = [&callback_calls](const std::shared_ptr<test_msgs::srv::Empty::Request>,
std::shared_ptr<test_msgs::srv::Empty::Response>) {
callback_calls++;
};
any_service_callback_.set(callback);
EXPECT_NO_THROW(
any_service_callback_.dispatch(request_header_, request_, response_));
EXPECT_EQ(callback_calls, 1);
}
TEST_F(TestAnyServiceCallback, set_and_dispatch_header) {
int callback_with_header_calls = 0;
auto callback_with_header =
[&callback_with_header_calls](const std::shared_ptr<rmw_request_id_t>,
const std::shared_ptr<test_msgs::srv::Empty::Request>,
std::shared_ptr<test_msgs::srv::Empty::Response>) {
callback_with_header_calls++;
};
any_service_callback_.set(callback_with_header);
EXPECT_NO_THROW(
any_service_callback_.dispatch(request_header_, request_, response_));
EXPECT_EQ(callback_with_header_calls, 1);
}

View File

@@ -0,0 +1,205 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <functional>
#include <memory>
#include <utility>
#include "rclcpp/any_subscription_callback.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
class TestAnySubscriptionCallback : public ::testing::Test
{
public:
TestAnySubscriptionCallback()
: any_subscription_callback_(allocator_) {}
void SetUp()
{
msg_shared_ptr_ = std::make_shared<test_msgs::msg::Empty>();
msg_const_shared_ptr_ = std::make_shared<const test_msgs::msg::Empty>();
msg_unique_ptr_ = std::make_unique<test_msgs::msg::Empty>();
}
protected:
std::shared_ptr<std::allocator<void>> allocator_;
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty, std::allocator<void>>
any_subscription_callback_;
std::shared_ptr<test_msgs::msg::Empty> msg_shared_ptr_;
std::shared_ptr<const test_msgs::msg::Empty> msg_const_shared_ptr_;
std::unique_ptr<test_msgs::msg::Empty> msg_unique_ptr_;
rclcpp::MessageInfo message_info_;
};
TEST_F(TestAnySubscriptionCallback, construct_destruct) {
}
TEST_F(TestAnySubscriptionCallback, unset_dispatch_throw) {
EXPECT_THROW(
any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_),
std::runtime_error);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_shared_ptr) {
int callback_count = 0;
auto shared_ptr_callback = [&callback_count](
const std::shared_ptr<test_msgs::msg::Empty>) {
callback_count++;
};
any_subscription_callback_.set(shared_ptr_callback);
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
// Can't convert ConstSharedPtr to SharedPtr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Promotes Unique into SharedPtr
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_shared_ptr_w_info) {
int callback_count = 0;
auto shared_ptr_w_info_callback = [&callback_count](
const std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {
callback_count++;
};
any_subscription_callback_.set(shared_ptr_w_info_callback);
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
// Can't convert ConstSharedPtr to SharedPtr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Promotes Unique into SharedPtr
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_const_shared_ptr) {
int callback_count = 0;
auto const_shared_ptr_callback = [&callback_count](
std::shared_ptr<const test_msgs::msg::Empty>) {
callback_count++;
};
any_subscription_callback_.set(const_shared_ptr_callback);
// Ok to promote shared_ptr to ConstSharedPtr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 2);
// Not allowed to convert unique_ptr to const shared_ptr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_const_shared_ptr_w_info) {
int callback_count = 0;
auto const_shared_ptr_callback = [&callback_count](
std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {
callback_count++;
};
any_subscription_callback_.set(
std::move(const_shared_ptr_callback));
// Ok to promote shared_ptr to ConstSharedPtr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 2);
// Not allowed to convert unique_ptr to const shared_ptr
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_unique_ptr) {
int callback_count = 0;
auto unique_ptr_callback = [&callback_count](
std::unique_ptr<test_msgs::msg::Empty>) {
callback_count++;
};
any_subscription_callback_.set(unique_ptr_callback);
// Message is copied into unique_ptr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Unique_ptr is_moved
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}
TEST_F(TestAnySubscriptionCallback, set_dispatch_unique_ptr_w_info) {
int callback_count = 0;
auto unique_ptr_callback = [&callback_count](
std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {
callback_count++;
};
any_subscription_callback_.set(unique_ptr_callback);
// Message is copied into unique_ptr
EXPECT_NO_THROW(any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_));
EXPECT_EQ(callback_count, 1);
EXPECT_THROW(
any_subscription_callback_.dispatch_intra_process(msg_const_shared_ptr_, message_info_),
std::runtime_error);
EXPECT_EQ(callback_count, 1);
// Unique_ptr is_moved
EXPECT_NO_THROW(
any_subscription_callback_.dispatch_intra_process(std::move(msg_unique_ptr_), message_info_));
EXPECT_EQ(callback_count, 2);
}

View File

@@ -0,0 +1,67 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/node.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/msg/empty.h"
using namespace std::chrono_literals;
class TestCreateSubscription : public ::testing::Test
{
public:
void SetUp() override
{
rclcpp::init(0, nullptr);
}
void TearDown() override
{
rclcpp::shutdown();
}
};
TEST_F(TestCreateSubscription, create) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);
auto options = rclcpp::SubscriptionOptions();
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
auto subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(node, "topic_name", qos, callback, options);
ASSERT_NE(nullptr, subscription);
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}
TEST_F(TestCreateSubscription, create_with_statistics) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
const rclcpp::QoS qos(10);
auto options = rclcpp::SubscriptionOptions();
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
options.topic_stats_options.publish_topic = "topic_statistics";
options.topic_stats_options.publish_period = 5min;
auto callback = [](const test_msgs::msg::Empty::SharedPtr) {};
auto subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(node, "topic_name", qos, callback, options);
ASSERT_NE(nullptr, subscription);
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
}

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);
@@ -67,7 +63,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 +82,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 +103,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 +126,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 +134,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

@@ -14,10 +14,12 @@
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node.hpp"
TEST(TestLogger, factory_functions) {
rclcpp::Logger logger = rclcpp::get_logger("test_logger");
@@ -33,3 +35,15 @@ TEST(TestLogger, hierarchy) {
rclcpp::Logger subsublogger = sublogger.get_child("grandchild");
EXPECT_STREQ("test_logger.child.grandchild", subsublogger.get_name());
}
TEST(TestLogger, get_node_logger) {
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
auto node_base = rclcpp::node_interfaces::get_node_base_interface(node);
auto logger = rclcpp::get_node_logger(node_base->get_rcl_node_handle());
EXPECT_STREQ(logger.get_name(), "ns.my_node");
logger = rclcpp::get_node_logger(nullptr);
EXPECT_STREQ(logger.get_name(), "rclcpp");
rclcpp::shutdown();
}

View File

@@ -2329,206 +2329,6 @@ TEST_F(TestNode, get_parameter_types_undeclared_parameters_allowed) {
}
}
// suppress deprecated function test warnings
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
// test that it is possible to call get_parameter within the set_callback
TEST_F(TestNode, set_on_parameters_set_callback_get_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_get_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
double floatout;
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node, &floatout](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
rclcpp::Parameter floatparam = node->get_parameter("floatparam");
if (floatparam.get_value<double>() != 5.4) {
result.successful = false;
}
floatout = floatparam.get_value<double>();
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
ASSERT_NO_THROW(node->set_parameter({"intparam", 40}));
ASSERT_EQ(floatout, 5.4);
}
// test that calling set_parameter inside of a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_set_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_set_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
// This should throw an exception
node->set_parameter({"floatparam", 5.6});
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// test that calling declare_parameter inside of a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_declare_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_declare_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
// This should throw an exception
node->declare_parameter("floatparam2", 5.6);
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// test that calling undeclare_parameter inside a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_undeclare_parameter) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_undeclare_parameter_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
// This should throw an exception
node->undeclare_parameter("floatparam");
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// test that calling set_on_parameters_set_callback from a set_callback throws an exception
TEST_F(TestNode, set_on_parameters_set_callback_set_on_parameters_set_callback) {
auto node = std::make_shared<rclcpp::Node>("test_set_callback_set_callback_node"_unq);
int64_t intval = node->declare_parameter("intparam", 42);
EXPECT_EQ(intval, 42);
double floatval = node->declare_parameter("floatparam", 5.4);
EXPECT_EQ(floatval, 5.4);
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
auto on_set_parameters =
[&node](const std::vector<rclcpp::Parameter> & parameters) {
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (parameters.size() != 1) {
result.successful = false;
}
if (parameters[0].get_value<int>() != 40) {
result.successful = false;
}
auto bad_parameters =
[](const std::vector<rclcpp::Parameter> & parameters) {
(void)parameters;
rcl_interfaces::msg::SetParametersResult result;
return result;
};
// This should throw an exception
node->set_on_parameters_set_callback(bad_parameters);
return result;
};
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
EXPECT_THROW(
{
node->set_parameter(rclcpp::Parameter("intparam", 40));
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
void expect_qos_profile_eq(
const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2, bool is_publisher)
{

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();
@@ -136,3 +168,33 @@ TEST(TestNodeOptions, enable_rosout) {
EXPECT_TRUE(options.get_rcl_node_options()->enable_rosout);
}
}
TEST(TestNodeOptions, copy) {
std::vector<std::string> expected_args{"--unknown-flag", "arg"};
auto options = rclcpp::NodeOptions().arguments(expected_args).use_global_arguments(false);
const rcl_node_options_t * rcl_options = options.get_rcl_node_options();
{
rclcpp::NodeOptions copied_options = options;
EXPECT_FALSE(copied_options.use_global_arguments());
EXPECT_EQ(expected_args, copied_options.arguments());
const rcl_node_options_t * copied_rcl_options = copied_options.get_rcl_node_options();
EXPECT_EQ(copied_rcl_options->use_global_arguments, rcl_options->use_global_arguments);
EXPECT_EQ(
rcl_arguments_get_count_unparsed(&copied_rcl_options->arguments),
rcl_arguments_get_count_unparsed(&rcl_options->arguments));
}
{
auto other_options = rclcpp::NodeOptions().use_global_arguments(true);
(void)other_options.get_rcl_node_options(); // force C structure initialization
other_options = options;
EXPECT_FALSE(other_options.use_global_arguments());
EXPECT_EQ(expected_args, other_options.arguments());
const rcl_node_options_t * other_rcl_options = other_options.get_rcl_node_options();
EXPECT_EQ(other_rcl_options->use_global_arguments, rcl_options->use_global_arguments);
EXPECT_EQ(
rcl_arguments_get_count_unparsed(&other_rcl_options->arguments),
rcl_arguments_get_count_unparsed(&rcl_options->arguments));
}
}

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

@@ -18,6 +18,7 @@
#include <chrono>
#include <exception>
#include <memory>
#include <utility>
#include "rcl/timer.h"
@@ -151,3 +152,42 @@ TEST_F(TestTimer, test_run_cancel_timer)
EXPECT_TRUE(has_timer_run.load());
EXPECT_TRUE(timer->is_canceled());
}
TEST_F(TestTimer, test_bad_arguments) {
auto node_base = rclcpp::node_interfaces::get_node_base_interface(test_node);
auto context = node_base->get_context();
auto steady_clock = std::make_shared<rclcpp::Clock>(RCL_STEADY_TIME);
// Negative period
EXPECT_THROW(
rclcpp::GenericTimer<void (*)()>(steady_clock, -1ms, []() {}, context),
rclcpp::exceptions::RCLInvalidArgument);
// Very negative period
constexpr auto nanoseconds_min = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::GenericTimer<void (*)()>(
steady_clock, nanoseconds_min, []() {}, context),
rclcpp::exceptions::RCLInvalidArgument);
// nanoseconds max, should be ok
constexpr auto nanoseconds_max = std::chrono::nanoseconds::max();
EXPECT_NO_THROW(
rclcpp::GenericTimer<void (*)()>(
steady_clock, nanoseconds_max, []() {}, context));
// 0 duration period, should be ok
EXPECT_NO_THROW(
rclcpp::GenericTimer<void (*)()>(steady_clock, 0ms, []() {}, context));
// context is null, which resorts to default
EXPECT_NO_THROW(
rclcpp::GenericTimer<void (*)()>(steady_clock, 1ms, []() {}, nullptr));
// Clock is unitialized
auto unitialized_clock = std::make_shared<rclcpp::Clock>(RCL_CLOCK_UNINITIALIZED);
EXPECT_THROW(
rclcpp::GenericTimer<void (*)()>(unitialized_clock, 1us, []() {}, context),
rclcpp::exceptions::RCLError);
}

View File

@@ -0,0 +1,116 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <string>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/executor.hpp"
using namespace std::chrono_literals;
class TestTimerCount : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
};
constexpr int EXECUTION_COUNT = 5;
constexpr rcl_duration_value_t TIME_ELAPSED = 12;
/*
Test timer wait mutex with multithreaded executor.
After 5 call
*/
TEST_F(TestTimerCount, timer_call_count_multi_threaded) {
rclcpp::executors::MultiThreadedExecutor executor;
std::shared_ptr<rclcpp::Node> node =
std::make_shared<rclcpp::Node>("timer_call_count_multi_threaded");
auto cbg = node->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
rclcpp::Clock system_clock(RCL_STEADY_TIME);
std::mutex last_mutex;
rclcpp::Time initial = system_clock.now();
std::atomic_int timer_count {0};
auto timer_callback = [&timer_count, &executor, &system_clock, &last_mutex, &initial]() {
rclcpp::Time now = system_clock.now();
timer_count++;
{
std::lock_guard<std::mutex> lock(last_mutex);
rcl_duration_value_t diff = (now - initial).nanoseconds() / (rcl_duration_value_t)1.0e9;
if (diff > TIME_ELAPSED) {
executor.cancel();
ASSERT_GT(timer_count, EXECUTION_COUNT);
}
}
};
auto timer_ = node->create_wall_timer(
2s, timer_callback, cbg);
executor.add_node(node);
executor.spin();
}
/*
Test timer wait mutex with singlethreaded executor
*/
TEST_F(TestTimerCount, timer_call_count_single_threaded) {
rclcpp::executors::SingleThreadedExecutor executor;
std::shared_ptr<rclcpp::Node> node =
std::make_shared<rclcpp::Node>("timer_call_count_single_threaded");
rclcpp::Clock system_clock(RCL_STEADY_TIME);
std::mutex last_mutex;
rclcpp::Time initial = system_clock.now();
std::atomic_int timer_count {0};
auto timer_callback = [&timer_count, &executor, &system_clock, &last_mutex, &initial]() {
rclcpp::Time now = system_clock.now();
timer_count++;
{
std::lock_guard<std::mutex> lock(last_mutex);
rcl_duration_value_t diff = (now - initial).nanoseconds() / (rcl_duration_value_t)1.0e9;
if (diff > TIME_ELAPSED) {
executor.cancel();
ASSERT_GT(timer_count, EXECUTION_COUNT);
}
}
};
auto timer_ = node->create_wall_timer(
2s, timer_callback);
executor.add_node(node);
executor.spin();
}

View File

@@ -1,8 +1,8 @@
This document is a declaration of software quality for the `rclcpp_action` package, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html).
# `rclcpp_action` Quality Declaration
# rclcpp_action Quality Declaration
The package `rclcpp_action` claims to be in the **Quality Level 4** category.
The package `rclcpp_action` claims to be in the **Quality Level 3** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -10,7 +10,7 @@ Below are the rationales, notes, and caveats for this claim, organized by each r
### Version Scheme [1.i]
`rclcpp_action` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
`rclcpp_action` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
### Version Stability [1.ii]
@@ -74,19 +74,19 @@ All pull requests must resolve related documentation changes before merging.
### Public API Documentation [3.ii]
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_action/).
The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_action/).
### License [3.iii]
The license for `rclcpp_action` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_action__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_action/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_action/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp_action`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_action__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_action/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_action/copyright/).
## Testing [4]
@@ -119,6 +119,8 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_action_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
@@ -149,19 +151,19 @@ It also has several test dependencies, which do not affect the resulting quality
`action_msgs` provides messages and services for ROS 2 actions.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/action_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/action_msgs/QUALITY_DECLARATION.md).
#### `rclcpp`
The `rclcpp` package provides the ROS client library in C++.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
#### `rcl_action`
The `rcl_action` package provides C-based ROS action implementation.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl_action/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl_action/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

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

View File

@@ -1,8 +1,8 @@
This document is a declaration of software quality for the `rclcpp_components` package, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html).
# `rclcpp_components` Quality Declaration
# rclcpp_components Quality Declaration
The package `rclcpp_components` claims to be in the **Quality Level 4** category.
The package `rclcpp_components` claims to be in the **Quality Level 3** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -10,7 +10,7 @@ Below are the rationales, notes, and caveats for this claim, organized by each r
### Version Scheme [1.i]
`rclcpp_components` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
`rclcpp_components` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
### Version Stability [1.ii]
@@ -70,25 +70,23 @@ All pull requests must resolve related documentation changes before merging.
### Feature Documentation [3.i]
`rclcpp_components` does not have a documented feature list.
`rclcpp_components` has a [feature list](http://docs.ros2.org/latest/api/rclcpp_components/) and each item in the list links to the corresponding feature documentation. There is documentation for all of the features, and new features require documentation before being added.
### Public API Documentation [3.ii]
`rclcpp_components` does not cover a public API documentation.
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_components/).
The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_components/).
### License [3.iii]
The license for `rclcpp_components` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_components__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_components/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_components/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp_components`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_components__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_components/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_components/copyright).
## Testing [4]
@@ -121,6 +119,8 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_components_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
@@ -151,25 +151,31 @@ It also has several test dependencies, which do not affect the resulting quality
The `ament_index_cpp` package provides a C++ API to access the ament resource index.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ament/ament_index/blob/master/ament_index_cpp/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ament/ament_index/blob/master/ament_index_cpp/QUALITY_DECLARATION.md).
#### `class_loader`
The `class_loader` package provides a ROS-independent package for loading plugins during runtime
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros/class_loader/blob/ros2/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros/class_loader/blob/ros2/QUALITY_DECLARATION.md).
#### `composition_interfaces`
The `composition_interfaces` package contains message and service definitions for managing composable nodes in a container process.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/composition_interfaces/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/composition_interfaces/QUALITY_DECLARATION.md).
#### `rclcpp`
The `rclcpp` package provides the ROS client library in C++.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
#### `rcpputils`
The `rcpputils` package provides an API which contains common utilities and data structures useful when programming in C++.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

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

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

@@ -1,8 +1,8 @@
This document is a declaration of software quality for the `rclcpp_lifecycle` package, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html).
# `rclcpp_lifecycle` Quality Declaration
# rclcpp_lifecycle Quality Declaration
The package `rclcpp_lifecycle` claims to be in the **Quality Level 4** category.
The package `rclcpp_lifecycle` claims to be in the **Quality Level 3** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
@@ -10,7 +10,7 @@ Below are the rationales, notes, and caveats for this claim, organized by each r
### Version Scheme [1.i]
`rclcpp_lifecycle` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
`rclcpp_lifecycle` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
### Version Stability [1.ii]
@@ -70,23 +70,23 @@ All pull requests must resolve related documentation changes before merging.
### Feature Documentation [3.i]
`rclcpp_lifecycle` does not have a documented feature list.
`rclcpp_lifecycle` has a [feature list](http://docs.ros2.org/latest/api/rclcpp_lifecycle/index.html) and each item in the list links to the corresponding feature documentation. There is documentation for all of the features, and new features require documentation before being added.
### Public API Documentation [3.ii]
`rclcpp_lifecycle` does not cover a public API documentation.
The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_lyfecycle/).
### License [3.iii]
The license for `rclcpp_lifecycle` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_lifecycle__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_lifecycle/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_lifecycle/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp_lifecycle`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_lifecycle__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_lifecycle/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp_lifecycle/copyright/).
## Testing [4]
@@ -119,6 +119,8 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_lifecycle_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
@@ -149,25 +151,31 @@ It also has several test dependencies, which do not affect the resulting quality
The `lifecycle_msgs` package contains message and service definitions for managing lifecycle nodes.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/lifecycle_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/lifecycle_msgs/QUALITY_DECLARATION.md).
#### `rclcpp`
The `rclcpp` package provides the ROS client library in C++.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rclcpp/blob/master/rclcpp/QUALITY_DECLARATION.md).
#### `rcl_lifecycle`
The `rcl_lifecycle` package provides functionality for ROS 2 lifecycle nodes in C.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl_lifecycle/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl_lifecycle/QUALITY_DECLARATION.md).
#### `rosidl_typesupport_cpp`
The `rosidl_typesupport_cpp` package generates the type support for C++ messages.
It is **Quality Level 4**, see its [Quality Declaration document](https://github.com/ros2/rosidl_typesupport/blob/master/rosidl_typesupport_cpp/QUALITY_DECLARATION.md).
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rosidl_typesupport/blob/master/rosidl_typesupport_cpp/QUALITY_DECLARATION.md).
#### `rmw`
`rmw` is the ROS 2 middleware library.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

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

View File

@@ -469,17 +469,6 @@ public:
remove_on_set_parameters_callback(
const rclcpp_lifecycle::LifecycleNode::OnSetParametersCallbackHandle * const handler);
/// Register a callback to be called anytime a parameter is about to be changed.
/**
* \deprecated Use add_on_set_parameters_callback instead.
* \sa rclcpp::Node::set_on_parameters_set_callback
*/
[[deprecated("use add_on_set_parameters_callback(OnParametersSetCallbackType callback) instead")]]
RCLCPP_LIFECYCLE_PUBLIC
rclcpp_lifecycle::LifecycleNode::OnParametersSetCallbackType
set_on_parameters_set_callback(
rclcpp_lifecycle::LifecycleNode::OnParametersSetCallbackType callback);
/// Return a vector of existing node names (string).
/**
* \sa rclcpp::Node::get_node_names

View File

@@ -268,28 +268,6 @@ LifecycleNode::remove_on_set_parameters_callback(
node_parameters_->remove_on_set_parameters_callback(callback);
}
// suppress deprecated function warning
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rclcpp::Node::OnParametersSetCallbackType
LifecycleNode::set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback)
{
return node_parameters_->set_on_parameters_set_callback(callback);
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::vector<std::string>
LifecycleNode::get_node_names() const
{

View File

@@ -20,6 +20,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
@@ -217,21 +218,31 @@ private:
void TearDown() override
{
rclcpp::shutdown();
{
std::lock_guard<std::mutex> guard(shutdown_mutex_);
rclcpp::shutdown();
}
spinner_.join();
}
void spin()
{
while (rclcpp::ok()) {
rclcpp::spin_some(lifecycle_node_->get_node_base_interface());
rclcpp::spin_some(lifecycle_client_);
while (true) {
{
std::lock_guard<std::mutex> guard(shutdown_mutex_);
if (!rclcpp::ok()) {
break;
}
rclcpp::spin_some(lifecycle_node_->get_node_base_interface());
rclcpp::spin_some(lifecycle_client_);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
std::shared_ptr<EmptyLifecycleNode> lifecycle_node_;
std::shared_ptr<LifecycleServiceClient> lifecycle_client_;
std::mutex shutdown_mutex_;
std::thread spinner_;
};