diff options
Diffstat (limited to 'testsuites/libtests/regulator01/regulator01.c')
-rw-r--r-- | testsuites/libtests/regulator01/regulator01.c | 1310 |
1 files changed, 1310 insertions, 0 deletions
diff --git a/testsuites/libtests/regulator01/regulator01.c b/testsuites/libtests/regulator01/regulator01.c new file mode 100644 index 0000000000..cc5af01223 --- /dev/null +++ b/testsuites/libtests/regulator01/regulator01.c @@ -0,0 +1,1310 @@ +/* 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 <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <rtems.h> +#include <rtems/test-info.h> +#include <tmacros.h> + +#include <rtems/regulator.h> + +/** + * @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 <stdio.h> +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); +} |