Skip to content

Commit

Permalink
Add coverage tests 94% service.c (#756)
Browse files Browse the repository at this point in the history
* Add tests for fail init
* Add fini tests
* Add tests rcl_take_request_with_info
* Add tests send_response
* Change const strings to constexpr
* Improve test descriptions
* Remove test

Signed-off-by: Jorge Perez <jjperez@ekumenlabs.com>
  • Loading branch information
Blast545 committed Aug 20, 2020
1 parent 4cc5f2e commit 686ba35
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 2 deletions.
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();
}
}

0 comments on commit 686ba35

Please sign in to comment.