Add coverage tests 94% service.c (#756)

* 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>
This commit is contained in:
Jorge Perez 2020-08-20 12:07:27 -03:00 committed by Alejandro Hernández Cordero
parent 04210ebdc2
commit 6d95545a9f
3 changed files with 207 additions and 2 deletions

View file

@ -111,7 +111,6 @@ rcl_service_init(
RCL_SET_ERROR_MSG(rcutils_get_error_string().str); RCL_SET_ERROR_MSG(rcutils_get_error_string().str);
ret = RCL_RET_ERROR; ret = RCL_RET_ERROR;
goto cleanup; goto cleanup;
return RCL_RET_ERROR;
} }
if (ret != RCL_RET_OK) { if (ret != RCL_RET_OK) {
if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) { if (ret == RCL_RET_TOPIC_NAME_INVALID || ret == RCL_RET_UNKNOWN_SUBSTITUTION) {

View file

@ -217,7 +217,7 @@ function(test_target_function)
SRCS rcl/test_service.cpp rcl/wait_for_entity_helpers.cpp SRCS rcl/test_service.cpp rcl/wait_for_entity_helpers.cpp
ENV ${rmw_implementation_env_var} ENV ${rmw_implementation_env_var}
APPEND_LIBRARY_DIRS ${extra_lib_dirs} APPEND_LIBRARY_DIRS ${extra_lib_dirs}
LIBRARIES ${PROJECT_NAME} LIBRARIES ${PROJECT_NAME} mimick
AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs" AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs"
) )

View file

@ -21,8 +21,11 @@
#include "osrf_testing_tools_cpp/scope_exit.hpp" #include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/error_handling.h" #include "rcl/error_handling.h"
#include "rmw/validate_namespace.h"
#include "wait_for_entity_helpers.hpp" #include "wait_for_entity_helpers.hpp"
#include "./allocator_testing_utils.h" #include "./allocator_testing_utils.h"
#include "../mocking_utils/patch.hpp"
#ifdef RMW_IMPLEMENTATION #ifdef RMW_IMPLEMENTATION
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX # define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
@ -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; EXPECT_EQ(RCL_RET_SERVICE_NAME_INVALID, ret) << rcl_get_error_string().str;
rcl_reset_error(); 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();
}
}