Add tests for time.c and timer.c for rcl package (#599)
* Add tests for time.c module * Add test for function rcl_timer_clock * Fix linter style issues * Add test for rcl_timer_call * Add callback test and improve call test * Add fixture class to reuse timer init/fini code * Change error code returned to match function being tested * Add tests for timer_reset function * Add tests for exchange_callback function * Add null parameter test for get guard condition * Add allocator testing tools auxiliar file * Add tests for failing ini/fini conditions * Add test for get_period function * Add test to get_time_since_last_call * Remove comment related to variable names * Fix return value on test case for fini clock * Address peer review comments * Fix CLang warning, replacing NULL with false Signed-off-by: Jorge Perez <jjperez@ekumenlabs.com>
This commit is contained in:
parent
7f57396fb4
commit
c64ca630f7
3 changed files with 289 additions and 0 deletions
94
rcl/test/rcl/allocator_testing_utils.h
Normal file
94
rcl/test/rcl/allocator_testing_utils.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2020 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCL__ALLOCATOR_TESTING_UTILS_H_
|
||||
#define RCL__ALLOCATOR_TESTING_UTILS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "rcutils/allocator.h"
|
||||
|
||||
typedef struct __failing_allocator_state
|
||||
{
|
||||
bool is_failing;
|
||||
} __failing_allocator_state;
|
||||
|
||||
void *
|
||||
failing_malloc(size_t size, void * state)
|
||||
{
|
||||
if (((__failing_allocator_state *)state)->is_failing) {
|
||||
return nullptr;
|
||||
}
|
||||
return rcutils_get_default_allocator().allocate(size, rcutils_get_default_allocator().state);
|
||||
}
|
||||
|
||||
void *
|
||||
failing_realloc(void * pointer, size_t size, void * state)
|
||||
{
|
||||
if (((__failing_allocator_state *)state)->is_failing) {
|
||||
return nullptr;
|
||||
}
|
||||
return rcutils_get_default_allocator().reallocate(
|
||||
pointer, size, rcutils_get_default_allocator().state);
|
||||
}
|
||||
|
||||
void
|
||||
failing_free(void * pointer, void * state)
|
||||
{
|
||||
if (((__failing_allocator_state *)state)->is_failing) {
|
||||
return;
|
||||
}
|
||||
rcutils_get_default_allocator().deallocate(pointer, rcutils_get_default_allocator().state);
|
||||
}
|
||||
|
||||
void *
|
||||
failing_calloc(size_t number_of_elements, size_t size_of_element, void * state)
|
||||
{
|
||||
if (((__failing_allocator_state *)state)->is_failing) {
|
||||
return nullptr;
|
||||
}
|
||||
return rcutils_get_default_allocator().zero_allocate(
|
||||
number_of_elements, size_of_element, rcutils_get_default_allocator().state);
|
||||
}
|
||||
|
||||
static inline rcutils_allocator_t
|
||||
get_failing_allocator(void)
|
||||
{
|
||||
static __failing_allocator_state state;
|
||||
state.is_failing = true;
|
||||
auto failing_allocator = rcutils_get_default_allocator();
|
||||
failing_allocator.allocate = failing_malloc;
|
||||
failing_allocator.deallocate = failing_free;
|
||||
failing_allocator.reallocate = failing_realloc;
|
||||
failing_allocator.zero_allocate = failing_calloc;
|
||||
failing_allocator.state = &state;
|
||||
return failing_allocator;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_failing_allocator_is_failing(rcutils_allocator_t & failing_allocator, bool state)
|
||||
{
|
||||
((__failing_allocator_state *)failing_allocator.state)->is_failing = state;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RCL__ALLOCATOR_TESTING_UTILS_H_
|
|
@ -268,6 +268,18 @@ TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), specific_clock_instantiation) {
|
|||
EXPECT_EQ(uninitialized_clock.type, RCL_CLOCK_UNINITIALIZED) <<
|
||||
"Expected time source of type RCL_CLOCK_UNINITIALIZED";
|
||||
EXPECT_TRUE(rcutils_allocator_is_valid(&(uninitialized_clock.allocator)));
|
||||
ret = rcl_clock_fini(&uninitialized_clock);
|
||||
EXPECT_EQ(ret, RCL_RET_INVALID_ARGUMENT) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
rcl_ros_clock_fini(&uninitialized_clock), RCL_RET_ERROR) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
rcl_steady_clock_fini(&uninitialized_clock), RCL_RET_ERROR) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
EXPECT_EQ(
|
||||
rcl_system_clock_fini(&uninitialized_clock), RCL_RET_ERROR) << rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
{
|
||||
rcl_clock_t ros_clock;
|
||||
|
@ -296,6 +308,12 @@ TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), specific_clock_instantiation) {
|
|||
ret = rcl_clock_fini(&steady_clock);
|
||||
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
|
||||
}
|
||||
{
|
||||
rcl_clock_t fail_clock;
|
||||
rcl_clock_type_t undefined_type = (rcl_clock_type_t) 130;
|
||||
rcl_ret_t ret = rcl_clock_init(undefined_type, &fail_clock, &allocator);
|
||||
EXPECT_EQ(ret, RCL_RET_INVALID_ARGUMENT) << rcl_get_error_string().str;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), rcl_time_difference) {
|
||||
|
@ -333,6 +351,9 @@ TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), rcl_time_difference) {
|
|||
ret = rcl_difference_times(&b, &a, &d);
|
||||
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(d.nanoseconds, -1000);
|
||||
|
||||
b.clock_type = RCL_SYSTEM_TIME;
|
||||
EXPECT_EQ(rcl_difference_times(&a, &b, &d), RCL_RET_ERROR) << rcl_get_error_string().str;
|
||||
}
|
||||
|
||||
TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), rcl_time_difference_signed) {
|
||||
|
@ -484,6 +505,33 @@ TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), rcl_time_clock_change_callbacks) {
|
|||
reset_callback_triggers();
|
||||
}
|
||||
|
||||
TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), rcl_time_fail_set_jump_callbacks) {
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
rcl_clock_t fail_clock;
|
||||
rcl_time_jump_t time_jump;
|
||||
rcl_jump_threshold_t threshold;
|
||||
rcl_ret_t ret = rcl_clock_init(RCL_CLOCK_UNINITIALIZED, &fail_clock, &allocator);
|
||||
EXPECT_EQ(RCL_RET_OK, ret) << rcl_get_error_string().str;
|
||||
|
||||
threshold.on_clock_change = false;
|
||||
threshold.min_forward.nanoseconds = -1;
|
||||
threshold.min_backward.nanoseconds = 0;
|
||||
|
||||
EXPECT_EQ(
|
||||
RCL_RET_INVALID_ARGUMENT,
|
||||
rcl_clock_add_jump_callback(&fail_clock, threshold, clock_callback, &time_jump)) <<
|
||||
rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
|
||||
threshold.min_forward.nanoseconds = 0;
|
||||
threshold.min_backward.nanoseconds = 1;
|
||||
EXPECT_EQ(
|
||||
RCL_RET_INVALID_ARGUMENT,
|
||||
rcl_clock_add_jump_callback(&fail_clock, threshold, clock_callback, &time_jump)) <<
|
||||
rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), rcl_time_forward_jump_callbacks) {
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
auto * ros_clock =
|
||||
|
@ -730,3 +778,29 @@ TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), add_remove_add_jump_callback) {
|
|||
rcl_get_error_string().str;
|
||||
EXPECT_EQ(1u, clock->num_jump_callbacks);
|
||||
}
|
||||
|
||||
TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), failed_get_now) {
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
rcl_clock_t uninitialized_clock;
|
||||
rcl_time_point_value_t query_now;
|
||||
rcl_ret_t ret = rcl_clock_init(RCL_CLOCK_UNINITIALIZED, &uninitialized_clock, &allocator);
|
||||
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(uninitialized_clock.type, RCL_CLOCK_UNINITIALIZED);
|
||||
uninitialized_clock.get_now = NULL;
|
||||
EXPECT_EQ(RCL_RET_ERROR, rcl_clock_get_now(&uninitialized_clock, &query_now));
|
||||
}
|
||||
|
||||
TEST(CLASSNAME(rcl_time, RMW_IMPLEMENTATION), fail_override) {
|
||||
rcl_clock_t ros_clock;
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
bool result;
|
||||
rcl_time_point_value_t set_point = 1000000000ull;
|
||||
ASSERT_EQ(
|
||||
RCL_RET_OK, rcl_clock_init(
|
||||
RCL_CLOCK_UNINITIALIZED, &ros_clock, &allocator)) << rcl_get_error_string().str;
|
||||
|
||||
EXPECT_EQ(RCL_RET_ERROR, rcl_enable_ros_time_override(&ros_clock));
|
||||
EXPECT_EQ(RCL_RET_ERROR, rcl_disable_ros_time_override(&ros_clock));
|
||||
EXPECT_EQ(RCL_RET_ERROR, rcl_is_enabled_ros_time_override(&ros_clock, &result));
|
||||
EXPECT_EQ(RCL_RET_ERROR, rcl_set_ros_time_override(&ros_clock, set_point));
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "osrf_testing_tools_cpp/scope_exit.hpp"
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "./allocator_testing_utils.h"
|
||||
|
||||
class TestTimerFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
|
@ -72,6 +74,12 @@ static void callback_function(rcl_timer_t * timer, int64_t last_call)
|
|||
(void) last_call;
|
||||
times_called++;
|
||||
}
|
||||
static void callback_function_changed(rcl_timer_t * timer, int64_t last_call)
|
||||
{
|
||||
(void) timer;
|
||||
(void) last_call;
|
||||
times_called--;
|
||||
}
|
||||
|
||||
class TestPreInitTimer : public TestTimerFixture
|
||||
{
|
||||
|
@ -80,6 +88,7 @@ public:
|
|||
rcl_allocator_t allocator;
|
||||
rcl_timer_t timer;
|
||||
rcl_timer_callback_t timer_callback_test = &callback_function;
|
||||
rcl_timer_callback_t timer_callback_changed = &callback_function_changed;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
|
@ -559,3 +568,115 @@ TEST_F(TestPreInitTimer, test_timer_get_allocator) {
|
|||
|
||||
EXPECT_EQ(NULL, rcl_timer_get_allocator(nullptr));
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_timer_clock) {
|
||||
rcl_clock_t * clock_impl = nullptr;
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_clock(&timer, &clock_impl)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(clock_impl, &clock);
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_timer_call) {
|
||||
int64_t next_call_start = 0;
|
||||
int64_t next_call_end = 0;
|
||||
int64_t old_period = 0;
|
||||
times_called = 0;
|
||||
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_get_time_until_next_call(&timer, &next_call_start));
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 1);
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 3);
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_get_time_until_next_call(&timer, &next_call_end));
|
||||
EXPECT_GT(next_call_end, next_call_start);
|
||||
|
||||
next_call_start = next_call_end;
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_exchange_period(&timer, 0, &old_period));
|
||||
EXPECT_EQ(RCL_S_TO_NS(1), old_period);
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 4);
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_get_time_until_next_call(&timer, &next_call_end));
|
||||
EXPECT_GT(next_call_start, next_call_end);
|
||||
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_cancel(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(RCL_RET_TIMER_CANCELED, rcl_timer_call(&timer));
|
||||
EXPECT_EQ(times_called, 4);
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_get_callback) {
|
||||
ASSERT_EQ(timer_callback_test, rcl_timer_get_callback(&timer)) << rcl_get_error_string().str;
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_timer_reset) {
|
||||
int64_t next_call_start = 0;
|
||||
int64_t next_call_end = 0;
|
||||
times_called = 0;
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 2);
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_get_time_until_next_call(&timer, &next_call_start));
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_reset(&timer));
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_get_time_until_next_call(&timer, &next_call_end));
|
||||
EXPECT_GT(next_call_start, next_call_end);
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_cancel(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(RCL_RET_TIMER_CANCELED, rcl_timer_call(&timer));
|
||||
EXPECT_EQ(times_called, 2);
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_reset(&timer));
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 3);
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_timer_exchange_callback) {
|
||||
times_called = 0;
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 1);
|
||||
ASSERT_EQ(
|
||||
timer_callback_test, rcl_timer_exchange_callback(
|
||||
&timer, timer_callback_changed)) << rcl_get_error_string().str;
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_call(&timer)) << rcl_get_error_string().str;
|
||||
EXPECT_EQ(times_called, 0);
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_invalid_get_guard) {
|
||||
ASSERT_EQ(NULL, rcl_timer_get_guard_condition(nullptr));
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_invalid_init_fini) {
|
||||
rcl_allocator_t bad_allocator = get_failing_allocator();
|
||||
rcl_timer_t timer_fail = rcl_get_zero_initialized_timer();
|
||||
|
||||
EXPECT_EQ(
|
||||
RCL_RET_ALREADY_INIT, rcl_timer_init(
|
||||
&timer, &clock, this->context_ptr, 500, nullptr,
|
||||
rcl_get_default_allocator())) << rcl_get_error_string().str;
|
||||
|
||||
ASSERT_EQ(
|
||||
RCL_RET_BAD_ALLOC, rcl_timer_init(
|
||||
&timer_fail, &clock, this->context_ptr, RCL_S_TO_NS(1), timer_callback_test,
|
||||
bad_allocator)) << rcl_get_error_string().str;
|
||||
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_timer_fini(nullptr));
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_timer_get_period) {
|
||||
int64_t period = 0;
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_get_period(&timer, &period));
|
||||
EXPECT_EQ(RCL_S_TO_NS(1), period);
|
||||
|
||||
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, rcl_timer_get_period(nullptr, &period));
|
||||
EXPECT_EQ(RCL_RET_INVALID_ARGUMENT, rcl_timer_get_period(&timer, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(TestPreInitTimer, test_time_since_last_call) {
|
||||
rcl_time_point_value_t time_sice_next_call_start = 0u;
|
||||
rcl_time_point_value_t time_sice_next_call_end = 0u;
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_get_time_since_last_call(&timer, &time_sice_next_call_start));
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_timer_get_time_since_last_call(&timer, &time_sice_next_call_end));
|
||||
EXPECT_GT(time_sice_next_call_end, time_sice_next_call_start);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue