This is an automated email from the ASF dual-hosted git repository.
jerpelea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new f04aee601 testing/testsuites: Add a System V message queue test.
f04aee601 is described below
commit f04aee6015cb1fda8d33b768c57ccb344d0826b0
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Nov 4 12:08:42 2026 +0100
testing/testsuites: Add a System V message queue test.
No test in apps covers msgget(), msgsnd(), msgrcv() and msgctl(). Add
the cmocka test cmocka_msg_test (CONFIG_CM_MSG_TEST, needs System V
message queues and pthreads). It checks:
- msgget(IPC_PRIVATE) with and without IPC_CREAT. msgget() of a key
gives the same identifier again, and EEXIST with IPC_CREAT | IPC_EXCL.
More than 250 queues at the same time.
- msgrcv() with msgtyp 0, greater than 0 and less than 0 (ENOMSG with
IPC_NOWAIT when no type is <= |msgtyp|).
- MSG_NOERROR truncation, E2BIG (the message stays in the queue),
ENOMSG and EAGAIN with IPC_NOWAIT, and EINVAL.
- msgctl() IPC_STAT (all fields), IPC_SET (msg_qbytes in bytes) and
IPC_RMID.
- A blocked msgrcv() or msgsnd() returns when msgsnd() or msgrcv() of
another thread gives it a message or room, fails with EIDRM when the
queue is removed, and fails with EINTR when a signal interrupts it.
A message goes to the waiter of its type.
- msgsnd() with an empty message pool (CONFIG_PREALLOC_MQ_MSGS): EAGAIN
with IPC_NOWAIT, blocks until msgrcv() frees a message, EINTR, EIDRM.
The CMake rules of the suites are in kernel/CMakeLists.txt, which this
commit updates [skip-cmake-parity].
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
testing/testsuites/Kconfig | 8 +
testing/testsuites/Makefile | 8 +
testing/testsuites/kernel/CMakeLists.txt | 21 ++
testing/testsuites/kernel/msg/cases/msg_test_ctl.c | 168 +++++++++++++
testing/testsuites/kernel/msg/cases/msg_test_get.c | 152 ++++++++++++
.../testsuites/kernel/msg/cases/msg_test_pool.c | 186 ++++++++++++++
.../testsuites/kernel/msg/cases/msg_test_size.c | 161 ++++++++++++
.../testsuites/kernel/msg/cases/msg_test_type.c | 141 +++++++++++
.../testsuites/kernel/msg/cases/msg_test_wait.c | 275 +++++++++++++++++++++
testing/testsuites/kernel/msg/cmocka_msg_test.c | 77 ++++++
.../testsuites/kernel/msg/common/test_msg_common.c | 240 ++++++++++++++++++
testing/testsuites/kernel/msg/include/MsgTest.h | 145 +++++++++++
12 files changed, 1582 insertions(+)
diff --git a/testing/testsuites/Kconfig b/testing/testsuites/Kconfig
index 5c909505e..32559d89c 100644
--- a/testing/testsuites/Kconfig
+++ b/testing/testsuites/Kconfig
@@ -62,5 +62,13 @@ config CM_MUTEX_TEST
bool "enable mutex test"
default n
+config CM_MSG_TEST
+ bool "enable System V message queue test"
+ default n
+ depends on !DISABLE_MQUEUE_SYSV && !DISABLE_PTHREAD
+ depends on PREALLOC_MQ_MSGS >= 4 && MQ_MAXMSGSIZE >= 8
+ ---help---
+ Test msgget(), msgsnd(), msgrcv() and msgctl().
+
endmenu
endif # TESTS_TESTSUITES
diff --git a/testing/testsuites/Makefile b/testing/testsuites/Makefile
index ac63f2164..406dab545 100644
--- a/testing/testsuites/Makefile
+++ b/testing/testsuites/Makefile
@@ -86,6 +86,14 @@ PROGNAME += cmocka_socket_test
MAINSRC += $(CURDIR)/kernel/socket/cmocka_socket_test.c
endif
+ifneq ($(CONFIG_CM_MSG_TEST),)
+CFLAGS += -I$(CURDIR)/kernel/msg/include
+CSRCS += $(wildcard kernel/msg/cases/*.c)
+CSRCS += $(wildcard kernel/msg/common/*.c)
+PROGNAME += cmocka_msg_test
+MAINSRC += $(CURDIR)/kernel/msg/cmocka_msg_test.c
+endif
+
ifneq ($(CONFIG_CM_SYSCALL_TEST),)
CFLAGS += -I$(CURDIR)/kernel/syscall/include
CFLAGS += -I$(APPDIR)/nshlib
diff --git a/testing/testsuites/kernel/CMakeLists.txt
b/testing/testsuites/kernel/CMakeLists.txt
index ce7f042cb..03a6c24f3 100644
--- a/testing/testsuites/kernel/CMakeLists.txt
+++ b/testing/testsuites/kernel/CMakeLists.txt
@@ -211,3 +211,24 @@ if(CONFIG_CM_MUTEX_TEST)
DEPENDS
cmocka)
endif()
+
+if(CONFIG_CM_MSG_TEST)
+ set(INCDIR ${CMAKE_CURRENT_SOURCE_DIR}/msg/include
+ ${NUTTX_DIR}/../apps/testing/cmocka/include)
+ file(GLOB MSG_CSRCS ${CMAKE_CURRENT_SOURCE_DIR}/msg/cases/*.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/msg/common/*.c)
+ nuttx_add_application(
+ NAME
+ cmocka_msg_test
+ STACKSIZE
+ ${CONFIG_TESTS_TESTSUITES_STACKSIZE}
+ PRIORITY
+ ${CONFIG_TESTS_TESTSUITES_PRIORITY}
+ SRCS
+ msg/cmocka_msg_test.c
+ ${MSG_CSRCS}
+ INCLUDE_DIRECTORIES
+ ${INCDIR}
+ DEPENDS
+ cmocka)
+endif()
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
b/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
new file mode 100644
index 000000000..737ea1b4f
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
@@ -0,0 +1,168 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_ctl.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_stat
+ *
+ * Description:
+ * IPC_STAT gives the number of messages and the size limit of the queue.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_stat(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ struct msqid_ds ds;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ memset(&ds, 0xff, sizeof(ds));
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+ assert_int_equal(ds.msg_qnum, 0);
+ assert_true(ds.msg_qbytes >= MSG_TEST_MAXSIZE);
+
+ assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+ assert_int_equal(msg_test_qnum(id), 2);
+
+ assert_int_equal(msg_test_recv(id, &buf, 1, 0, 0), 1);
+ assert_int_equal(msg_test_qnum(id), 1);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_fields
+ *
+ * Description:
+ * IPC_STAT gives the permissions, the process IDs and the times of the
+ * last msgsnd() and msgrcv().
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_fields(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ struct msqid_ds ds;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0640);
+ assert_true(id >= 0);
+
+ memset(&ds, 0xff, sizeof(ds));
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+ assert_int_equal(ds.msg_perm.mode & 0777, 0640);
+ assert_int_equal(ds.msg_lspid, 0);
+ assert_int_equal(ds.msg_lrpid, 0);
+ assert_int_equal(ds.msg_stime, 0);
+ assert_int_equal(ds.msg_rtime, 0);
+ assert_true(ds.msg_ctime > 0);
+
+ assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+ memset(&ds, 0xff, sizeof(ds));
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+ assert_int_equal(ds.msg_lspid, getpid());
+ assert_true(ds.msg_stime > 0);
+
+ assert_int_equal(msg_test_recv(id, &buf, 1, 0, 0), 1);
+ memset(&ds, 0xff, sizeof(ds));
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+ assert_int_equal(ds.msg_lrpid, getpid());
+ assert_true(ds.msg_rtime > 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_set
+ *
+ * Description:
+ * IPC_SET changes msg_qbytes, and IPC_STAT gives the new value.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_set(FAR void **state)
+{
+ struct msqid_ds ds;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_set_qbytes(id, 3 * MSG_TEST_MAXSIZE), 0);
+ memset(&ds, 0, sizeof(ds));
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+ assert_int_equal(ds.msg_qbytes, 3 * MSG_TEST_MAXSIZE);
+
+ assert_int_equal(msg_test_set_qbytes(id, MSG_TEST_MAXSIZE + 1), 0);
+ memset(&ds, 0, sizeof(ds));
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), 0);
+ assert_int_equal(ds.msg_qbytes, MSG_TEST_MAXSIZE + 1);
+
+ assert_int_equal(msgctl(id, IPC_SET, NULL), -1);
+ assert_int_equal(errno, EFAULT);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_ctl_rmid
+ *
+ * Description:
+ * IPC_RMID removes the queue and its messages; the identifier is then
+ * not valid.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_ctl_rmid(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ struct msqid_ds ds;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+ assert_int_equal(msg_test_remove(id), 0);
+
+ assert_int_equal(msgctl(id, IPC_STAT, &ds), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msgctl(id, IPC_RMID, NULL), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msg_test_send(id, 1, "a", 1, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msg_test_recv(id, &buf, 1, 0, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_get.c
b/testing/testsuites/kernel/msg/cases/msg_test_get.c
new file mode 100644
index 000000000..ef9fca853
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_get.c
@@ -0,0 +1,152 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_get.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_get_private
+ *
+ * Description:
+ * IPC_PRIVATE always creates a new queue, also without IPC_CREAT.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_get_private(FAR void **state)
+{
+ struct msqid_ds ds;
+ int id1;
+ int id2;
+
+ id1 = msg_test_create(IPC_PRIVATE, IPC_CREAT | 0600);
+ assert_true(id1 >= 0);
+
+ id2 = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id2 >= 0);
+ assert_int_not_equal(id1, id2);
+
+ assert_int_equal(msg_test_remove(id1), 0);
+ assert_int_equal(msgctl(id1, IPC_STAT, &ds), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msg_test_qnum(id2), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_get_key
+ *
+ * Description:
+ * msgget() of a key: ENOENT before IPC_CREAT, then the same identifier,
+ * and EEXIST with IPC_CREAT | IPC_EXCL.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_get_key(FAR void **state)
+{
+ int id;
+
+ assert_int_equal(msgget(MSG_TEST_KEY, 0600), -1);
+ assert_int_equal(errno, ENOENT);
+
+ id = msg_test_create(MSG_TEST_KEY, IPC_CREAT | 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msgget(MSG_TEST_KEY, 0600), id);
+ assert_int_equal(msg_test_create(MSG_TEST_KEY, IPC_CREAT | 0600), id);
+
+ assert_int_equal(msg_test_create(MSG_TEST_KEY,
+ IPC_CREAT | IPC_EXCL | 0600), -1);
+ assert_int_equal(errno, EEXIST);
+
+ assert_int_equal(msg_test_remove(id), 0);
+ assert_int_equal(msgget(MSG_TEST_KEY, 0600), -1);
+ assert_int_equal(errno, ENOENT);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_get_many
+ *
+ * Description:
+ * More than 250 queues at the same time: each one has its own
+ * identifier, and msgctl() finds each one. Skipped when the kernel heap
+ * is too small for them.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_get_many(FAR void **state)
+{
+ static int ids[MSG_TEST_NMANY];
+ struct msqid_ds ds;
+ int nfound = 0;
+ int ndup = 0;
+ int n;
+ int i;
+ int j;
+
+ for (n = 0; n < MSG_TEST_NMANY; n++)
+ {
+ ids[n] = msgget(IPC_PRIVATE, 0600);
+ if (ids[n] < 0)
+ {
+ break;
+ }
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ if (msgctl(ids[i], IPC_STAT, &ds) == 0)
+ {
+ nfound++;
+ }
+
+ for (j = 0; j < i; j++)
+ {
+ if (ids[j] == ids[i])
+ {
+ ndup++;
+ }
+ }
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ msgctl(ids[i], IPC_RMID, NULL);
+ }
+
+ if (n < MSG_TEST_NMANY)
+ {
+ skip();
+ }
+
+ assert_int_equal(nfound, MSG_TEST_NMANY);
+ assert_int_equal(ndup, 0);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_pool.c
b/testing/testsuites/kernel/msg/cases/msg_test_pool.c
new file mode 100644
index 000000000..29d31beca
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_pool.c
@@ -0,0 +1,186 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_pool.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct msg_test_waiter_s g_msg_test_poolwaiter;
+static volatile int g_msg_test_poolsig;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void msg_test_poolhandler(int signo)
+{
+ g_msg_test_poolsig++;
+}
+
+/* Take all CONFIG_PREALLOC_MQ_MSGS messages of the system-wide pool: they
+ * stay in the queue *full. Return the identifier of a second, empty queue.
+ */
+
+static int msg_test_fill_pool(FAR int *full)
+{
+ int id;
+ int i;
+
+ *full = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(*full >= 0);
+ assert_int_equal(msg_test_set_qbytes(*full, CONFIG_PREALLOC_MQ_MSGS *
+ MSG_TEST_MAXSIZE), 0);
+
+ for (i = 0; i < CONFIG_PREALLOC_MQ_MSGS; i++)
+ {
+ assert_int_equal(msg_test_send(*full, 1, "p", 1, IPC_NOWAIT), 0);
+ }
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+ return id;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_nowait
+ *
+ * Description:
+ * No free message in the system: msgsnd() with IPC_NOWAIT gives EAGAIN.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_nowait(FAR void **state)
+{
+ int full;
+ int id;
+
+ id = msg_test_fill_pool(&full);
+ assert_int_equal(msg_test_send(id, 1, "a", 1, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EAGAIN);
+ assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_wait
+ *
+ * Description:
+ * No free message in the system: msgsnd() blocks until msgrcv() of
+ * another queue frees a message.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_wait(FAR void **state)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_poolwaiter;
+ struct msg_test_buf_s buf;
+ int full;
+ int id;
+
+ id = msg_test_fill_pool(&full);
+ assert_int_equal(msg_test_qnum(full), CONFIG_PREALLOC_MQ_MSGS);
+
+ msg_test_start(w, id, true, 1);
+ assert_false(w->done);
+
+ assert_int_equal(msg_test_recv(full, &buf, 1, 0, 0), 1);
+ assert_true(msg_test_finish(w));
+ assert_int_equal(w->ret, 0);
+ assert_int_equal(msg_test_qnum(id), 1);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_eintr
+ *
+ * Description:
+ * A signal interrupts a thread that waits in msgsnd() for a free
+ * message: EINTR.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_eintr(FAR void **state)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_poolwaiter;
+ struct sigaction act;
+ struct sigaction old;
+ int full;
+ int id;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = msg_test_poolhandler;
+ sigemptyset(&act.sa_mask);
+ assert_int_equal(sigaction(SIGUSR1, &act, &old), 0);
+
+ id = msg_test_fill_pool(&full);
+ g_msg_test_poolsig = 0;
+ msg_test_start(w, id, true, 1);
+ assert_false(w->done);
+
+ assert_int_equal(pthread_kill(w->thread, SIGUSR1), 0);
+ assert_true(msg_test_finish(w));
+ sigaction(SIGUSR1, &old, NULL);
+
+ assert_int_equal(g_msg_test_poolsig, 1);
+ assert_int_equal(w->ret, -1);
+ assert_int_equal(w->err, EINTR);
+ assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_pool_eidrm
+ *
+ * Description:
+ * IPC_RMID of the queue of a thread that waits in msgsnd() for a free
+ * message: EIDRM, while the pool stays empty.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_pool_eidrm(FAR void **state)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_poolwaiter;
+ int full;
+ int id;
+
+ id = msg_test_fill_pool(&full);
+ msg_test_start(w, id, true, 1);
+ assert_false(w->done);
+
+ assert_int_equal(msg_test_remove(id), 0);
+ assert_true(msg_test_finish(w));
+ assert_int_equal(w->ret, -1);
+ assert_int_equal(w->err, EIDRM);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_size.c
b/testing/testsuites/kernel/msg/cases/msg_test_size.c
new file mode 100644
index 000000000..7ba8d5e2a
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_size.c
@@ -0,0 +1,161 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_size.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_noerror
+ *
+ * Description:
+ * MSG_NOERROR truncates a message that is longer than msgsz.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_noerror(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 1, "abcdefgh", 8, 0), 0);
+ assert_int_equal(msg_test_recv(id, &buf, 4, 0, MSG_NOERROR), 4);
+ assert_int_equal(buf.mtype, 1);
+ assert_memory_equal(buf.mtext, "abcd", 4);
+ assert_int_equal(buf.mtext[4], 0);
+ assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_e2big
+ *
+ * Description:
+ * Without MSG_NOERROR, a message longer than msgsz gives E2BIG and stays
+ * in the queue. A message that fits is received, also with a small
+ * msgsz.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_e2big(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 1, "abcdefgh", 8, 0), 0);
+
+ assert_int_equal(msg_test_recv(id, &buf, 4, 0, 0), -1);
+ assert_int_equal(errno, E2BIG);
+ assert_int_equal(msg_test_recv(id, &buf, 7, 0, IPC_NOWAIT), -1);
+ assert_int_equal(errno, E2BIG);
+ assert_int_equal(msg_test_qnum(id), 1);
+
+ assert_int_equal(msg_test_recv(id, &buf, 8, 0, 0), 8);
+ assert_memory_equal(buf.mtext, "abcdefgh", 8);
+
+ assert_int_equal(msg_test_send(id, 1, "ab", 2, 0), 0);
+ assert_int_equal(msg_test_recv(id, &buf, 2, 0, 0), 2);
+ assert_memory_equal(buf.mtext, "ab", 2);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_nowait
+ *
+ * Description:
+ * IPC_NOWAIT: msgrcv() of an empty queue gives ENOMSG, and msgsnd() to a
+ * full queue gives EAGAIN.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_nowait(FAR void **state)
+{
+ char text[MSG_TEST_MAXSIZE];
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 0,
+ IPC_NOWAIT), -1);
+ assert_int_equal(errno, ENOMSG);
+
+ /* Room for two messages of the maximum size */
+
+ assert_int_equal(msg_test_set_qbytes(id, 2 * MSG_TEST_MAXSIZE), 0);
+
+ memset(text, 'x', sizeof(text));
+ assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), 0);
+ assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), 0);
+ assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), -1);
+ assert_int_equal(errno, EAGAIN);
+ assert_int_equal(msg_test_qnum(id), 2);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_einval
+ *
+ * Description:
+ * EINVAL: a type less than 1, a message that is too long, and a queue
+ * identifier that is not valid.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_einval(FAR void **state)
+{
+ char text[MSG_TEST_MAXSIZE + 1];
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 0, "a", 1, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msg_test_send(id, -1, "a", 1, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+ memset(text, 'x', sizeof(text));
+ assert_int_equal(msg_test_send(id, 1, text, sizeof(text), IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msg_test_qnum(id), 0);
+
+ assert_int_equal(msg_test_send(-1, 1, "a", 1, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+ assert_int_equal(msg_test_recv(-1, &buf, 1, 0, IPC_NOWAIT), -1);
+ assert_int_equal(errno, EINVAL);
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_type.c
b/testing/testsuites/kernel/msg/cases/msg_test_type.c
new file mode 100644
index 000000000..f23ab4c14
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_type.c
@@ -0,0 +1,141 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_type.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Receive one message and check its type and its one-byte text */
+
+static void msg_test_expect(int msqid, long msgtyp, long mtype, char text)
+{
+ struct msg_test_buf_s buf;
+
+ assert_int_equal(msg_test_recv(msqid, &buf, MSG_TEST_MAXSIZE, msgtyp,
+ IPC_NOWAIT), 1);
+ assert_int_equal(buf.mtype, mtype);
+ assert_int_equal(buf.mtext[0], text);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_type_zero
+ *
+ * Description:
+ * msgtyp 0 receives the messages in the order of msgsnd().
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_type_zero(FAR void **state)
+{
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 3, "a", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 1, "b", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 2, "c", 1, 0), 0);
+ assert_int_equal(msg_test_qnum(id), 3);
+
+ msg_test_expect(id, 0, 3, 'a');
+ msg_test_expect(id, 0, 1, 'b');
+ msg_test_expect(id, 0, 2, 'c');
+ assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_type_positive
+ *
+ * Description:
+ * msgtyp > 0 receives the first message of that type.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_type_positive(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 1, "c", 1, 0), 0);
+
+ msg_test_expect(id, 2, 2, 'b');
+ msg_test_expect(id, 1, 1, 'a');
+ msg_test_expect(id, 1, 1, 'c');
+
+ assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 1,
+ IPC_NOWAIT), -1);
+ assert_int_equal(errno, ENOMSG);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_type_negative
+ *
+ * Description:
+ * msgtyp < 0 receives the first message of the lowest type that is less
+ * than or equal to the absolute value of msgtyp.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_type_negative(FAR void **state)
+{
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+
+ assert_int_equal(msg_test_send(id, 3, "a", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 1, "c", 1, 0), 0);
+ assert_int_equal(msg_test_send(id, 1, "d", 1, 0), 0);
+
+ msg_test_expect(id, -2, 1, 'c');
+ msg_test_expect(id, -2, 1, 'd');
+ msg_test_expect(id, -2, 2, 'b');
+
+ /* Only type 3 is left: no message of type 2 or less */
+
+ assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, -2,
+ IPC_NOWAIT), -1);
+ assert_int_equal(errno, ENOMSG);
+
+ msg_test_expect(id, -3, 3, 'a');
+}
diff --git a/testing/testsuites/kernel/msg/cases/msg_test_wait.c
b/testing/testsuites/kernel/msg/cases/msg_test_wait.c
new file mode 100644
index 000000000..c5acd45fc
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cases/msg_test_wait.c
@@ -0,0 +1,275 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cases/msg_test_wait.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct msg_test_waiter_s g_msg_test_waiter;
+static struct msg_test_waiter_s g_msg_test_waiter2;
+static volatile int g_msg_test_nsig;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void msg_test_sighandler(int signo)
+{
+ g_msg_test_nsig++;
+}
+
+/* A new queue with room for one message of the maximum size; full is true:
+ * the queue has one message of type 1.
+ */
+
+static int msg_test_queue(bool full)
+{
+ char text[MSG_TEST_MAXSIZE];
+ int id;
+
+ id = msg_test_create(IPC_PRIVATE, 0600);
+ assert_true(id >= 0);
+ assert_int_equal(msg_test_set_qbytes(id, MSG_TEST_MAXSIZE), 0);
+
+ if (full)
+ {
+ memset(text, 'x', sizeof(text));
+ assert_int_equal(msg_test_send(id, 1, text, sizeof(text),
+ IPC_NOWAIT), 0);
+ assert_int_equal(msg_test_send(id, 1, text, sizeof(text),
+ IPC_NOWAIT), -1);
+ assert_int_equal(errno, EAGAIN);
+ }
+
+ return id;
+}
+
+/* A signal to a thread blocked in msgsnd() or msgrcv(): EINTR */
+
+static void msg_test_eintr(bool snd)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+ struct sigaction act;
+ struct sigaction old;
+ int id;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = msg_test_sighandler;
+ sigemptyset(&act.sa_mask);
+ assert_int_equal(sigaction(SIGUSR1, &act, &old), 0);
+
+ id = msg_test_queue(snd);
+ g_msg_test_nsig = 0;
+ msg_test_start(w, id, snd, 1);
+ assert_false(w->done);
+
+ assert_int_equal(pthread_kill(w->thread, SIGUSR1), 0);
+ assert_true(msg_test_finish(w));
+ sigaction(SIGUSR1, &old, NULL);
+
+ assert_int_equal(g_msg_test_nsig, 1);
+ assert_int_equal(w->ret, -1);
+ assert_int_equal(w->err, EINTR);
+ assert_int_equal(msg_test_qnum(id), snd ? 1 : 0);
+}
+
+/* IPC_RMID of the queue of a thread blocked in msgsnd() or msgrcv() */
+
+static void msg_test_eidrm(bool snd)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+ int id;
+
+ id = msg_test_queue(snd);
+ msg_test_start(w, id, snd, 1);
+ assert_false(w->done);
+
+ assert_int_equal(msg_test_remove(id), 0);
+ assert_true(msg_test_finish(w));
+ assert_int_equal(w->ret, -1);
+ assert_int_equal(w->err, EIDRM);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: test_nuttx_msg_wait_rcv
+ *
+ * Description:
+ * A thread blocked in msgrcv() of type 2 stays blocked after a message of
+ * type 1, and receives the next message of type 2.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_wait_rcv(FAR void **state)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+ int id;
+
+ id = msg_test_queue(false);
+ assert_int_equal(msg_test_set_qbytes(id, 2 * MSG_TEST_MAXSIZE), 0);
+ msg_test_start(w, id, false, 2);
+ assert_false(w->done);
+
+ assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+ usleep(100000);
+ assert_false(w->done);
+
+ assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+ assert_true(msg_test_finish(w));
+ assert_int_equal(w->ret, 1);
+ assert_int_equal(w->buf.mtype, 2);
+ assert_int_equal(w->buf.mtext[0], 'b');
+ assert_int_equal(msg_test_qnum(id), 1);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_wait_types
+ *
+ * Description:
+ * Two threads block in msgrcv(): the first for type 2, the second for
+ * type 1. A message of type 1 goes to the second thread.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_wait_types(FAR void **state)
+{
+ FAR struct msg_test_waiter_s *w1 = &g_msg_test_waiter;
+ FAR struct msg_test_waiter_s *w2 = &g_msg_test_waiter2;
+ int id;
+
+ id = msg_test_queue(false);
+ assert_int_equal(msg_test_set_qbytes(id, 2 * MSG_TEST_MAXSIZE), 0);
+ msg_test_start(w1, id, false, 2);
+ msg_test_start(w2, id, false, 1);
+ assert_false(w1->done);
+ assert_false(w2->done);
+
+ assert_int_equal(msg_test_send(id, 1, "a", 1, 0), 0);
+ assert_true(msg_test_finish(w2));
+ assert_int_equal(w2->ret, 1);
+ assert_int_equal(w2->buf.mtype, 1);
+ assert_false(w1->done);
+
+ assert_int_equal(msg_test_send(id, 2, "b", 1, 0), 0);
+ assert_true(msg_test_finish(w1));
+ assert_int_equal(w1->ret, 1);
+ assert_int_equal(w1->buf.mtype, 2);
+ assert_int_equal(msg_test_qnum(id), 0);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_wait_snd
+ *
+ * Description:
+ * A thread blocked in msgsnd() of a full queue sends its message after
+ * msgrcv() makes room.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_wait_snd(FAR void **state)
+{
+ FAR struct msg_test_waiter_s *w = &g_msg_test_waiter;
+ struct msg_test_buf_s buf;
+ int id;
+
+ id = msg_test_queue(true);
+ msg_test_start(w, id, true, 2);
+ assert_false(w->done);
+
+ assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 0, 0),
+ MSG_TEST_MAXSIZE);
+ assert_int_equal(buf.mtype, 1);
+ assert_true(msg_test_finish(w));
+ assert_int_equal(w->ret, 0);
+
+ assert_int_equal(msg_test_recv(id, &buf, MSG_TEST_MAXSIZE, 0,
+ IPC_NOWAIT), MSG_TEST_MAXSIZE);
+ assert_int_equal(buf.mtype, 2);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eidrm_rcv
+ *
+ * Description:
+ * IPC_RMID wakes up a thread blocked in msgrcv(): EIDRM.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eidrm_rcv(FAR void **state)
+{
+ msg_test_eidrm(false);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eidrm_snd
+ *
+ * Description:
+ * IPC_RMID wakes up a thread blocked in msgsnd(): EIDRM.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eidrm_snd(FAR void **state)
+{
+ msg_test_eidrm(true);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eintr_rcv
+ *
+ * Description:
+ * A signal interrupts a thread blocked in msgrcv(): EINTR.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eintr_rcv(FAR void **state)
+{
+ msg_test_eintr(false);
+}
+
+/****************************************************************************
+ * Name: test_nuttx_msg_eintr_snd
+ *
+ * Description:
+ * A signal interrupts a thread blocked in msgsnd(): EINTR.
+ *
+ ****************************************************************************/
+
+void test_nuttx_msg_eintr_snd(FAR void **state)
+{
+ msg_test_eintr(true);
+}
diff --git a/testing/testsuites/kernel/msg/cmocka_msg_test.c
b/testing/testsuites/kernel/msg/cmocka_msg_test.c
new file mode 100644
index 000000000..93cc60062
--- /dev/null
+++ b/testing/testsuites/kernel/msg/cmocka_msg_test.c
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/cmocka_msg_test.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MSG_TEST(f) cmocka_unit_test_setup_teardown(f, NULL, msg_test_teardown)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+ const struct CMUnitTest nuttx_msg_test_suites[] =
+ {
+ MSG_TEST(test_nuttx_msg_get_private),
+ MSG_TEST(test_nuttx_msg_get_key),
+ MSG_TEST(test_nuttx_msg_type_zero),
+ MSG_TEST(test_nuttx_msg_type_positive),
+ MSG_TEST(test_nuttx_msg_type_negative),
+ MSG_TEST(test_nuttx_msg_noerror),
+ MSG_TEST(test_nuttx_msg_e2big),
+ MSG_TEST(test_nuttx_msg_nowait),
+ MSG_TEST(test_nuttx_msg_einval),
+ MSG_TEST(test_nuttx_msg_ctl_stat),
+ MSG_TEST(test_nuttx_msg_ctl_fields),
+ MSG_TEST(test_nuttx_msg_ctl_set),
+ MSG_TEST(test_nuttx_msg_ctl_rmid),
+ MSG_TEST(test_nuttx_msg_wait_rcv),
+ MSG_TEST(test_nuttx_msg_wait_types),
+ MSG_TEST(test_nuttx_msg_wait_snd),
+ MSG_TEST(test_nuttx_msg_eidrm_rcv),
+ MSG_TEST(test_nuttx_msg_eidrm_snd),
+ MSG_TEST(test_nuttx_msg_eintr_rcv),
+ MSG_TEST(test_nuttx_msg_eintr_snd),
+ MSG_TEST(test_nuttx_msg_pool_nowait),
+ MSG_TEST(test_nuttx_msg_pool_wait),
+ MSG_TEST(test_nuttx_msg_pool_eintr),
+ MSG_TEST(test_nuttx_msg_pool_eidrm),
+ MSG_TEST(test_nuttx_msg_get_many),
+ };
+
+ return cmocka_run_group_tests(nuttx_msg_test_suites, NULL, NULL);
+}
diff --git a/testing/testsuites/kernel/msg/common/test_msg_common.c
b/testing/testsuites/kernel/msg/common/test_msg_common.c
new file mode 100644
index 000000000..51de9121b
--- /dev/null
+++ b/testing/testsuites/kernel/msg/common/test_msg_common.c
@@ -0,0 +1,240 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/common/test_msg_common.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "MsgTest.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MSG_TEST_NQUEUES 8
+#define MSG_TEST_NWAITERS 4
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int g_msg_test_ids[MSG_TEST_NQUEUES];
+static int g_msg_test_nids;
+static FAR struct msg_test_waiter_s *g_msg_test_waiters[MSG_TEST_NWAITERS];
+static int g_msg_test_nwaiters;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static FAR void *msg_test_waiter(FAR void *arg)
+{
+ FAR struct msg_test_waiter_s *w = arg;
+
+ errno = 0;
+ if (w->snd)
+ {
+ w->buf.mtype = w->mtype;
+ w->ret = msgsnd(w->msqid, &w->buf, MSG_TEST_MAXSIZE, 0);
+ }
+ else
+ {
+ w->ret = msgrcv(w->msqid, &w->buf, MSG_TEST_MAXSIZE, w->mtype, 0);
+ }
+
+ w->err = w->ret < 0 ? errno : 0;
+ w->done = true;
+ return NULL;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* msgget() that remembers the queue, so that the teardown removes it */
+
+int msg_test_create(key_t key, int msgflg)
+{
+ int msqid;
+
+ msqid = msgget(key, msgflg);
+ if (msqid >= 0 && g_msg_test_nids < MSG_TEST_NQUEUES)
+ {
+ g_msg_test_ids[g_msg_test_nids++] = msqid;
+ }
+
+ return msqid;
+}
+
+int msg_test_remove(int msqid)
+{
+ int i;
+
+ for (i = 0; i < g_msg_test_nids; i++)
+ {
+ if (g_msg_test_ids[i] == msqid)
+ {
+ g_msg_test_ids[i] = g_msg_test_ids[--g_msg_test_nids];
+ break;
+ }
+ }
+
+ return msgctl(msqid, IPC_RMID, NULL);
+}
+
+int msg_test_send(int msqid, long mtype, FAR const char *text, size_t len,
+ int msgflg)
+{
+ struct msg_test_buf_s buf;
+
+ memset(&buf, 0, sizeof(buf));
+ buf.mtype = mtype;
+ memcpy(buf.mtext, text, len);
+ return msgsnd(msqid, &buf, len, msgflg);
+}
+
+ssize_t msg_test_recv(int msqid, FAR struct msg_test_buf_s *buf,
+ size_t len, long mtype, int msgflg)
+{
+ memset(buf, 0, sizeof(*buf));
+ return msgrcv(msqid, buf, len, mtype, msgflg);
+}
+
+long msg_test_qnum(int msqid)
+{
+ struct msqid_ds ds;
+
+ memset(&ds, 0, sizeof(ds));
+ if (msgctl(msqid, IPC_STAT, &ds) < 0)
+ {
+ return -1;
+ }
+
+ return ds.msg_qnum;
+}
+
+int msg_test_set_qbytes(int msqid, size_t qbytes)
+{
+ struct msqid_ds ds;
+ int ret;
+
+ memset(&ds, 0, sizeof(ds));
+ ret = msgctl(msqid, IPC_STAT, &ds);
+ if (ret == 0)
+ {
+ ds.msg_qbytes = qbytes;
+ ret = msgctl(msqid, IPC_SET, &ds);
+ }
+
+ return ret;
+}
+
+/* Start a thread with a higher priority than the caller that blocks in
+ * msgsnd() (snd true) or msgrcv() of msqid, and give it time to block.
+ */
+
+void msg_test_start(FAR struct msg_test_waiter_s *w, int msqid, bool snd,
+ long mtype)
+{
+ struct sched_param param;
+ pthread_attr_t attr;
+ int policy;
+ int ret;
+
+ memset(w, 0, sizeof(*w));
+ w->msqid = msqid;
+ w->snd = snd;
+ w->mtype = mtype;
+ w->ret = -2;
+
+ ret = pthread_getschedparam(pthread_self(), &policy, ¶m);
+ assert_int_equal(ret, 0);
+ if (param.sched_priority < sched_get_priority_max(SCHED_FIFO))
+ {
+ param.sched_priority++;
+ }
+
+ pthread_attr_init(&attr);
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+ pthread_attr_setschedparam(&attr, ¶m);
+ ret = pthread_create(&w->thread, &attr, msg_test_waiter, w);
+ pthread_attr_destroy(&attr);
+ assert_int_equal(ret, 0);
+
+ if (g_msg_test_nwaiters < MSG_TEST_NWAITERS)
+ {
+ g_msg_test_waiters[g_msg_test_nwaiters++] = w;
+ }
+
+ usleep(100000);
+}
+
+/* Wait up to 3 seconds for the waiter to return and join it; false if it
+ * is still blocked.
+ */
+
+bool msg_test_finish(FAR struct msg_test_waiter_s *w)
+{
+ int i;
+
+ for (i = 0; i < 300 && !w->done; i++)
+ {
+ usleep(10000);
+ }
+
+ if (w->done && !w->joined)
+ {
+ pthread_join(w->thread, NULL);
+ w->joined = true;
+ }
+
+ return w->done;
+}
+
+/* Remove the queues of the test case; this also wakes up its waiters */
+
+int msg_test_teardown(FAR void **state)
+{
+ int i;
+
+ while (g_msg_test_nids > 0)
+ {
+ msg_test_remove(g_msg_test_ids[0]);
+ }
+
+ for (i = 0; i < g_msg_test_nwaiters; i++)
+ {
+ msg_test_finish(g_msg_test_waiters[i]);
+ }
+
+ g_msg_test_nwaiters = 0;
+ return 0;
+}
diff --git a/testing/testsuites/kernel/msg/include/MsgTest.h
b/testing/testsuites/kernel/msg/include/MsgTest.h
new file mode 100644
index 000000000..e99673333
--- /dev/null
+++ b/testing/testsuites/kernel/msg/include/MsgTest.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * apps/testing/testsuites/kernel/msg/include/MsgTest.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you 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 __APPS_TESTING_TESTSUITES_KERNEL_MSG_INCLUDE_MSGTEST_H
+#define __APPS_TESTING_TESTSUITES_KERNEL_MSG_INCLUDE_MSGTEST_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* The largest message that msgsnd() accepts */
+
+#define MSG_TEST_MAXSIZE CONFIG_MQ_MAXMSGSIZE
+
+/* The key of the queue in the msgget() test */
+
+#define MSG_TEST_KEY ((key_t)0x4d534754)
+
+/* The number of queues in the test of many queues */
+
+#define MSG_TEST_NMANY 260
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct msg_test_buf_s
+{
+ long mtype;
+ char mtext[MSG_TEST_MAXSIZE + 1];
+};
+
+/* A thread that blocks in msgsnd() or msgrcv() */
+
+struct msg_test_waiter_s
+{
+ pthread_t thread;
+ int msqid;
+ bool snd;
+ long mtype;
+ volatile bool done;
+ bool joined;
+ ssize_t ret;
+ int err;
+ struct msg_test_buf_s buf;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* common/test_msg_common.c *************************************************/
+
+int msg_test_create(key_t key, int msgflg);
+int msg_test_remove(int msqid);
+int msg_test_send(int msqid, long mtype, FAR const char *text, size_t len,
+ int msgflg);
+ssize_t msg_test_recv(int msqid, FAR struct msg_test_buf_s *buf,
+ size_t len, long mtype, int msgflg);
+long msg_test_qnum(int msqid);
+int msg_test_set_qbytes(int msqid, size_t qbytes);
+void msg_test_start(FAR struct msg_test_waiter_s *w, int msqid, bool snd,
+ long mtype);
+bool msg_test_finish(FAR struct msg_test_waiter_s *w);
+int msg_test_teardown(FAR void **state);
+
+/* cases/msg_test_get.c *****************************************************/
+
+void test_nuttx_msg_get_private(FAR void **state);
+void test_nuttx_msg_get_key(FAR void **state);
+void test_nuttx_msg_get_many(FAR void **state);
+
+/* cases/msg_test_type.c ****************************************************/
+
+void test_nuttx_msg_type_zero(FAR void **state);
+void test_nuttx_msg_type_positive(FAR void **state);
+void test_nuttx_msg_type_negative(FAR void **state);
+
+/* cases/msg_test_size.c ****************************************************/
+
+void test_nuttx_msg_noerror(FAR void **state);
+void test_nuttx_msg_e2big(FAR void **state);
+void test_nuttx_msg_nowait(FAR void **state);
+void test_nuttx_msg_einval(FAR void **state);
+
+/* cases/msg_test_ctl.c *****************************************************/
+
+void test_nuttx_msg_ctl_stat(FAR void **state);
+void test_nuttx_msg_ctl_fields(FAR void **state);
+void test_nuttx_msg_ctl_set(FAR void **state);
+void test_nuttx_msg_ctl_rmid(FAR void **state);
+
+/* cases/msg_test_wait.c ****************************************************/
+
+void test_nuttx_msg_wait_rcv(FAR void **state);
+void test_nuttx_msg_wait_types(FAR void **state);
+void test_nuttx_msg_wait_snd(FAR void **state);
+void test_nuttx_msg_eidrm_rcv(FAR void **state);
+void test_nuttx_msg_eidrm_snd(FAR void **state);
+void test_nuttx_msg_eintr_rcv(FAR void **state);
+void test_nuttx_msg_eintr_snd(FAR void **state);
+
+/* cases/msg_test_pool.c ****************************************************/
+
+void test_nuttx_msg_pool_nowait(FAR void **state);
+void test_nuttx_msg_pool_wait(FAR void **state);
+void test_nuttx_msg_pool_eintr(FAR void **state);
+void test_nuttx_msg_pool_eidrm(FAR void **state);
+
+#endif /* __APPS_TESTING_TESTSUITES_KERNEL_MSG_INCLUDE_MSGTEST_H */