Improve rcl init test coverage. (#684)

* Improve rcl init test coverage.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>

* Address peer review comments.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
This commit is contained in:
Michel Hidalgo 2020-06-18 10:54:02 -03:00 committed by Alejandro Hernández Cordero
parent dda5103935
commit 6ec0c6cfa2

View file

@ -14,15 +14,17 @@
#include <gtest/gtest.h>
#include "rcl/rcl.h"
#include "./failing_allocator_functions.hpp"
#include "osrf_testing_tools_cpp/memory_tools/memory_tools.hpp"
#include "osrf_testing_tools_cpp/scope_exit.hpp"
#include "rcl/arguments.h"
#include "rcl/error_handling.h"
#include "rcl/rcl.h"
#include "rcl/security.h"
#include "rcutils/env.h"
#include "rcutils/format_string.h"
#include "rcutils/snprintf.h"
#include "./allocator_testing_utils.h"
#include "../src/rcl/init_options_impl.h"
#ifdef RMW_IMPLEMENTATION
@ -98,65 +100,148 @@ private:
FakeTestArgv(const FakeTestArgv &) = delete;
};
/* Tests the rcl_init() and rcl_shutdown() functions.
/* Tests rcl_init_options_init() and rcl_init_options_fini() functions.
*/
TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_and_shutdown) {
rcl_ret_t ret;
TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_options_init) {
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
rcl_ret_t ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
rcl_context_t context = rcl_get_zero_initialized_context();
// A shutdown before any init has been called should fail.
ret = rcl_shutdown(&context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
// Already init
ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
EXPECT_EQ(RCL_RET_ALREADY_INIT, ret) << rcl_get_error_string().str;
rcl_reset_error();
// If argc is not 0, but argv is, it should be an invalid argument.
ret = rcl_init(42, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
// If argc is not 0, argv is not null but contains one, it should be an invalid argument.
const char * invalid_args[] = {"some-arg", nullptr};
ret = rcl_init(2, invalid_args, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
// If argc is less than 1, argv is not null, it should be an invalid argument.
ret = rcl_init(0, invalid_args, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
// If either the allocate or deallocate function pointers are not set, it should be invalid arg.
init_options.impl->allocator.allocate = nullptr;
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
init_options.impl->allocator.allocate = rcl_get_default_allocator().allocate;
init_options.impl->allocator.deallocate = nullptr;
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
// If the malloc call fails (with some valid arguments to copy), it should be a bad alloc.
}
/* Tests calling rcl_init() with invalid arguments fails.
*/
TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_invalid_arguments) {
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_ret_t ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
FakeTestArgv test_args;
rcl_allocator_t failing_allocator = rcl_get_default_allocator();
failing_allocator.allocate = failing_malloc;
failing_allocator.reallocate = failing_realloc;
failing_allocator.zero_allocate = failing_calloc;
init_options.impl->allocator = failing_allocator;
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_BAD_ALLOC, ret);
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
{
// If argc is not 0, but argv is, it should be an invalid argument.
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(42, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
}
init_options.impl->allocator = rcl_get_default_allocator();
{
// If argc is not 0, argv is not null but contains one, it should be an invalid argument.
rcl_context_t context = rcl_get_zero_initialized_context();
const char * null_args[] = {"some-arg", nullptr};
ret = rcl_init(2, null_args, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
}
{
// If argc is less than 1, argv is not null, it should be an invalid argument.
rcl_context_t context = rcl_get_zero_initialized_context();
const char * some_args[] = {"some-arg"};
ret = rcl_init(0, some_args, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
}
{
// If an invalid ROS arg is given, init should fail.
rcl_context_t context = rcl_get_zero_initialized_context();
const char * bad_remap_args[] = {
"some-arg", RCL_ROS_ARGS_FLAG, RCL_REMAP_FLAG, "name:="};
const size_t argc = sizeof(bad_remap_args) / sizeof(const char *);
ret = rcl_init(argc, bad_remap_args, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ROS_ARGS, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
}
{
// If an invalid enclave is given, init should fail.
rcl_context_t context = rcl_get_zero_initialized_context();
const char * bad_enclave_args[] = {
"some-arg", RCL_ROS_ARGS_FLAG, RCL_ENCLAVE_FLAG, "1foo"};
const size_t argc = sizeof(bad_enclave_args) / sizeof(const char *);
ret = rcl_init(argc, bad_enclave_args, &init_options, &context);
EXPECT_EQ(RCL_RET_ERROR, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
}
{
// If security keystore is invalid, init should fail.
ASSERT_TRUE(rcutils_set_env(ROS_SECURITY_ENABLE_VAR_NAME, "true"));
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_TRUE(rcutils_set_env(ROS_SECURITY_ENABLE_VAR_NAME, ""));
});
ASSERT_TRUE(rcutils_set_env(ROS_SECURITY_STRATEGY_VAR_NAME, "Enforce"));
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_TRUE(rcutils_set_env(ROS_SECURITY_STRATEGY_VAR_NAME, ""));
});
ASSERT_TRUE(rcutils_set_env(ROS_SECURITY_KEYSTORE_VAR_NAME, "/not/a/real/secure/root"));
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_TRUE(rcutils_set_env(ROS_SECURITY_KEYSTORE_VAR_NAME, ""));
});
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_ERROR, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
}
{
// If either the allocate or deallocate function pointers are not set,
// it should be invalid arg.
rcl_context_t context = rcl_get_zero_initialized_context();
rcl_allocator_t allocator = init_options.impl->allocator;
init_options.impl->allocator =
(rcl_allocator_t)rcutils_get_zero_initialized_allocator();
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
init_options.impl->allocator = allocator;
ASSERT_FALSE(rcl_context_is_valid(&context));
}
{
// If the malloc call fails (with some valid arguments to copy),
// it should be a bad alloc.
FakeTestArgv test_args;
rcl_allocator_t allocator = init_options.impl->allocator;
init_options.impl->allocator = get_failing_allocator();
rcl_context_t context = rcl_get_zero_initialized_context();
ret = rcl_init(test_args.argc, test_args.argv, &init_options, &context);
EXPECT_EQ(RCL_RET_BAD_ALLOC, ret);
rcl_reset_error();
init_options.impl->allocator = allocator;
ASSERT_FALSE(rcl_context_is_valid(&context));
}
}
/* Tests the rcl_init() and rcl_shutdown() functions.
*/
TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_and_shutdown) {
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_ret_t ret = rcl_init_options_init(&init_options, rcl_get_default_allocator());
ASSERT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
rcl_context_t context = rcl_get_zero_initialized_context();
// A shutdown before an init should fail.
ret = rcl_shutdown(&context);
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, ret);
rcl_reset_error();
ASSERT_FALSE(rcl_context_is_valid(&context));
// If argc is 0 and argv is nullptr and the allocator is valid, it should succeed.
ret = rcl_init(0, nullptr, &init_options, &context);
EXPECT_EQ(RCL_RET_OK, ret);
@ -210,10 +295,6 @@ TEST_F(CLASSNAME(TestRCLFixture, RMW_IMPLEMENTATION), test_rcl_init_and_shutdown
ret = rcl_context_fini(&context);
EXPECT_EQ(ret, RCL_RET_OK);
context = rcl_get_zero_initialized_context();
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
EXPECT_EQ(RCL_RET_OK, rcl_init_options_fini(&init_options)) << rcl_get_error_string().str;
});
}
/* Tests the rcl_get_instance_id() function.