root/lib/common/tests/rules/pcmk_evaluate_rule_test.c

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

DEFINITIONS

This source file includes following definitions.
  1. null_invalid
  2. id_missing
  3. good_idref
  4. bad_idref
  5. empty_default
  6. empty_and
  7. empty_or
  8. default_boolean_op
  9. invalid_boolean_op
  10. and_passes
  11. lonely_and_passes
  12. and_one_fails
  13. and_two_fail
  14. or_one_passes
  15. or_two_pass
  16. lonely_or_passes
  17. or_fails

   1 /*
   2  * Copyright 2024 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 General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdio.h>
  13 #include <glib.h>
  14 
  15 #include <crm/common/xml.h>
  16 #include <crm/common/rules_internal.h>
  17 #include <crm/common/unittest_internal.h>
  18 
  19 /*
  20  * Shared data
  21  */
  22 
  23 static pcmk_rule_input_t rule_input = {
  24     .rsc_standard = PCMK_RESOURCE_CLASS_OCF,
  25     .rsc_provider = "heartbeat",
  26     .rsc_agent = "IPaddr2",
  27     .op_name = PCMK_ACTION_MONITOR,
  28     .op_interval_ms = 10000,
  29 };
  30 
  31 
  32 /*
  33  * Test invalid arguments
  34  */
  35 
  36 #define RULE_OP                                         \
  37     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' > "           \
  38     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' "  \
  39           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "    \
  40           PCMK_XA_INTERVAL "='10s' />"                  \
  41     "</" PCMK_XE_RULE ">"
  42 
  43 static void
  44 null_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46     xmlNode *xml = NULL;
  47     crm_time_t *next_change = crm_time_new_undefined();
  48 
  49     assert_int_equal(pcmk_evaluate_rule(NULL, NULL, next_change),
  50                      EINVAL);
  51 
  52     xml = pcmk__xml_parse(RULE_OP);
  53     assert_int_equal(pcmk_evaluate_rule(xml, NULL, next_change), EINVAL);
  54     free_xml(xml);
  55 
  56     assert_int_equal(pcmk_evaluate_rule(NULL, &rule_input, next_change),
  57                      EINVAL);
  58 
  59     crm_time_free(next_change);
  60 }
  61 
  62 #define RULE_OP_MISSING_ID                              \
  63     "<" PCMK_XE_RULE "> "                               \
  64     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' "  \
  65           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "    \
  66           PCMK_XA_INTERVAL "='10s' />"                  \
  67     "</" PCMK_XE_RULE ">"
  68 
  69 static void
  70 id_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72     // Currently acceptable
  73     xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID);
  74     crm_time_t *next_change = crm_time_new_undefined();
  75 
  76     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change),
  77                      pcmk_rc_ok);
  78 
  79     crm_time_free(next_change);
  80     free_xml(xml);
  81 }
  82 
  83 #define RULE_IDREF_PARENT "<" PCMK_XE_CIB ">" RULE_OP "</" PCMK_XE_CIB ">"
  84 
  85 static void
  86 good_idref(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88     xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
  89     xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
  90     crm_time_t *next_change = crm_time_new_undefined();
  91 
  92     crm_xml_add(rule_xml, PCMK_XA_ID_REF, "r");
  93     assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
  94                      pcmk_rc_ok);
  95 
  96     crm_time_free(next_change);
  97     free_xml(parent_xml);
  98 }
  99 
 100 static void
 101 bad_idref(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103     xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
 104     xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
 105     crm_time_t *next_change = crm_time_new_undefined();
 106 
 107     crm_xml_add(rule_xml, PCMK_XA_ID_REF, "x");
 108     assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
 109                      pcmk_rc_unpack_error);
 110 
 111     crm_time_free(next_change);
 112     free_xml(parent_xml);
 113 }
 114 
 115 #define RULE_EMPTY "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' />"
 116 
 117 static void
 118 empty_default(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120     // Currently acceptable
 121     xmlNode *xml = pcmk__xml_parse(RULE_EMPTY);
 122 
 123     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 124                      pcmk_rc_ok);
 125 
 126     free_xml(xml);
 127 }
 128 
 129 #define RULE_EMPTY_AND                                  \
 130     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "             \
 131         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' />"
 132 
 133 static void
 134 empty_and(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 135 {
 136     // Currently acceptable
 137     xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_AND);
 138 
 139     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 140                      pcmk_rc_ok);
 141 
 142     free_xml(xml);
 143 }
 144 
 145 #define RULE_EMPTY_OR                                   \
 146     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "             \
 147         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' />"
 148 
 149 static void
 150 empty_or(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152     // Currently treated as unsatisfied
 153     xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_OR);
 154 
 155     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 156                      pcmk_rc_op_unsatisfied);
 157 
 158     free_xml(xml);
 159 }
 160 
 161 #define RULE_DEFAULT_BOOLEAN_OP                             \
 162     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' >"                \
 163     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 164           PCMK_XA_TYPE "='Dummy' />"                        \
 165     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 166           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 167           PCMK_XA_INTERVAL "='10s' />"                      \
 168     "</" PCMK_XE_RULE ">"
 169 
 170 static void
 171 default_boolean_op(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173     // Defaults to PCMK_VALUE_AND
 174     xmlNode *xml = pcmk__xml_parse(RULE_DEFAULT_BOOLEAN_OP);
 175 
 176     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 177                      pcmk_rc_op_unsatisfied);
 178 
 179     free_xml(xml);
 180 }
 181 
 182 #define RULE_INVALID_BOOLEAN_OP                             \
 183     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 184         PCMK_XA_BOOLEAN_OP "='not-an-op' >"                 \
 185     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 186           PCMK_XA_TYPE "='Dummy' />"                        \
 187     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 188           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 189           PCMK_XA_INTERVAL "='10s' />"                      \
 190     "</" PCMK_XE_RULE ">"
 191 
 192 static void
 193 invalid_boolean_op(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195     // Currently defaults to PCMK_VALUE_AND
 196     xmlNode *xml = pcmk__xml_parse(RULE_INVALID_BOOLEAN_OP);
 197 
 198     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 199                      pcmk_rc_op_unsatisfied);
 200 
 201     free_xml(xml);
 202 }
 203 
 204 #define RULE_AND_PASSES                                     \
 205     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 206         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >"        \
 207     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 208           PCMK_XA_TYPE "='IPaddr2' />"                      \
 209     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 210           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 211           PCMK_XA_INTERVAL "='10s' />"                      \
 212     "</" PCMK_XE_RULE ">"
 213 
 214 static void
 215 and_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217     xmlNode *xml = pcmk__xml_parse(RULE_AND_PASSES);
 218 
 219     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
 220 
 221     free_xml(xml);
 222 }
 223 
 224 #define RULE_LONELY_AND                                     \
 225     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 226         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >"        \
 227     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 228           PCMK_XA_TYPE "='IPaddr2' />"                      \
 229     "</" PCMK_XE_RULE ">"
 230 
 231 static void
 232 lonely_and_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234     xmlNode *xml = pcmk__xml_parse(RULE_LONELY_AND);
 235 
 236     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
 237 
 238     free_xml(xml);
 239 }
 240 
 241 #define RULE_AND_ONE_FAILS                                  \
 242     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 243         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >"        \
 244     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 245           PCMK_XA_TYPE "='Dummy' />"                        \
 246     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 247           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 248           PCMK_XA_INTERVAL "='10s' />"                      \
 249     "</" PCMK_XE_RULE ">"
 250 
 251 static void
 252 and_one_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254     xmlNode *xml = pcmk__xml_parse(RULE_AND_ONE_FAILS);
 255 
 256     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 257                      pcmk_rc_op_unsatisfied);
 258 
 259     free_xml(xml);
 260 }
 261 
 262 #define RULE_AND_TWO_FAIL                                   \
 263     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 264         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >"        \
 265     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 266           PCMK_XA_TYPE "='Dummy' />"                        \
 267     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 268           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 269           PCMK_XA_INTERVAL "='9s' />"                       \
 270     "</" PCMK_XE_RULE ">"
 271 
 272 static void
 273 and_two_fail(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275     xmlNode *xml = pcmk__xml_parse(RULE_AND_TWO_FAIL);
 276 
 277     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 278                      pcmk_rc_op_unsatisfied);
 279 
 280     free_xml(xml);
 281 }
 282 
 283 #define RULE_OR_ONE_PASSES                                  \
 284     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 285         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >"         \
 286     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 287           PCMK_XA_TYPE "='Dummy' />"                        \
 288     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 289           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 290           PCMK_XA_INTERVAL "='10s' />"                      \
 291     "</" PCMK_XE_RULE ">"
 292 
 293 static void
 294 or_one_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296     xmlNode *xml = pcmk__xml_parse(RULE_OR_ONE_PASSES);
 297 
 298     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
 299 
 300     free_xml(xml);
 301 }
 302 
 303 #define RULE_OR_TWO_PASS                                    \
 304     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 305         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >"         \
 306     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 307           PCMK_XA_TYPE "='IPAddr2' />"                      \
 308     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 309           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 310           PCMK_XA_INTERVAL "='10s' />"                      \
 311     "</" PCMK_XE_RULE ">"
 312 
 313 static void
 314 or_two_pass(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316     xmlNode *xml = pcmk__xml_parse(RULE_OR_TWO_PASS);
 317 
 318     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
 319 
 320     free_xml(xml);
 321 }
 322 
 323 #define RULE_LONELY_OR                                      \
 324     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 325         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >"         \
 326     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 327           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 328           PCMK_XA_INTERVAL "='10s' />"                      \
 329     "</" PCMK_XE_RULE ">"
 330 
 331 static void
 332 lonely_or_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334     xmlNode *xml = pcmk__xml_parse(RULE_LONELY_OR);
 335 
 336     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
 337 
 338     free_xml(xml);
 339 }
 340 
 341 #define RULE_OR_FAILS                                       \
 342     "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' "                 \
 343         PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >"         \
 344     "  <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' "    \
 345           PCMK_XA_TYPE "='Dummy' />"                        \
 346     "  <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' "     \
 347           PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' "        \
 348           PCMK_XA_INTERVAL "='20s' />"                      \
 349     "</" PCMK_XE_RULE ">"
 350 
 351 static void
 352 or_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354     xmlNode *xml = pcmk__xml_parse(RULE_OR_FAILS);
 355 
 356     assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
 357                      pcmk_rc_op_unsatisfied);
 358 
 359     free_xml(xml);
 360 }
 361 
 362 PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
 363                 cmocka_unit_test(null_invalid),
 364                 cmocka_unit_test(id_missing),
 365                 cmocka_unit_test(good_idref),
 366                 cmocka_unit_test(bad_idref),
 367                 cmocka_unit_test(empty_default),
 368                 cmocka_unit_test(empty_and),
 369                 cmocka_unit_test(empty_or),
 370                 cmocka_unit_test(default_boolean_op),
 371                 cmocka_unit_test(invalid_boolean_op),
 372                 cmocka_unit_test(and_passes),
 373                 cmocka_unit_test(lonely_and_passes),
 374                 cmocka_unit_test(and_one_fails),
 375                 cmocka_unit_test(and_two_fail),
 376                 cmocka_unit_test(or_one_passes),
 377                 cmocka_unit_test(or_two_pass),
 378                 cmocka_unit_test(lonely_or_passes),
 379                 cmocka_unit_test(or_fails))

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