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 94% service.c #756

Merged
merged 7 commits into from
Aug 20, 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
1 change: 0 additions & 1 deletion rcl/src/rcl/service.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ rcl_service_init(
RCL_SET_ERROR_MSG(rcutils_get_error_string().str);
ret = RCL_RET_ERROR;
goto cleanup;
return RCL_RET_ERROR;
}
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {
Expand Down
2 changes: 1 addition & 1 deletion rcl/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ function(test_target_function)
SRCS rcl/test_service.cpp rcl/wait_for_entity_helpers.cpp
ENV ${rmw_implementation_env_var}
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
LIBRARIES ${PROJECT_NAME}
LIBRARIES ${PROJECT_NAME} mimick
AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs"
)

Expand Down
206 changes: 206 additions & 0 deletions rcl/test/rcl/test_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@

#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/error_handling.h"
#include "rmw/validate_namespace.h"

#include "wait_for_entity_helpers.hpp"
#include "./allocator_testing_utils.h"
#include "../mocking_utils/patch.hpp"

#ifdef RMW_IMPLEMENTATION
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
Expand Down Expand Up @@ -420,3 +423,206 @@ TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_service_fail_name
EXPECT_EQ(RCL_RET_SERVICE_NAME_INVALID, ret) << rcl_get_error_string().str;
rcl_reset_error();
}

// Define dummy comparison operators for rcutils_allocator_t type for use with the Mimick Library
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, ==)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, <)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, >)
MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE(rcutils_allocator_t, !=)

/* Test failed service initialization using mocks
*/
TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_fail_ini_mocked) {
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
test_msgs, srv, BasicTypes);
constexpr char topic[] = "topic";
rcl_service_t service = rcl_get_zero_initialized_service();
rcl_service_options_t service_options = rcl_service_get_default_options();
service_options.qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
rcl_ret_t ret = RCL_RET_OK;

{
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rcutils_string_map_init, RCUTILS_RET_ERROR);
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_ERROR, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
{
// Mocking this function causes rcl_expand_topic_name to return RCL_RET_ERROR
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rmw_validate_namespace, RMW_RET_ERROR);
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_ERROR, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
{
auto mock = mocking_utils::inject_on_return(
"lib:rcl", rcutils_string_map_fini, RCUTILS_RET_ERROR);
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_ERROR, ret);
}
{
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rmw_validate_full_topic_name, RMW_RET_ERROR);
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_ERROR, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
{
auto mock = mocking_utils::patch(
"lib:rcl", rmw_validate_full_topic_name,
[](auto, int * result, auto) {
*result = RMW_TOPIC_INVALID_IS_EMPTY_STRING;
return RMW_RET_OK;
});
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_SERVICE_NAME_INVALID, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
{
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rmw_create_service, nullptr);
ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
EXPECT_EQ(RCL_RET_ERROR, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
}

/* Test failed service finalization using mocks
*/
TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_fail_fini_mocked) {
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
test_msgs, srv, BasicTypes);
constexpr char topic[] = "primitives";

rcl_service_t service = rcl_get_zero_initialized_service();
rcl_service_options_t service_options = rcl_service_get_default_options();
rcl_ret_t ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;

rcl_service_t empty_service = rcl_get_zero_initialized_service();
ret = rcl_service_fini(&empty_service, this->node_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;

auto mock = mocking_utils::inject_on_return(
"lib:rcl", rmw_destroy_service, RMW_RET_ERROR);
ret = rcl_service_fini(&service, this->node_ptr);
EXPECT_EQ(RCL_RET_ERROR, ret) << rcl_get_error_string().str;
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}

/* Test failed service take_request_with_info using mocks and nullptrs
*/
TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_fail_take_request_with_info) {
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
test_msgs, srv, BasicTypes);
constexpr char topic[] = "primitives";

rcl_service_t service = rcl_get_zero_initialized_service();
rcl_service_options_t service_options = rcl_service_get_default_options();
rcl_ret_t ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
rcl_ret_t ret = rcl_service_fini(&service, this->node_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
});

test_msgs__srv__BasicTypes_Request service_request;
test_msgs__srv__BasicTypes_Request__init(&service_request);
rmw_service_info_t header;

ret = rcl_take_request_with_info(nullptr, &header, &service_request);
EXPECT_EQ(RCL_RET_SERVICE_INVALID, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();

ret = rcl_take_request_with_info(&service, nullptr, &service_request);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();

ret = rcl_take_request_with_info(&service, &header, nullptr);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();

{
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rmw_take_request, RMW_RET_ERROR);
ret = rcl_take_request_with_info(&service, &header, &service_request);
EXPECT_EQ(RCL_RET_ERROR, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
{
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rmw_take_request, RMW_RET_BAD_ALLOC);
ret = rcl_take_request_with_info(&service, &header, &service_request);
EXPECT_EQ(RCL_RET_BAD_ALLOC, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
{
auto mock = mocking_utils::patch(
"lib:rcl", rmw_take_request,
[](auto, auto, auto, bool * taken) {
*taken = false;
return RMW_RET_OK;
});
ret = rcl_take_request_with_info(&service, &header, &service_request);
EXPECT_EQ(RCL_RET_SERVICE_TAKE_FAILED, ret);
}
}

/* Test failed service send_response using mocks and nullptrs
*/
TEST_F(CLASSNAME(TestServiceFixture, RMW_IMPLEMENTATION), test_fail_send_response) {
const rosidl_service_type_support_t * ts = ROSIDL_GET_SRV_TYPE_SUPPORT(
test_msgs, srv, BasicTypes);
constexpr char topic[] = "primitives";

rcl_service_t service = rcl_get_zero_initialized_service();
rcl_service_options_t service_options = rcl_service_get_default_options();
rcl_ret_t ret = rcl_service_init(&service, this->node_ptr, ts, topic, &service_options);
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
rcl_ret_t ret = rcl_service_fini(&service, this->node_ptr);
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
});

// Init dummy response.
test_msgs__srv__BasicTypes_Response service_response;
test_msgs__srv__BasicTypes_Response__init(&service_response);
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
test_msgs__srv__BasicTypes_Response__fini(&service_response);
});
rmw_service_info_t header;

ret = rcl_send_response(nullptr, &header.request_id, &service_response);
EXPECT_EQ(RCL_RET_SERVICE_INVALID, ret);

ret = rcl_send_response(&service, nullptr, &service_response);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);

ret = rcl_send_response(&service, &header.request_id, nullptr);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);

{
auto mock = mocking_utils::patch_and_return(
"lib:rcl", rmw_send_response, RMW_RET_ERROR);
ret = rcl_send_response(&service, &header.request_id, &service_response);
EXPECT_EQ(RCL_RET_ERROR, ret);
EXPECT_TRUE(rcl_error_is_set());
rcl_reset_error();
}
}