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

Improve rcl init test coverage. #684

Merged
merged 2 commits into from
Jun 18, 2020
Merged
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
185 changes: 133 additions & 52 deletions rcl/test/rcl/test_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -98,65 +100,148 @@ struct FakeTestArgv
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(
{
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));
}
{
// 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, ""));
});
Blast545 marked this conversation as resolved.
Show resolved Hide resolved
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 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;
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));
}
init_options.impl->allocator = rcl_get_default_allocator();
}

/* 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);
Expand Down Expand Up @@ -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.
Expand Down