/* SPDX-License-Identifier: BSD-2-Clause */ /** * @defgroup RegulatorTests Regulator Test Cases * * @brief Unit test cases for the Regulator * * This is a set of unit test cases for the regulator. */ /** * @ingroup RegulatorTests * * @file * * @brief Test 01 for Regulator Library */ /* * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include /** * @brief Regulator Test Name */ const char rtems_test_name[] = "Regulator 1"; /* * Prototypes for wrapped functions */ void *__wrap_malloc(size_t size); void *__real_malloc(size_t size); /** * @ingroup RegulatorTests * @brief Calloc Wrapper Trigger Count */ static int malloc_trigger_count; /** * @ingroup RegulatorTests * @brief Calloc Wrapper Call Count */ static int malloc_call_count; /** * @ingroup RegulatorTests * @brief Calloc Wrapper Trigger enable */ static bool malloc_trigger_enabled; /** * @ingroup RegulatorTests * @brief Enable Calloc Wrapper Trigger */ static void malloc_trigger_enable( int trigger_count ) { malloc_trigger_enabled = true; malloc_trigger_count = trigger_count; malloc_call_count = 0; } /** * @ingroup RegulatorTests * @brief Reset Calloc Wrapper Trigger and Count */ static void malloc_trigger_reset(void) { malloc_trigger_enabled = 0; malloc_trigger_count = 0; malloc_call_count = 0; } /** * @ingroup RegulatorTests * @brief Calloc Wrapper to Trigger Allocation Errors */ void *__wrap_malloc(size_t size) { if (malloc_trigger_enabled) { malloc_call_count++; if (malloc_call_count == malloc_trigger_count) { return NULL; } } return __real_malloc(size); } /** * @brief Constant to simpify code */ #define FIVE_SECONDS (5 * rtems_clock_get_ticks_per_second()) /** * @ingroup RegulatorTests * @brief Empty Deliver Method for Testing */ static bool test_regulator_deliverer( void *context, void *message, size_t length ) { (void) context; (void) message; (void) length; return true; } /** * @ingroup RegulatorTests * @brief Maximum length of a test message that is delivered */ #define MAXIMUM_MESSAGE_LENGTH 32 /** * @ingroup RegulatorTests * @brief Maximum number of test messages to buffer */ #define MAXIMUM_MESSAGES_TO_BUFFER 10 /** * @ingroup RegulatorTests * @brief Structure for capturing messages as delivered */ typedef struct { rtems_interval processed; char message[MAXIMUM_MESSAGE_LENGTH]; } message_log_t; /** * @ingroup RegulatorTests * @brief Set of Delivered messages */ message_log_t delivered_messages[MAXIMUM_MESSAGES_TO_BUFFER]; /** * @ingroup RegulatorTests * @brief Count of Delivered messages */ int delivered_message_count; /** * @ingroup RegulatorTests * @brief Reset Delivered Message Set * * This is used at the beginning of a test case which is going to * check that message contents and delivery times were as expected. */ static void delivered_messages_reset(void) { delivered_message_count = 0; memset(delivered_messages, 0xc5, sizeof(delivered_messages)); } /** * @brief Context for Logger Delivery Function */ typedef struct { /** Regulator instance being operated on */ rtems_regulator_instance *regulator; } deliverer_logger_context_t; /** * @brief Context Instance for Logger Delivery Function */ static deliverer_logger_context_t deliverer_logger_context; /** * @ingroup RegulatorTests * @brief Empty Deliver Method for Testing * * This deliverer method implementation logs the messages along with * their time of arrival. This is used by the test cases to verify * proper delivery. */ static bool test_regulator_deliverer_logger( void *context, void *message, size_t length ) { deliverer_logger_context_t *the_context; the_context = (deliverer_logger_context_t *)context; static bool caller_releases_buffer = true; size_t len; rtems_interval ticks; rtems_status_code sc; len = strnlen(message, MAXIMUM_MESSAGE_LENGTH) + 1; rtems_test_assert(len = length); ticks = rtems_clock_get_ticks_since_boot(); delivered_messages[delivered_message_count].processed = ticks; strcpy(delivered_messages[delivered_message_count].message, message); delivered_message_count++; /* * Alternate releasing the buffer here and allowing the calling Delivery * Thread to do it. This increases coverage of that logic. */ if (caller_releases_buffer == true) { caller_releases_buffer = false; return true; } sc = rtems_regulator_release_buffer(the_context->regulator, message); rtems_test_assert(sc == RTEMS_SUCCESSFUL); return false; } /** * @ingroup RegulatorTests * @brief Helper to create a Regulator instance * * This helper creates a regulator instance with some arbitrary attributes. * This is used in multiple test cases to have a valie regulator instance to * trigger error cases. */ static rtems_regulator_instance *test_regulator_create_regulator_OK(void) { rtems_status_code sc; rtems_regulator_attributes attributes = { .deliverer = test_regulator_deliverer, .deliverer_context = NULL, .maximum_message_size = 16, .maximum_messages = 10, .delivery_thread_priority = 16, .delivery_thread_stack_size = 0, .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000), .maximum_to_dequeue_per_period = 3 }; rtems_regulator_instance *regulator; regulator = NULL; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(regulator != NULL); return regulator; } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create() maximum_to_dequeue_per_period * attributes error * * This unit test verifies that rtems_regulator_create() returns an error when * the maximum_to_dequeue_per_period attribute is zero. */ static void test_regulator_create_max_dequeue_zero(void) { rtems_status_code sc; rtems_regulator_attributes attributes = { .deliverer = test_regulator_deliverer, .deliverer_context = NULL, .maximum_message_size = 16, .maximum_messages = 10, .delivery_thread_priority = 16, .delivery_thread_stack_size = 0, .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000), .maximum_to_dequeue_per_period = 0 }; rtems_regulator_instance *regulator; regulator = NULL; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_NUMBER); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create() NULL attributes error * * This unit test verifies that rtems_regulator_create() returns an error when * the attributes argument is NULL. */ static void test_regulator_create_null_attributes(void) { rtems_status_code sc; rtems_regulator_instance *regulator; sc = rtems_regulator_create(NULL, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create NULL regulator error * * This unit test verifies that rtems_regulator_create() returns an error when * the regulator argument is NULL. */ static void test_regulator_create_null_regulator(void) { rtems_status_code sc; rtems_regulator_attributes attributes; sc = rtems_regulator_create(&attributes, NULL); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create deliverer is NULL * * This unit test verifies that rtems_regulator_create() returns an error when * the the attributes deliverer field is NULL. */ static void test_regulator_create_deliverer_is_null(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = NULL; attributes.maximum_messages = 0; attributes.maximum_message_size = 16; attributes.maximum_to_dequeue_per_period = 1; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create maximum_messages is 0 error * * This unit test verifies that rtems_regulator_create() returns an error when * the the attributes maximum_messages field is 0. */ static void test_regulator_create_maximum_messages_is_zero(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 0; attributes.maximum_message_size = 16; attributes.maximum_to_dequeue_per_period = 1; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_NUMBER); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create maximum_message_size is 0 error * * This unit test verifies that rtems_regulator_create() returns an error when * the the attributes maximum_message_size field is 0. */ static void test_regulator_create_maximum_message_size_is_zero(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 0; attributes.maximum_to_dequeue_per_period = 1; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_SIZE); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create maximum_to_dequeue_per_period is 0 error * * This unit test verifies that rtems_regulator_create() returns an error when * the the attributes maximum_to_dequeue_per_period field is 0. */ static void test_regulator_create_maximum_to_dequeue_per_period_is_zero(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 0; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_SIZE); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create returns error on failure to allocate regulator * * This unit test verifies that rtems_regulator_create() returns an error when * it is unable to allocate the mmemory for the regulator instance. */ static void test_regulator_create_malloc_regulator_fails(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 32; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); malloc_trigger_enable(1); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_NO_MEMORY); malloc_trigger_reset(); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create returns error on failure to allocate buffers * * This unit test verifies that rtems_regulator_create() returns an error when * it is unable to allocate the mmemory for the regulator buffers. */ static void test_regulator_create_malloc_buffers_fails(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 32; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); malloc_trigger_enable(2); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_NO_MEMORY); malloc_trigger_reset(); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create and delete work * * This unit test verifies that rtems_regulator_create() can successfully create * the the attributes delivery_thread_priority field is 0. */ static void test_regulator_create_delivery_thread_priority_is_zero(void) { rtems_status_code sc; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 0; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_INVALID_PRIORITY); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create rtems_partition_create error * * This unit test verifies that rtems_regulator_create() correctly returns an * error when the call to rtems_partition_create() fails. */ static void test_regulator_create_partition_create_fails(void) { rtems_status_code sc; rtems_id partition_id; unsigned long partition_area[16]; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; sc = rtems_partition_create( rtems_build_name('T', 'P', 'T', 'P'), partition_area, 16 * sizeof(unsigned long), 2 * sizeof(unsigned long), RTEMS_DEFAULT_ATTRIBUTES, &partition_id ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 8; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_TOO_MANY); sc = rtems_partition_delete(partition_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create rtems_message_queue_create error * * This unit test verifies that rtems_regulator_create() correctly returns an * error when the call to rtems_message_queue_create() fails. */ static void test_regulator_create_message_queue_create_fails(void) { rtems_status_code sc; rtems_id queue_id; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; sc = rtems_message_queue_create( rtems_build_name('T', 'Q', 'T', 'Q'), 4, sizeof(unsigned long), RTEMS_DEFAULT_ATTRIBUTES, &queue_id ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 8; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_TOO_MANY); sc = rtems_message_queue_delete(queue_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_create rtems_task_create error * * This unit test verifies that rtems_regulator_create() correctly returns an * error when the call to rtems_task_create() fails. */ static void test_regulator_create_task_create_fails(void) { rtems_status_code sc; rtems_id task_id; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; sc = rtems_task_create( rtems_build_name('T', 'T', 'T', 'T'), 80, 0, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &task_id ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 8; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_TOO_MANY); sc = rtems_task_delete(task_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify Regulator Output Thread Handles Error on Period Create * * This unit test verifies that regulator output thread correctly exits * when the call to rtems_rate_monotonic_create() fails. * * This error condition/path cannot be directly detected via a return code, * It is verified via a debugger or code coverage reports. */ static void test_regulator_create_rate_monotonic_create_fails(void) { rtems_status_code sc; rtems_id period_id; rtems_regulator_attributes attributes; rtems_regulator_instance *regulator; sc = rtems_rate_monotonic_create( rtems_build_name('T', 'S', 'T', 'P'), &period_id ); rtems_test_assert(sc == RTEMS_SUCCESSFUL); (void) memset(&attributes, 0, sizeof(rtems_regulator_attributes)); attributes.deliverer = test_regulator_deliverer; attributes.maximum_messages = 10; attributes.maximum_message_size = 16; attributes.delivery_thread_priority = 8; attributes.maximum_to_dequeue_per_period = 1; attributes.delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_SUCCESSFUL); /* * Let the output thread execute and encounter the create error. */ sleep(1); /* * Now deallocate the resources allocated earlier */ sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); sc = rtems_rate_monotonic_delete(period_id); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_delete NULL regulator error * * This unit test verifies that rtems_regulator_delete() returns an error when * the regulator argument is NULL. */ static void test_regulator_delete_null_regulator(void) { rtems_status_code sc; sc = rtems_regulator_delete(NULL, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_delete uninitialized regulator error * * This unit test verifies that rtems_regulator_delete() returns an error when * the regulator argument is uninitialized. */ static void test_regulator_delete_uninitialized_regulator(void) { rtems_status_code sc; rtems_regulator_instance regulator; (void) memset(®ulator, 0, sizeof(regulator)); sc = rtems_regulator_delete(®ulator, 0); rtems_test_assert(sc == RTEMS_INCORRECT_STATE); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_delete successful case * * This unit test verifies that rtems_regulator_delete() can be successfully * deleted. */ static void test_regulator_delete_OK(void) { rtems_status_code sc; rtems_regulator_instance *regulator; regulator = test_regulator_create_regulator_OK(); rtems_test_assert(regulator != NULL); sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_obtain_buffer NULL regulator error * * This unit test verifies that rtems_regulator_obtain_buffer() returns an error when * the regulator argument is NULL. */ static void test_regulator_obtain_buffer_null_regulator(void) { rtems_status_code sc; void *buffer; sc = rtems_regulator_obtain_buffer(NULL, &buffer); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_obtain_buffer uninitialized regulator error * * This unit test verifies that rtems_regulator_obtain_buffer() returns an error when * the regulator argument is uninitialized. */ static void test_regulator_obtain_buffer_uninitialized_regulator(void) { rtems_status_code sc; rtems_regulator_instance regulator; void *buffer; (void) memset(®ulator, 0, sizeof(regulator)); sc = rtems_regulator_obtain_buffer(®ulator, &buffer); rtems_test_assert(sc == RTEMS_INCORRECT_STATE); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_obtain_buffer successful case * * This unit test verifies that rtems_regulator_obtain_buffer() can be successfully * obtained from an initialized regulator. */ static void test_regulator_obtain_buffer_OK(void) { rtems_status_code sc; rtems_regulator_instance *regulator; void *buffer; regulator = test_regulator_create_regulator_OK(); rtems_test_assert(regulator != NULL); sc = rtems_regulator_obtain_buffer(regulator, &buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(buffer != NULL); /* * Not really testing this here but cannot delete underlying partition * if there are buffers outstanding. */ sc = rtems_regulator_release_buffer(regulator, buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(buffer != NULL); sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_release_buffer NULL regulator error * * This unit test verifies that rtems_regulator_release_buffer() returns an error when * the regulator argument is NULL. */ static void test_regulator_release_buffer_null_regulator(void) { rtems_status_code sc; void *buffer; sc = rtems_regulator_release_buffer(NULL, &buffer); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_release_buffer uninitialized regulator error * * This unit test verifies that rtems_regulator_release_buffer() returns an * error when the regulator argument is uninitialized. */ static void test_regulator_release_buffer_uninitialized_regulator(void) { rtems_status_code sc; rtems_regulator_instance regulator; void *buffer; (void) memset(®ulator, 0, sizeof(regulator)); sc = rtems_regulator_release_buffer(®ulator, &buffer); rtems_test_assert(sc == RTEMS_INCORRECT_STATE); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_release_buffer successful case * * This unit test verifies that rtems_regulator_release_buffer() can be successfully * invoked with a buffer previously allocated by rtems_regulator_obtain_buffer(). */ static void test_regulator_release_buffer_OK(void) { rtems_status_code sc; rtems_regulator_instance *regulator; void *buffer; regulator = test_regulator_create_regulator_OK(); rtems_test_assert(regulator != NULL); sc = rtems_regulator_obtain_buffer(regulator, &buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(buffer != NULL); sc = rtems_regulator_release_buffer(regulator, buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_send NULL regulator error * * This unit test verifies that rtems_regulator_send() returns an error when * the regulator argument is NULL. */ static void test_regulator_send_null_regulator(void) { rtems_status_code sc; void *buffer; size_t length; buffer = &length; length = sizeof(size_t); sc = rtems_regulator_send(NULL, buffer, length); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_send NULL message error * * This unit test verifies that rtems_regulator_send() returns an error when * the message argument is NULL. */ static void test_regulator_send_null_message(void) { rtems_status_code sc; size_t length; rtems_regulator_instance regulator; length = sizeof(size_t); sc = rtems_regulator_send(®ulator, NULL, length); rtems_test_assert(sc == RTEMS_INVALID_ADDRESS); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_send zero length message error * * This unit test verifies that rtems_regulator_send() returns an * error when the message length is 0. */ static void test_regulator_send_length_is_zero(void) { rtems_status_code sc; rtems_regulator_instance regulator; void *buffer; size_t length; buffer = &length; length = 0; sc = rtems_regulator_send(®ulator, buffer, length); rtems_test_assert(sc == RTEMS_INVALID_NUMBER); } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_send uninitialized regulator error * * This unit test verifies that rtems_regulator_send() returns an * error when the regulator argument is uninitialized. */ static void test_regulator_send_uninitialized_regulator(void) { rtems_status_code sc; rtems_regulator_instance regulator; void *buffer; size_t length; buffer = &length; length = sizeof(size_t); (void) memset(®ulator, 0, sizeof(regulator)); sc = rtems_regulator_send(®ulator, buffer, length); rtems_test_assert(sc == RTEMS_INCORRECT_STATE); } /** * @ingroup RegulatorTests * @brief Verify Cannot Delete with Message Outstanding * * This unit test verifies that when the regulator is successfully * initialized, that it cannot be deleted with an undelivered message. * It also verifies some basic statistics are working. */ static void test_regulator_cannot_delete_with_outstanding(void) { rtems_status_code sc; rtems_regulator_instance *regulator; char message[MAXIMUM_MESSAGE_LENGTH]; void *buffer; size_t length; int match; rtems_regulator_attributes attributes = { .deliverer = test_regulator_deliverer_logger, .deliverer_context = &deliverer_logger_context, .maximum_message_size = 16, .maximum_messages = 10, .delivery_thread_priority = 16, .delivery_thread_stack_size = 0, .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(250), .maximum_to_dequeue_per_period = 3 }; rtems_regulator_statistics stats; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(regulator != NULL); deliverer_logger_context.regulator = regulator; delivered_messages_reset(); // Ensure statistics show no buffers obtained or processed sc = rtems_regulator_get_statistics(regulator, &stats); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(stats.obtained == 0); rtems_test_assert(stats.released == 0); rtems_test_assert(stats.delivered == 0); rtems_test_assert(stats.period_statistics.count == 0); rtems_test_assert(stats.period_statistics.missed_count == 0); // Obtain a buffer which should change the statistics sc = rtems_regulator_obtain_buffer(regulator, &buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(buffer != NULL); // Ensure statistics show one buffer obtained sc = rtems_regulator_get_statistics(regulator, &stats); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(stats.obtained == 1); rtems_test_assert(stats.released == 0); rtems_test_assert(stats.delivered == 0); rtems_test_assert(stats.period_statistics.count == 0); rtems_test_assert(stats.period_statistics.missed_count == 0); // Format and send the message -- statistics do not change length = snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", 1024) + 1; strcpy(buffer, message); sc = rtems_regulator_send(regulator, buffer, length); rtems_test_assert(sc == RTEMS_SUCCESSFUL); // Ensure statistics show one buffer obtained sc = rtems_regulator_get_statistics(regulator, &stats); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(stats.obtained == 1); rtems_test_assert(stats.released == 0); rtems_test_assert(stats.delivered == 0); rtems_test_assert(stats.period_statistics.count == 0); rtems_test_assert(stats.period_statistics.missed_count == 0); // This is the actual failing case -- cannot delete w/outstanding sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE); // Now let the deliveries happen sleep(1); // Ensure statistics show all buffers released sc = rtems_regulator_get_statistics(regulator, &stats); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(stats.obtained == 1); rtems_test_assert(stats.released == 1); rtems_test_assert(stats.delivered == 1); rtems_test_assert(stats.period_statistics.count != 0); rtems_test_assert(stats.period_statistics.missed_count == 0); rtems_test_assert(delivered_message_count == 1); match = strncmp( delivered_messages[0].message, message, MAXIMUM_MESSAGE_LENGTH ); rtems_test_assert(match == 0); sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); deliverer_logger_context.regulator = NULL; } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_send and output thread delivers message * * This unit test verifies that when the regulator is * successfully initialized and used as expected, a message sent via * rtems_regulator_send() is delivered as expected. */ static void test_regulator_send_one_message_OK(void) { rtems_status_code sc; rtems_regulator_instance *regulator; char message[MAXIMUM_MESSAGE_LENGTH]; void *buffer; size_t length; int match; rtems_regulator_attributes attributes = { .deliverer = test_regulator_deliverer_logger, .deliverer_context = &deliverer_logger_context, .maximum_message_size = 16, .maximum_messages = 10, .delivery_thread_priority = 16, .delivery_thread_stack_size = 0, .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(250), .maximum_to_dequeue_per_period = 3 }; sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(regulator != NULL); deliverer_logger_context.regulator = regulator; delivered_messages_reset(); sc = rtems_regulator_obtain_buffer(regulator, &buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(buffer != NULL); length = snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", 1024) + 1; strcpy(buffer, message); sc = rtems_regulator_send(regulator, buffer, length); rtems_test_assert(sc == RTEMS_SUCCESSFUL); sleep(1); rtems_test_assert(delivered_message_count == 1); match = strncmp( delivered_messages[0].message, message, MAXIMUM_MESSAGE_LENGTH ); rtems_test_assert(match == 0); sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); deliverer_logger_context.regulator = NULL; } /** * @ingroup RegulatorTests * @brief Verify rtems_regulator_send and output thread delivers messages * * This unit test verifies that when the regulator is successfully initialized * and used as expected, and multiple messages are sent via rtems_regulator_send() * that they are delivered as expected. */ #include static void test_regulator_send_multiple_messages_OK(void) { rtems_status_code sc; rtems_regulator_instance *regulator; char message[MAXIMUM_MESSAGE_LENGTH]; void *buffer; size_t length; int match; int i; time_t base_time; time_t tmp_time; rtems_interval base_ticks; rtems_interval ticks; rtems_interval ticks_per_second; rtems_regulator_attributes attributes = { .deliverer = test_regulator_deliverer_logger, .deliverer_context = &deliverer_logger_context, .maximum_message_size = MAXIMUM_MESSAGE_LENGTH, .maximum_messages = 10, .delivery_thread_priority = 16, .delivery_thread_stack_size = 0, .delivery_thread_period = RTEMS_MILLISECONDS_TO_TICKS(1000), .maximum_to_dequeue_per_period = 2 }; delivered_messages_reset(); sc = rtems_regulator_create(&attributes, ®ulator); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(regulator != NULL); deliverer_logger_context.regulator = regulator; /* * Ensure the messages are sent on a second boundary to ensure the * output thread will process them as expected. */ tmp_time = time(NULL); do { base_time = time(NULL); } while (tmp_time == base_time); /** * Send five messages as a burst which will need to be smoothly sent at * the configured rate. */ for (i=1 ; i <= 5 ; i++) { sc = rtems_regulator_obtain_buffer(regulator, &buffer); rtems_test_assert(sc == RTEMS_SUCCESSFUL); rtems_test_assert(buffer != NULL); length = snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", i); strcpy(buffer, message); sc = rtems_regulator_send(regulator, buffer, length); rtems_test_assert(sc == RTEMS_SUCCESSFUL); } /* * Let the output thread executed and deliver the messages. */ sleep(5); /** * Ensure the five messages were delivered as follows: * * - deliver all 5 * - contents are "message N" where N is 1 to 5 * - message 1 and 2 delivered during the first second * - message 3 and 4 delivered during the second second * - message 5 delivered during the third second * - no further messages delivered */ rtems_test_assert(delivered_message_count == 5); for (i=0 ; i < 5 ; i++) { (void) snprintf(message, MAXIMUM_MESSAGE_LENGTH, "message %d", i+1); // printf("%d %s\n", i, delivered_messages[i].message); match = strncmp( delivered_messages[i].message, message, MAXIMUM_MESSAGE_LENGTH ); rtems_test_assert(match == 0); } /** * Verify that messages were delivered in the proper groups. Check that * the delivery time matches expectations. */ rtems_test_assert(delivered_messages[0].processed == delivered_messages[1].processed); rtems_test_assert(delivered_messages[1].processed != delivered_messages[2].processed); rtems_test_assert(delivered_messages[2].processed == delivered_messages[3].processed); rtems_test_assert(delivered_messages[3].processed != delivered_messages[4].processed); /** * Verify that the message groups were properly spaced temporally. They * should be one second apart. */ ticks_per_second = rtems_clock_get_ticks_per_second(); base_ticks = delivered_messages[1].processed; ticks = delivered_messages[2].processed; rtems_test_assert(ticks_per_second == ticks - base_ticks); base_ticks = delivered_messages[3].processed; ticks = delivered_messages[4].processed; rtems_test_assert(ticks_per_second == ticks - base_ticks); sc = rtems_regulator_delete(regulator, FIVE_SECONDS); rtems_test_assert(sc == RTEMS_SUCCESSFUL); deliverer_logger_context.regulator = NULL; } /* Necessary prototype */ rtems_task test_regulator(rtems_task_argument); /** * @ingroup RegulatorTestshttps://devel.rtems.org/milestone/6.1 * @brief Test entry task which invokes test cases */ rtems_task test_regulator(rtems_task_argument arg) { (void) arg; TEST_BEGIN(); malloc_trigger_reset(); test_regulator_create_max_dequeue_zero(); test_regulator_create_null_attributes(); test_regulator_create_null_regulator(); test_regulator_create_deliverer_is_null(); test_regulator_create_maximum_messages_is_zero(); test_regulator_create_maximum_message_size_is_zero(); test_regulator_create_maximum_to_dequeue_per_period_is_zero(); test_regulator_create_malloc_regulator_fails(); test_regulator_create_malloc_buffers_fails(); test_regulator_create_delivery_thread_priority_is_zero(); test_regulator_create_partition_create_fails(); test_regulator_create_message_queue_create_fails(); test_regulator_create_task_create_fails(); test_regulator_create_rate_monotonic_create_fails(); test_regulator_delete_null_regulator(); test_regulator_delete_uninitialized_regulator(); test_regulator_delete_OK(); test_regulator_obtain_buffer_null_regulator(); test_regulator_obtain_buffer_uninitialized_regulator(); test_regulator_obtain_buffer_OK(); test_regulator_release_buffer_null_regulator(); test_regulator_release_buffer_uninitialized_regulator(); test_regulator_release_buffer_OK(); test_regulator_send_null_regulator(); test_regulator_send_null_message(); test_regulator_send_length_is_zero(); test_regulator_send_uninitialized_regulator(); test_regulator_send_one_message_OK(); test_regulator_cannot_delete_with_outstanding(); test_regulator_send_multiple_messages_OK(); TEST_END(); rtems_test_exit(0); }