[PATCH 1/2] unit: Test POSIX-specific message queue impl
Sebastian Huber
sebastian.huber at embedded-brains.de
Thu Jul 20 13:40:01 UTC 2023
From: Frank Kühndel <frank.kuehndel at embedded-brains.de>
This unit test covers code paths of the Message Handler which are only
reached by through POSIX message queue API.
Update #3716.
---
.../build/testsuites/unit/unit-no-clock-0.yml | 1 +
testsuites/unit/tc-score-msgq.c | 452 ++++++++++++++++++
2 files changed, 453 insertions(+)
create mode 100644 testsuites/unit/tc-score-msgq.c
diff --git a/spec/build/testsuites/unit/unit-no-clock-0.yml b/spec/build/testsuites/unit/unit-no-clock-0.yml
index 57cd279a7a..517b84284d 100644
--- a/spec/build/testsuites/unit/unit-no-clock-0.yml
+++ b/spec/build/testsuites/unit/unit-no-clock-0.yml
@@ -12,6 +12,7 @@ ldflags: []
links: []
source:
- testsuites/unit/tc-misaligned-builtin-memcpy.c
+- testsuites/unit/tc-score-msgq.c
- testsuites/unit/tc-score-rbtree.c
- testsuites/unit/ts-unit-no-clock-0.c
stlib: []
diff --git a/testsuites/unit/tc-score-msgq.c b/testsuites/unit/tc-score-msgq.c
new file mode 100644
index 0000000000..c4baa6d53e
--- /dev/null
+++ b/testsuites/unit/tc-score-msgq.c
@@ -0,0 +1,452 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup ScoreMsgqUnitMsgq
+ */
+
+/*
+ * Copyright (C) 2021 embedded brains GmbH & Co. KG
+ *
+ * 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.
+ */
+
+/*
+ * This file is part of the RTEMS quality process and was automatically
+ * generated. If you find something that needs to be fixed or
+ * worded better please post a report or patch to an RTEMS mailing list
+ * or raise a bug report:
+ *
+ * https://www.rtems.org/bugs.html
+ *
+ * For information on updating and regenerating please refer to the How-To
+ * section in the Software Requirements Engineering chapter of the
+ * RTEMS Software Engineering manual. The manual is provided as a part of
+ * a release. For development sources please refer to the online
+ * documentation at:
+ *
+ * https://docs.rtems.org
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/rtems/messageimpl.h>
+#include <rtems/rtems/statusimpl.h>
+#include <rtems/score/coremsgimpl.h>
+
+#include "../validation/tx-support.h"
+
+#include <rtems/test.h>
+
+/**
+ * @defgroup ScoreMsgqUnitMsgq spec:/score/msgq/unit/msgq
+ *
+ * @ingroup TestsuitesUnitNoClock0
+ *
+ * @brief Unit tests for the Message Queue Handler.
+ *
+ * Parts of the files ``cpukit/score/src/coremsginsert.c``,
+ * ``cpukit/score/src/coremsgseize.c``, and
+ * ``cpukit/score/src/coremsgsubmit.c`` are only executed by the POSIX API.
+ * Currently, the pre-qualified subset of RTEMS does not contain the POSIX API.
+ * This test exercises the code parts otherwise only reached by the POSIX API
+ * to achieve full code coverage.
+ *
+ * This test case performs the following actions:
+ *
+ * - Use _CORE_message_queue_Insert_message() to insert two messages into a
+ * message queue and use the POSIX message priority to define their order in
+ * the queue.
+ *
+ * - Check that _CORE_message_queue_Submit() was executed successfully.
+ *
+ * - Check that the messages are in right order in the message queue.
+ *
+ * - Submit three messages into a message queue which can only store two and
+ * have the third submit() blocked till a seize() occurs.
+ *
+ * - Check that the third _CORE_message_queue_Submit() did actually block
+ * till there was room for the message in the message queue.
+ *
+ * - Submit messages in the queue from within an ISR.
+ *
+ * - Check that the first two messages were successfully send.
+ *
+ * - Check that trying to send the third message from ISR when the message
+ * queue was full was rejected.
+ *
+ * @{
+ */
+
+#define MAXIMUM_PENDING_MESSAGES 2
+#define MAXIMUM_MESSAGE_SIZE 3
+
+static void WorkerTask( rtems_task_argument argument );
+
+/**
+ * @brief Test context for spec:/score/msgq/unit/msgq test case.
+ */
+typedef struct {
+ /**
+ * @brief This member contains a valid ID of a message queue.
+ */
+ rtems_id message_queue_id;
+
+ /**
+ * @brief This member is used as storage area for the message queue.
+ */
+ RTEMS_MESSAGE_QUEUE_BUFFER( MAXIMUM_MESSAGE_SIZE )
+ storage_area[ MAXIMUM_PENDING_MESSAGES];
+
+ /**
+ * @brief This member contains the task identifier of the worker task.
+ */
+ rtems_id worker_id;
+
+ /**
+ * @brief This member indicated whether the worker task is currently sending
+ * a message (``true``) or whether it is waiting to receive an event
+ * (``false``)..
+ */
+ bool is_worker_working;
+
+ /**
+ * @brief This member contains the returned status code of the SendMessage()
+ * function.
+ */
+ rtems_status_code send_status;
+} ScoreMsgqUnitMsgq_Context;
+
+static ScoreMsgqUnitMsgq_Context
+ ScoreMsgqUnitMsgq_Instance;
+
+#define EVENT_SEND RTEMS_EVENT_17
+#define MESSAGE_CONTENT_LOW { 1, 2, 3 }
+#define MESSAGE_CONTENT_HIGH { 4, 5 }
+#define MESSAGE_PRIORITY_LOW 5
+#define MESSAGE_PRIORITY_HIGH 7
+#define DO_WAIT true
+
+typedef ScoreMsgqUnitMsgq_Context Context;
+
+/*
+ * This is a code fragment from rtems_message_queue_send() with the
+ * specialty that it uses a POSIX priority and the sender
+ * task will wait in case the queue is full.
+ */
+static rtems_status_code SubmitMessage(
+ rtems_id id,
+ uint8_t *message,
+ size_t message_size,
+ unsigned int posix_piority
+)
+{
+ rtems_status_code status;
+ Thread_queue_Context queue_context;
+ Message_queue_Control *the_message_queue;
+
+ T_assert_lt_uint( posix_piority, MQ_PRIO_MAX );
+
+ the_message_queue = _Message_queue_Get(
+ id,
+ &queue_context
+ );
+ T_assert_not_null( the_message_queue );
+
+ /* The next two calls are from _POSIX_Message_queue_Send_support() */
+ _Thread_queue_Context_set_enqueue_callout(
+ &queue_context,
+ _Thread_queue_Enqueue_do_nothing_extra
+ );
+ _Thread_queue_Context_set_timeout_argument( &queue_context, NULL, true );
+
+ _CORE_message_queue_Acquire_critical(
+ &the_message_queue->message_queue,
+ &queue_context
+ );
+
+ status = _CORE_message_queue_Submit(
+ &the_message_queue->message_queue,
+ _Thread_Executing,
+ message,
+ message_size,
+ (CORE_message_queue_Submit_types) ( posix_piority * -1 ),
+ DO_WAIT,
+ &queue_context
+ );
+
+ return _Status_Get( status );
+}
+
+static rtems_status_code ReceiveMessage(
+ rtems_id id,
+ void *buffer,
+ size_t *size
+)
+{
+ return rtems_message_queue_receive(
+ id,
+ buffer,
+ size,
+ RTEMS_LOCAL | RTEMS_NO_WAIT,
+ RTEMS_NO_TIMEOUT
+ );
+}
+
+static rtems_status_code ReceiveOneMessages( Context *ctx )
+{
+ uint8_t message_buffer[ MAXIMUM_MESSAGE_SIZE ];
+ size_t message_size;
+
+ return ReceiveMessage(
+ ctx->message_queue_id,
+ &message_buffer,
+ &message_size
+ );
+}
+
+static void SendMessage( Context *ctx )
+{
+ uint8_t message[] = { 100, 101, 102 };
+ ctx->send_status = SubmitMessage(
+ ctx->message_queue_id,
+ message,
+ sizeof( message ),
+ MESSAGE_PRIORITY_LOW
+ );
+}
+
+static void WorkerTask( rtems_task_argument argument )
+{
+ Context *ctx = (Context *) argument;
+
+ while ( true ) {
+ ctx->is_worker_working = false;
+ ReceiveAnyEvents();
+ ctx->is_worker_working = true;
+ SendMessage( ctx );
+ T_assert_rsc_success( ctx->send_status );
+ }
+}
+
+static void WorkerSendMessage( Context *ctx )
+{
+ SendEvents( ctx->worker_id, EVENT_SEND );
+}
+
+static void ScoreMsgqUnitMsgq_Setup( ScoreMsgqUnitMsgq_Context *ctx )
+{
+ rtems_status_code status;
+ rtems_message_queue_config config = {
+ .name = rtems_build_name( 'M', 'S', 'G', 'Q' ),
+ .maximum_pending_messages = MAXIMUM_PENDING_MESSAGES,
+ .maximum_message_size = MAXIMUM_MESSAGE_SIZE,
+ .storage_area = ctx->storage_area,
+ .storage_size = sizeof( ctx->storage_area ),
+ .storage_free = NULL,
+ .attributes = RTEMS_DEFAULT_ATTRIBUTES
+ };
+
+ status = rtems_message_queue_construct(
+ &config,
+ &ctx->message_queue_id
+ );
+ T_rsc_success( status );
+
+ SetSelfPriority( PRIO_NORMAL );
+
+ ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
+ StartTask( ctx->worker_id, WorkerTask, ctx );
+}
+
+static void ScoreMsgqUnitMsgq_Setup_Wrap( void *arg )
+{
+ ScoreMsgqUnitMsgq_Context *ctx;
+
+ ctx = arg;
+ ScoreMsgqUnitMsgq_Setup( ctx );
+}
+
+static void ScoreMsgqUnitMsgq_Teardown( ScoreMsgqUnitMsgq_Context *ctx )
+{
+ DeleteTask( ctx->worker_id );
+ RestoreRunnerPriority();
+ T_rsc_success( rtems_message_queue_delete( ctx->message_queue_id ) );
+}
+
+static void ScoreMsgqUnitMsgq_Teardown_Wrap( void *arg )
+{
+ ScoreMsgqUnitMsgq_Context *ctx;
+
+ ctx = arg;
+ ScoreMsgqUnitMsgq_Teardown( ctx );
+}
+
+static T_fixture ScoreMsgqUnitMsgq_Fixture = {
+ .setup = ScoreMsgqUnitMsgq_Setup_Wrap,
+ .stop = NULL,
+ .teardown = ScoreMsgqUnitMsgq_Teardown_Wrap,
+ .scope = NULL,
+ .initial_context = &ScoreMsgqUnitMsgq_Instance
+};
+
+/**
+ * @brief Use _CORE_message_queue_Insert_message() to insert two messages into
+ * a message queue and use the POSIX message priority to define their order
+ * in the queue.
+ */
+static void ScoreMsgqUnitMsgq_Action_0( ScoreMsgqUnitMsgq_Context *ctx )
+{
+ rtems_status_code status_submit_low;
+ rtems_status_code status_submit_high;
+ rtems_status_code status_receive_low;
+ rtems_status_code status_receive_high;
+ uint8_t message_low[] = MESSAGE_CONTENT_LOW;
+ uint8_t message_high[] = MESSAGE_CONTENT_HIGH;
+ uint8_t message_buffer_low[ MAXIMUM_MESSAGE_SIZE ];
+ uint8_t message_buffer_high[ MAXIMUM_MESSAGE_SIZE ];
+ size_t message_size_low;
+ size_t message_size_high;
+
+ status_submit_low = SubmitMessage(
+ ctx->message_queue_id,
+ message_low,
+ sizeof( message_low ),
+ MESSAGE_PRIORITY_LOW
+ );
+
+ status_submit_high = SubmitMessage(
+ ctx->message_queue_id,
+ message_high,
+ sizeof( message_high ),
+ MESSAGE_PRIORITY_HIGH
+ );
+
+ status_receive_high = ReceiveMessage(
+ ctx->message_queue_id,
+ &message_buffer_high,
+ &message_size_high
+ );
+
+ status_receive_low = ReceiveMessage(
+ ctx->message_queue_id,
+ &message_buffer_low,
+ &message_size_low
+ );
+
+ /*
+ * Check that _CORE_message_queue_Submit() was executed successfully.
+ */
+ T_rsc_success( status_submit_low );
+ T_rsc_success( status_submit_high );
+
+ /*
+ * Check that the messages are in right order in the message queue.
+ */
+ T_rsc_success( status_receive_high );
+ T_eq_sz( message_size_high, sizeof( message_high ) );
+ T_eq_mem( message_buffer_high, message_high, message_size_high );
+
+ T_rsc_success( status_receive_low );
+ T_eq_sz( message_size_low, sizeof( message_low ) );
+ T_eq_mem( message_buffer_low, message_low, message_size_low );
+}
+
+/**
+ * @brief Submit three messages into a message queue which can only store two
+ * and have the third submit() blocked till a seize() occurs.
+ */
+static void ScoreMsgqUnitMsgq_Action_1( ScoreMsgqUnitMsgq_Context *ctx )
+{
+ bool is_worker_blocked_after_third_send;
+ bool is_worker_blocked_after_first_receive;
+
+ WorkerSendMessage( ctx );
+ WorkerSendMessage( ctx );
+ WorkerSendMessage( ctx );
+ is_worker_blocked_after_third_send = ctx->is_worker_working;
+
+ T_rsc_success( ReceiveOneMessages( ctx ) );
+ is_worker_blocked_after_first_receive = ctx->is_worker_working;
+
+ T_rsc_success( ReceiveOneMessages( ctx ) );
+ T_rsc_success( ReceiveOneMessages( ctx ) );
+
+ /*
+ * Check that the third _CORE_message_queue_Submit() did actually block till
+ * there was room for the message in the message queue.
+ */
+ T_true( is_worker_blocked_after_third_send );
+ T_true( !is_worker_blocked_after_first_receive );
+}
+
+/**
+ * @brief Submit messages in the queue from within an ISR.
+ */
+static void ScoreMsgqUnitMsgq_Action_2( ScoreMsgqUnitMsgq_Context *ctx )
+{
+ rtems_status_code status_send_first_message;
+ rtems_status_code status_send_second_message;
+ rtems_status_code status_send_third_message;
+
+ CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
+ status_send_first_message = ctx->send_status;
+ CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
+ status_send_second_message = ctx->send_status;
+ CallWithinISR( ( void (*)(void*) ) SendMessage, ctx );
+ status_send_third_message = ctx->send_status;
+
+ T_rsc_success( ReceiveOneMessages( ctx ) );
+ T_rsc_success( ReceiveOneMessages( ctx ) );
+
+ /*
+ * Check that the first two messages were successfully send.
+ */
+ T_assert_rsc_success( status_send_first_message );
+ T_assert_rsc_success( status_send_second_message );
+
+ /*
+ * Check that trying to send the third message from ISR when the message
+ * queue was full was rejected.
+ */
+ T_rsc( status_send_third_message, STATUS_CLASSIC_INTERNAL_ERROR );
+}
+
+/**
+ * @fn void T_case_body_ScoreMsgqUnitMsgq( void )
+ */
+T_TEST_CASE_FIXTURE( ScoreMsgqUnitMsgq, &ScoreMsgqUnitMsgq_Fixture )
+{
+ ScoreMsgqUnitMsgq_Context *ctx;
+
+ ctx = T_fixture_context();
+
+ ScoreMsgqUnitMsgq_Action_0( ctx );
+ ScoreMsgqUnitMsgq_Action_1( ctx );
+ ScoreMsgqUnitMsgq_Action_2( ctx );
+}
+
+/** @} */
--
2.35.3
More information about the devel
mailing list