root/include/crm/common/unittest_internal.h

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

INCLUDED FROM


   1 /*
   2  * Copyright 2022-2023 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 /*!
  69  * \internal
  70  * \brief Assert that a statement exits with the expected exit status.
  71  *
  72  * \param[in] stmt  Statement to execute; can be an expression.
  73  * \param[in] rc    The expected exit status.
  74  *
  75  * This functions just like \c pcmk__assert_asserts, except that it tests for
  76  * an expected exit status.  Abnormal termination or incorrect exit status is
  77  * treated as a failure of the test.
  78  *
  79  * In the event that stmt does not exit at all, the special code \c CRM_EX_NONE
  80  * will be returned.  It is expected that this code is not used anywhere, thus
  81  * always causing an error.
  82  */
  83 #define pcmk__assert_exits(rc, stmt) \
  84     do { \
  85         pid_t p = fork(); \
  86         if (p == 0) { \
  87             struct rlimit cores = { 0, 0 }; \
  88             setrlimit(RLIMIT_CORE, &cores); \
  89             stmt; \
  90             _exit(CRM_EX_NONE); \
  91         } else if (p > 0) { \
  92             int wstatus = 0; \
  93             if (waitpid(p, &wstatus, 0) == -1) { \
  94                 fail_msg("waitpid failed"); \
  95             } \
  96             if (!WIFEXITED(wstatus)) { \
  97                 fail_msg("statement terminated abnormally"); \
  98             } else if (WEXITSTATUS(wstatus) != rc) { \
  99                 fail_msg("statement exited with %d, not expected %d", WEXITSTATUS(wstatus), rc); \
 100             } \
 101         } else { \
 102             fail_msg("unable to fork for assert test"); \
 103         } \
 104     } while (0);
 105 
 106 /* Generate the main function of most unit test files.  Typically, group_setup
 107  * and group_teardown will be NULL.  The rest of the arguments are a list of
 108  * calls to cmocka_unit_test or cmocka_unit_test_setup_teardown to run the
 109  * individual unit tests.
 110  */
 111 #define PCMK__UNIT_TEST(group_setup, group_teardown, ...) \
 112 int \
 113 main(int argc, char **argv) \
 114 { \
 115     const struct CMUnitTest t[] = { \
 116         __VA_ARGS__ \
 117     }; \
 118     cmocka_set_message_output(CM_OUTPUT_TAP); \
 119     return cmocka_run_group_tests(t, group_setup, group_teardown); \
 120 }
 121 
 122 #endif /* CRM_COMMON_UNITTEST_INTERNAL__H */

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