root/include/crm/common/unittest_internal.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


   1 /*
   2  * Copyright 2022 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <signal.h>
  11 #include <stdarg.h>
  12 #include <stddef.h>
  13 #include <stdint.h>
  14 #include <setjmp.h>
  15 #include <sys/resource.h>
  16 #include <sys/types.h>
  17 #include <sys/wait.h>
  18 #include <unistd.h>
  19 
  20 #include <cmocka.h>
  21 
  22 #ifndef CRM_COMMON_UNITTEST_INTERNAL__H
  23 #define CRM_COMMON_UNITTEST_INTERNAL__H
  24 
  25 /* internal unit testing related utilities */
  26 
  27 /*!
  28  * \internal
  29  * \brief Assert that a statement aborts through CRM_ASSERT().
  30  *
  31  * \param[in] stmt  Statement to execute; can be an expression.
  32  *
  33  * A cmocka-like assert macro for use in unit testing. This one verifies that a
  34  * statement aborts through CRM_ASSERT(), erroring out if that is not the case.
  35  *
  36  * This macro works by running the statement in a forked child process with core
  37  * dumps disabled (CRM_ASSERT() calls \c abort(), which will write out a core
  38  * dump). The parent waits for the child to exit and checks why. If the child
  39  * received a \c SIGABRT, the test passes. For all other cases, the test fails.
  40  *
  41  * \note If cmocka's expect_*() or will_return() macros are called along with
  42  *       pcmk__assert_asserts(), they must be called within a block that is
  43  *       passed as the \c stmt argument. That way, the values are added only to
  44  *       the child's queue. Otherwise, values added to the parent's queue will
  45  *       never be popped, and the test will fail.
  46  */
  47 #define pcmk__assert_asserts(stmt) \
  48     do { \
  49         pid_t p = fork(); \
  50         if (p == 0) { \
  51             struct rlimit cores = { 0, 0 }; \
  52             setrlimit(RLIMIT_CORE, &cores); \
  53             stmt; \
  54             _exit(0); \
  55         } else if (p > 0) { \
  56             int wstatus = 0; \
  57             if (waitpid(p, &wstatus, 0) == -1) { \
  58                 fail_msg("waitpid failed"); \
  59             } \
  60             if (!(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)) { \
  61                 fail_msg("statement terminated in child without asserting"); \
  62             } \
  63         } else { \
  64             fail_msg("unable to fork for assert test"); \
  65         } \
  66     } while (0);
  67 
  68 /* Generate the main function of most unit test files.  Typically, group_setup
  69  * and group_teardown will be NULL.  The rest of the arguments are a list of
  70  * calls to cmocka_unit_test or cmocka_unit_test_setup_teardown to run the
  71  * individual unit tests.
  72  */
  73 #define PCMK__UNIT_TEST(group_setup, group_teardown, ...) \
  74 int \
  75 main(int argc, char **argv) \
  76 { \
  77     const struct CMUnitTest t[] = { \
  78         __VA_ARGS__ \
  79     }; \
  80     cmocka_set_message_output(CM_OUTPUT_TAP); \
  81     return cmocka_run_group_tests(t, group_setup, group_teardown); \
  82 }
  83 
  84 #endif /* CRM_COMMON_UNITTEST_INTERNAL__H */

/* [previous][next][first][last][top][bottom][index][help] */