Skip to content
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

Add coverage tests context functions #1321

Merged
merged 9 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rclcpp/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ ament_add_gtest(test_utilities rclcpp/test_utilities.cpp
if(TARGET test_utilities)
ament_target_dependencies(test_utilities
"rcl")
target_link_libraries(test_utilities ${PROJECT_NAME})
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
endif()

ament_add_gtest(test_init rclcpp/test_init.cpp
Expand Down
131 changes: 131 additions & 0 deletions rclcpp/test/rclcpp/test_utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@
#include <string>
#include <memory>

#include "rcl/init.h"
#include "rcl/logging.h"

#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/scope_exit.hpp"

#include "../mocking_utils/patch.hpp"

TEST(TestUtilities, remove_ros_arguments) {
const char * const argv[] = {
Expand Down Expand Up @@ -78,3 +84,128 @@ TEST(TestUtilities, multi_init) {
EXPECT_FALSE(rclcpp::ok(context1));
EXPECT_FALSE(rclcpp::ok(context2));
}

TEST(TestUtilities, test_context_basic_access) {
auto context1 = std::make_shared<rclcpp::contexts::DefaultContext>();
EXPECT_NE(nullptr, context1->get_init_options().get_rcl_init_options());
EXPECT_EQ(0u, context1->get_on_shutdown_callbacks().size());
EXPECT_EQ(std::string{""}, context1->shutdown_reason());
}

TEST(TestUtilities, test_context_basic_access_const_methods) {
auto context1 = std::make_shared<const rclcpp::contexts::DefaultContext>();

EXPECT_NE(nullptr, context1->get_init_options().get_rcl_init_options());
EXPECT_EQ(0u, context1->get_on_shutdown_callbacks().size());
// EXPECT_EQ(std::string{""}, context1->shutdown_reason()); not available for const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a method that should be const, I wonder if there is a better thread-safe way of setting the string in rclcpp::Context so it can be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine it is not const because the shutdown_reason may change. But, in terms of this specific test, is odd that the method is not available for a const context. Not sure how to proceed here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it's const because it has to lock the mutex. It might just be worth opening an issue and getting some input from others. I don't know whether it's worth investigating or if it's not an important use case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened #1323 to track the conversation. I didn't tag anyone as it might not be a priority at the moment, let me know if you think I should tag someone in particular.

}

MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, ==)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, !=)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, >)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcl_guard_condition_options_t, <)

TEST(TestUtilities, test_context_release_interrupt_guard_condition) {
auto context1 = std::make_shared<rclcpp::contexts::DefaultContext>();
context1->init(0, nullptr);
RCLCPP_SCOPE_EXIT(rclcpp::shutdown(context1););

rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_ret_t ret = rcl_wait_set_init(
&wait_set, 0, 2, 0, 0, 0, 0, context1->get_rcl_context().get(),
rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret);

// Expected usage
rcl_guard_condition_t * interrupt_guard_condition =
context1->get_interrupt_guard_condition(&wait_set);
EXPECT_NE(nullptr, interrupt_guard_condition);
EXPECT_NO_THROW(context1->release_interrupt_guard_condition(&wait_set));

{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_guard_condition_init, RCL_RET_ERROR);
EXPECT_THROW(
{interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);},
rclcpp::exceptions::RCLError);
}

{
interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_guard_condition_fini, RCL_RET_ERROR);
EXPECT_THROW(
{context1->release_interrupt_guard_condition(&wait_set);},
rclcpp::exceptions::RCLError);
}

{
interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_guard_condition_fini, RCL_RET_ERROR);
EXPECT_NO_THROW({context1->release_interrupt_guard_condition(&wait_set, std::nothrow);});
}

{
EXPECT_THROW(
context1->release_interrupt_guard_condition(nullptr),
std::runtime_error);
}

// Test it works after restore mocks
interrupt_guard_condition = context1->get_interrupt_guard_condition(&wait_set);
EXPECT_NE(nullptr, interrupt_guard_condition);
EXPECT_NO_THROW(context1->release_interrupt_guard_condition(&wait_set));
}


TEST(TestUtilities, test_context_init_shutdown_fails) {
{
auto context = std::make_shared<rclcpp::contexts::DefaultContext>();
auto context_fail_init = std::make_shared<rclcpp::contexts::DefaultContext>();
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_init, RCL_RET_ERROR);
EXPECT_THROW(context_fail_init->init(0, nullptr), rclcpp::exceptions::RCLError);
}

{
auto context_fail_init = std::make_shared<rclcpp::contexts::DefaultContext>();
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_logging_configure_with_output_handler, RCL_RET_ERROR);
EXPECT_THROW(context_fail_init->init(0, nullptr), rclcpp::exceptions::RCLError);
}

{
auto context = std::make_shared<rclcpp::contexts::DefaultContext>();
context->init(0, nullptr);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
// This will log a message, no throw expected
EXPECT_NO_THROW(context->shutdown(""));
}

{
auto context = std::make_shared<rclcpp::contexts::DefaultContext>();
context->init(0, nullptr);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_shutdown, RCL_RET_ERROR);
EXPECT_THROW(context->shutdown(""), rclcpp::exceptions::RCLError);
}

{
auto context = std::make_shared<rclcpp::contexts::DefaultContext>();
context->init(0, nullptr);
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_logging_fini, RCL_RET_ERROR);
// This will log a message, no throw expected
EXPECT_NO_THROW(context->shutdown(""));
}

{
auto context_to_destroy = std::make_shared<rclcpp::contexts::DefaultContext>();
auto mock = mocking_utils::inject_on_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
// This will log a message, no throw expected
EXPECT_NO_THROW({context_to_destroy.reset();});
}
}