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:
Jorge Perez 2020-05-13 14:15:36 -03:00 committed by GitHub
parent 7f57396fb4
commit c64ca630f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 289 additions and 0 deletions

View 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_

View file

@ -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));
}

View file

@ -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);
}