-
Notifications
You must be signed in to change notification settings - Fork 483
Increase coverage rclcpp_action to 95% #1290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
9b832d0 to
3bb2a25
Compare
| * \tparam ReturnT Return value type. | ||
| * \tparam ArgTx Argument types. | ||
| */ | ||
| template<size_t ID, typename ReturnT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is unchanged, except this overload was added to accommodate 7 arguments.
| TEST_F(TestClient, wait_for_action_server) | ||
| { | ||
| auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name); | ||
| EXPECT_FALSE(action_client->wait_for_action_server(0ms)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These checks were flaky on my machine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really? The server's not up yet, how could it return true? Perhaps an issue with the ROS graph?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It must have been a weird issue. Also it turns out these two checks were responsible for about 20 lines of coverage. I added them back in.
3bb2a25 to
1476715
Compare
Blast545
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, left some minor questions
| { | ||
| auto mock = mocking_utils::patch_and_return( | ||
| "lib:rclcpp_action", rcl_action_client_fini, RCL_RET_ERROR); | ||
| // It just logs an error message and continues |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it there any way to check this error logged msg? maybe checking with rcl_error_is_set() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also seems a bit curious to me if rcl_action_client_fini is called when using rclcpp_action::create_client, does it create an auxiliar internal or something like that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rcl_action_client_fini won't be called during create_client. Instead, the smart pointer is reset in this line so the action client's destructor will be called. The smart pointer to the rcl_action_server_t is created with a custom deleter, which just calls RCLCPP_ERROR (
rclcpp/rclcpp_action/src/client.cpp
Lines 54 to 57 in 01d6f52
| RCLCPP_ERROR( | |
| rclcpp::get_logger(rcl_node_get_logger_name(handle.get())).get_child("rclcpp_action"), | |
| "Error in destruction of rcl action client handle: %s", rcl_get_error_string().str); | |
| rcl_reset_error(); |
| @@ -0,0 +1,159 @@ | |||
| // Copyright 2018 Open Source Robotics Foundation, Inc. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Copyright 2018 Open Source Robotics Foundation, Inc. | |
| // Copyright 2020 Open Source Robotics Foundation, Inc. |
| { | ||
| auto mock_get_status = mocking_utils::patch_and_return( | ||
| "lib:rclcpp_action", rcl_action_goal_handle_get_status, RCL_RET_ERROR); | ||
| EXPECT_FALSE(handle_->cancel()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do this sets some error at some point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, the test case implies that it fails silently, which I don't think might be desirable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The coverage this test is trying to add is to the protected try_canceling method in ServerGoalHandleBase, which is a noexcept method, and just returns true or false whether cancel succeeded or failed. I exposed it publicly in FibonacciServerGoalHandle with cancel(), which does imply something slightly different with its name.
I changed cancel() to be named try_cancel() to give a better indication to its use.
hidmic
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good! Perhaps some comments next to each test case would help clarify what it is that they are testing.
| { | ||
| { | ||
| auto mock = mocking_utils::patch_and_return( | ||
| "lib:rclcpp_action", rcl_action_client_fini, RCL_RET_ERROR); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner consider using mocking_utils::inject_on_return() instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea!
rclcpp_action/test/test_client.cpp
Outdated
| std::launch::async, [&action_client]() { | ||
| return action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT); | ||
| }); | ||
| EXPECT_TRUE(future.get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner how isn't this is equivalent to calling wait_for_action_server() directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was copied from wait_for_action_server. You might have to ask the author of #1153 about that one :P. I removed the async bit and also from wait_for_action_server.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to think hard to remember why I did what I did 😅
The difference is that in #1153 the action server is brought up while the action client is waiting for it, which ensures (well, attempts to ensure) wait_for_action_server() won't return immediately here. In this case, the action server is already up and thus the separate thread is not necessary. Does that make sense?
rclcpp_action/test/test_client.cpp
Outdated
| auto send_goal_ops = rclcpp_action::Client<ActionType>::SendGoalOptions(); | ||
| send_goal_ops.result_callback = | ||
| []( | ||
| const typename ActionGoalHandle::WrappedResult &) mutable {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner out of curiosity, why mutable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed, removed.
rclcpp_action/test/test_client.cpp
Outdated
| auto send_goal_ops = rclcpp_action::Client<ActionType>::SendGoalOptions(); | ||
| send_goal_ops.result_callback = | ||
| []( | ||
| const typename ActionGoalHandle::WrappedResult &) mutable {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner same question.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
rclcpp_action/test/test_client.cpp
Outdated
| auto goal_handle = future_goal_handle.get(); | ||
| EXPECT_THROW( | ||
| { | ||
| auto future_result = action_client->async_get_result(goal_handle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner should this be outside the expectation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it can be. Moved
rclcpp_action/test/test_server.cpp
Outdated
| using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>; | ||
| if (nullptr != node_) { | ||
| node_.reset(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner nit: if SetupActionServerAndSpin returned all relevant state instead of persisting it, preventive resets would not be necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking a fresh look at this today, I chopped up TestBasicServer into two derived test fixtures so node, uuid, and action_server are now created during SetUp(). I also separated each patch call into its own test to prevent test crossover.
| std::function<void( | ||
| std::shared_ptr<test_msgs::action::Fibonacci::Impl::FeedbackMessage>)> publish_feedback) | ||
| : rclcpp_action::ServerGoalHandle<test_msgs::action::Fibonacci>( | ||
| rcl_handle, uuid, goal, on_terminal_state, on_executing, publish_feedback) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I did learn something today, it appears that's not strictly usable because ServerGoalHandle's constructor is protected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argh, almost :)
d916bff to
306a1c7
Compare
306a1c7 to
b252517
Compare
|
Retesting after rebasing onto #1311 |
rclcpp_action/test/test_server.cpp
Outdated
| std::chrono::milliseconds timeout = std::chrono::milliseconds(-1)) override | ||
| { | ||
| send_goal_request(node_, uuid_, timeout); | ||
| goal_handle_->execute(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brawner Hi, I found that this throws an exception while writing my test case based on your test.
If you call SendClientRequest without EXPECT_THROW, you get
C++ exception with description "goal_handle attempted invalid transition from state EXECUTING with event EXECUTE, at /opt/ros/src/ros2/rcl/rcl_action/src/rcl_action/goal_handle.c:95" thrown in the test body.
Without this line, some tests got failed.
[1.870s] 2: [ FAILED ] TestGoalRequestServer.publish_result_send_result_response_errors
[1.870s] 2: [ FAILED ] TestGoalRequestServer.publish_status_rcl_errors
[1.871s] 2: [ FAILED ] TestGoalRequestServer.publish_status_send_cancel_response_errors
[1.871s] 2: [ FAILED ] TestGoalRequestServer.get_result_rcl_errors
[1.871s] 2: [ FAILED ] TestGoalRequestServer.send_result_rcl_errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're correct. I wrote these tests just to cover different errors that can occur, but it won't work as it is anyway. I think it makes sense for me to add a correctly functioning unit test to prove the test fixture code is good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I updated these test fixtures. I now run a nominal check that shouldn't throw, so you can refer either TestGoalRequestServer or TestCancelRequestServer if need be (but it sounds like you were able to write one).
hidmic
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
4a3e745 to
9cb1776
Compare
cfe0311 to
b1271f6
Compare
Signed-off-by: Stephen Brawner <[email protected]>
Signed-off-by: Stephen Brawner <[email protected]>
Signed-off-by: Stephen Brawner <[email protected]>
Signed-off-by: Stephen Brawner <[email protected]>
Signed-off-by: Stephen Brawner <[email protected]>
Signed-off-by: Stephen Brawner <[email protected]>
b1271f6 to
deaa2c5
Compare
|
Rebasing onto master after #1311 was merged. |
* Increase coverage rclcpp_action to 95% Signed-off-by: Stephen Brawner <[email protected]> * PR fixup Signed-off-by: Stephen Brawner <[email protected]> * Address PR Feedback Signed-off-by: Stephen Brawner <[email protected]> * Rebase onto #1311 Signed-off-by: Stephen Brawner <[email protected]> * rcutils test depend Signed-off-by: Stephen Brawner <[email protected]> * Cleaning up Signed-off-by: Stephen Brawner <[email protected]>
* Increase coverage rclcpp_action to 95% Signed-off-by: Stephen Brawner <[email protected]> * PR fixup Signed-off-by: Stephen Brawner <[email protected]> * Address PR Feedback Signed-off-by: Stephen Brawner <[email protected]> * Rebase onto #1311 Signed-off-by: Stephen Brawner <[email protected]> * rcutils test depend Signed-off-by: Stephen Brawner <[email protected]> * Cleaning up Signed-off-by: Stephen Brawner <[email protected]>
This adds unit tests for rclcpp_action and increases the coverage to just bit over 95%. As part of this work, an issue was found with the client implementation, which is potentially addressed in #1292. This branch is currently targeting that PR branch for easy review.
Testing
--packages-select rclcpp_actionSigned-off-by: Stephen Brawner [email protected]