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

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

DEFINITIONS

This source file includes following definitions.
  1. setup
  2. teardown
  3. assert_attr_expression
  4. null_invalid
  5. id_missing
  6. attr_missing
  7. attr_with_submatch_passes
  8. attr_with_submatch_fails
  9. source_missing
  10. source_invalid
  11. source_literal_passes
  12. source_literal_value_fails
  13. source_literal_attr_fails
  14. source_params_missing
  15. source_params_passes
  16. source_params_fails
  17. source_meta_missing
  18. source_meta_passes
  19. source_meta_fails
  20. type_default_number
  21. type_default_int
  22. type_invalid
  23. type_string_passes
  24. type_string_fails
  25. type_integer_passes
  26. type_integer_fails
  27. type_integer_truncation
  28. type_number_passes
  29. type_number_fails
  30. type_version_passes
  31. type_version_equality
  32. type_version_fails
  33. op_missing
  34. op_invalid
  35. op_lt_passes
  36. op_lt_fails
  37. op_gt_passes
  38. op_gt_fails
  39. op_lte_lt_passes
  40. op_lte_eq_passes
  41. op_lte_fails
  42. op_gte_gt_passes
  43. op_gte_eq_passes
  44. op_gte_fails
  45. op_eq_passes
  46. op_eq_empty_vs_empty_passes
  47. op_eq_fails
  48. op_eq_undefined_vs_empty_fails
  49. op_ne_passes
  50. op_ne_fails
  51. op_defined_passes
  52. op_defined_empty_passes
  53. op_defined_fails
  54. op_defined_with_value
  55. op_undefined_passes
  56. op_undefined_fails
  57. op_undefined_empty_fails
  58. value_missing_defined_ok
  59. value_missing_eq_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 #include "crmcommon_private.h"
  19 
  20 /*
  21  * Shared data
  22  */
  23 
  24 #define MATCHED_STRING "server-north"
  25 
  26 static const regmatch_t submatches[] = {
  27     { .rm_so = 0, .rm_eo = 12 }, // %0 = Entire string
  28     { .rm_so = 7, .rm_eo = 12 }, // %1 = "north"
  29 };
  30 
  31 static pcmk_rule_input_t rule_input = {
  32     // These are the only members used to evaluate attribute expressions
  33 
  34     // Used to replace submatches in attribute name
  35     .rsc_id = MATCHED_STRING,
  36     .rsc_id_submatches = submatches,
  37     .rsc_id_nmatches = 2,
  38 
  39     // Used when source is instance attributes
  40     .rsc_params = NULL,
  41 
  42     // Used when source is meta-attributes
  43     .rsc_meta = NULL,
  44 
  45     // Used to get actual value of node attribute
  46     .node_attrs = NULL,
  47 };
  48 
  49 static int
  50 setup(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52     rule_input.rsc_params = pcmk__strkey_table(free, free);
  53     pcmk__insert_dup(rule_input.rsc_params, "foo-param", "bar");
  54     pcmk__insert_dup(rule_input.rsc_params, "myparam", "different");
  55 
  56     rule_input.rsc_meta = pcmk__strkey_table(free, free);
  57     pcmk__insert_dup(rule_input.rsc_meta, "foo-meta", "bar");
  58     pcmk__insert_dup(rule_input.rsc_params, "mymeta", "different");
  59 
  60     rule_input.node_attrs = pcmk__strkey_table(free, free);
  61     pcmk__insert_dup(rule_input.node_attrs, "foo", "bar");
  62     pcmk__insert_dup(rule_input.node_attrs, "num", "10");
  63     pcmk__insert_dup(rule_input.node_attrs, "ver", "3.5.0");
  64     pcmk__insert_dup(rule_input.node_attrs, "prefer-north", "100");
  65     pcmk__insert_dup(rule_input.node_attrs, "empty", "");
  66 
  67     return 0;
  68 }
  69 
  70 static int
  71 teardown(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73     g_hash_table_destroy(rule_input.rsc_params);
  74     g_hash_table_destroy(rule_input.rsc_meta);
  75     g_hash_table_destroy(rule_input.node_attrs);
  76     return 0;
  77 }
  78 
  79 /*!
  80  * \internal
  81  * \brief Run one test, comparing return value
  82  *
  83  * \param[in] xml_string    Node attribute expression XML as string
  84  * \param[in] reference_rc  Assert that evaluation result equals this
  85  */
  86 static void
  87 assert_attr_expression(const char *xml_string, int reference_rc)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89     xmlNode *xml = pcmk__xml_parse(xml_string);
  90 
  91     assert_int_equal(pcmk__evaluate_attr_expression(xml, &rule_input),
  92                      reference_rc);
  93     pcmk__xml_free(xml);
  94 }
  95 
  96 
  97 /*
  98  * Invalid arguments
  99  */
 100 
 101 #define EXPR_SOURCE_LITERAL_PASSES                      \
 102         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 103         PCMK_XA_ATTRIBUTE "='foo' "                     \
 104         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 105         PCMK_XA_VALUE "='bar' "                         \
 106         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 107 
 108 static void
 109 null_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111     xmlNode *xml = pcmk__xml_parse(EXPR_SOURCE_LITERAL_PASSES);
 112 
 113     assert_int_equal(pcmk__evaluate_attr_expression(NULL, NULL), EINVAL);
 114     assert_int_equal(pcmk__evaluate_attr_expression(xml, NULL), EINVAL);
 115     assert_int_equal(pcmk__evaluate_attr_expression(NULL, &rule_input), EINVAL);
 116 
 117     pcmk__xml_free(xml);
 118 }
 119 
 120 
 121 /*
 122  * Test PCMK_XA_ID
 123  */
 124 
 125 #define EXPR_ID_MISSING                                 \
 126         "<" PCMK_XE_EXPRESSION " "                      \
 127         PCMK_XA_ATTRIBUTE "='foo' "                     \
 128         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 129         PCMK_XA_VALUE "='bar' />"
 130 
 131 static void
 132 id_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     assert_attr_expression(EXPR_ID_MISSING, pcmk_rc_unpack_error);
 135 }
 136 
 137 
 138 /*
 139  * Test PCMK_XA_ATTRIBUTE
 140  */
 141 
 142 #define EXPR_ATTR_MISSING                               \
 143         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 144         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 145         PCMK_XA_VALUE "='bar' />"
 146 
 147 static void
 148 attr_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150     assert_attr_expression(EXPR_ATTR_MISSING, pcmk_rc_unpack_error);
 151 }
 152 
 153 #define EXPR_ATTR_SUBMATCH_PASSES                       \
 154         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 155         PCMK_XA_ATTRIBUTE "='prefer-%1' "               \
 156         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 157 
 158 static void
 159 attr_with_submatch_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161     assert_attr_expression(EXPR_ATTR_SUBMATCH_PASSES, pcmk_rc_ok);
 162 }
 163 
 164 #define EXPR_ATTR_SUBMATCH_FAILS                        \
 165         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 166         PCMK_XA_ATTRIBUTE "='undefined-%1' "            \
 167         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 168 
 169 static void
 170 attr_with_submatch_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172     assert_attr_expression(EXPR_ATTR_SUBMATCH_FAILS, pcmk_rc_op_unsatisfied);
 173 }
 174 
 175 
 176 /*
 177  * Test PCMK_XA_VALUE_SOURCE
 178  */
 179 
 180 #define EXPR_SOURCE_MISSING                             \
 181         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 182         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 183         PCMK_XA_ATTRIBUTE "='foo' "                     \
 184         PCMK_XA_VALUE "='bar' />"
 185 
 186 static void
 187 source_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189     // Defaults to literal
 190     assert_attr_expression(EXPR_SOURCE_MISSING, pcmk_rc_ok);
 191 }
 192 
 193 #define EXPR_SOURCE_INVALID                             \
 194         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 195         PCMK_XA_ATTRIBUTE "='foo' "                     \
 196         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 197         PCMK_XA_VALUE "='bar' "                         \
 198         PCMK_XA_VALUE_SOURCE "='not-a-source' />"
 199 
 200 static void
 201 source_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     assert_attr_expression(EXPR_SOURCE_INVALID, pcmk_rc_unpack_error);
 204 }
 205 
 206 static void
 207 source_literal_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209     assert_attr_expression(EXPR_SOURCE_LITERAL_PASSES, pcmk_rc_ok);
 210 }
 211 
 212 #define EXPR_SOURCE_LITERAL_VALUE_FAILS                 \
 213         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 214         PCMK_XA_ATTRIBUTE "='foo' "                     \
 215         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 216         PCMK_XA_VALUE "='wrong-value' "                 \
 217         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 218 
 219 static void
 220 source_literal_value_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 221 {
 222     assert_attr_expression(EXPR_SOURCE_LITERAL_VALUE_FAILS,
 223                            pcmk_rc_op_unsatisfied);
 224 }
 225 
 226 #define EXPR_SOURCE_LITERAL_ATTR_FAILS                  \
 227         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 228         PCMK_XA_ATTRIBUTE "='not-an-attribute' "        \
 229         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 230         PCMK_XA_VALUE "='bar' "                         \
 231         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 232 
 233 static void
 234 source_literal_attr_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236     assert_attr_expression(EXPR_SOURCE_LITERAL_ATTR_FAILS,
 237                            pcmk_rc_op_unsatisfied);
 238 }
 239 
 240 #define EXPR_SOURCE_PARAM_MISSING                       \
 241         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 242         PCMK_XA_ATTRIBUTE "='foo' "                     \
 243         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 244         PCMK_XA_VALUE "='not-a-param' "                 \
 245         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
 246 
 247 static void
 248 source_params_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250     assert_attr_expression(EXPR_SOURCE_PARAM_MISSING, pcmk_rc_op_unsatisfied);
 251 }
 252 
 253 #define EXPR_SOURCE_PARAM_PASSES                        \
 254         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 255         PCMK_XA_ATTRIBUTE "='foo' "                     \
 256         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 257         PCMK_XA_VALUE "='foo-param' "                   \
 258         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
 259 
 260 static void
 261 source_params_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263     assert_attr_expression(EXPR_SOURCE_PARAM_PASSES, pcmk_rc_ok);
 264 }
 265 
 266 #define EXPR_SOURCE_PARAM_FAILS                         \
 267         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 268         PCMK_XA_ATTRIBUTE "='foo' "                     \
 269         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 270         PCMK_XA_VALUE "='myparam' "                     \
 271         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
 272 
 273 static void
 274 source_params_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276     assert_attr_expression(EXPR_SOURCE_PARAM_FAILS, pcmk_rc_op_unsatisfied);
 277 }
 278 
 279 #define EXPR_SOURCE_META_MISSING                        \
 280         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 281         PCMK_XA_ATTRIBUTE "='foo' "                     \
 282         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 283         PCMK_XA_VALUE "='not-a-meta' "                  \
 284         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
 285 
 286 static void
 287 source_meta_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289     assert_attr_expression(EXPR_SOURCE_META_MISSING, pcmk_rc_op_unsatisfied);
 290 }
 291 
 292 #define EXPR_SOURCE_META_PASSES                         \
 293         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 294         PCMK_XA_ATTRIBUTE "='foo' "                     \
 295         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 296         PCMK_XA_VALUE "='foo-meta' "                    \
 297         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
 298 
 299 static void
 300 source_meta_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302     assert_attr_expression(EXPR_SOURCE_META_PASSES, pcmk_rc_ok);
 303 }
 304 
 305 #define EXPR_SOURCE_META_FAILS                        \
 306         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 307         PCMK_XA_ATTRIBUTE "='foo' "                     \
 308         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 309         PCMK_XA_VALUE "='mymeta' "                      \
 310         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
 311 
 312 static void
 313 source_meta_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315     assert_attr_expression(EXPR_SOURCE_META_FAILS, pcmk_rc_op_unsatisfied);
 316 }
 317 
 318 
 319 /*
 320  * Test PCMK_XA_TYPE
 321  */
 322 
 323 #define EXPR_TYPE_DEFAULT_NUMBER                        \
 324         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 325         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 326         PCMK_XA_ATTRIBUTE "='num' "                     \
 327         PCMK_XA_VALUE "='2.5' />"
 328 
 329 static void
 330 type_default_number(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332     // Defaults to number for "gt" if either value contains a decimal point
 333     assert_attr_expression(EXPR_TYPE_DEFAULT_NUMBER, pcmk_rc_ok);
 334 }
 335 
 336 #define EXPR_TYPE_DEFAULT_INT                           \
 337         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 338         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 339         PCMK_XA_ATTRIBUTE "='num' "                     \
 340         PCMK_XA_VALUE "='2' />"
 341 
 342 static void
 343 type_default_int(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 344 {
 345     // Defaults to integer for "gt" if neither value contains a decimal point
 346     assert_attr_expression(EXPR_TYPE_DEFAULT_INT, pcmk_rc_ok);
 347 }
 348 
 349 #define EXPR_TYPE_INVALID                               \
 350         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 351         PCMK_XA_TYPE "='not-a-value' "                  \
 352         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 353         PCMK_XA_ATTRIBUTE "='foo' "                     \
 354         PCMK_XA_VALUE "='bar' />"
 355 
 356 static void
 357 type_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 358 {
 359     assert_attr_expression(EXPR_TYPE_INVALID, pcmk_rc_unpack_error);
 360 }
 361 
 362 #define EXPR_TYPE_STRING_PASSES                         \
 363         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 364         PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' "        \
 365         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 366         PCMK_XA_ATTRIBUTE "='foo' "                     \
 367         PCMK_XA_VALUE "='bar' />"
 368 
 369 static void
 370 type_string_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 371 {
 372     assert_attr_expression(EXPR_TYPE_STRING_PASSES, pcmk_rc_ok);
 373 }
 374 
 375 #define EXPR_TYPE_STRING_FAILS                          \
 376         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 377         PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' "        \
 378         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 379         PCMK_XA_ATTRIBUTE "='foo' "                     \
 380         PCMK_XA_VALUE "='bat' />"
 381 
 382 static void
 383 type_string_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 384 {
 385     assert_attr_expression(EXPR_TYPE_STRING_FAILS, pcmk_rc_op_unsatisfied);
 386 }
 387 
 388 #define EXPR_TYPE_INTEGER_PASSES                        \
 389         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 390         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 391         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 392         PCMK_XA_ATTRIBUTE "='num' "                     \
 393         PCMK_XA_VALUE "='10' />"
 394 
 395 static void
 396 type_integer_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 397 {
 398     assert_attr_expression(EXPR_TYPE_INTEGER_PASSES, pcmk_rc_ok);
 399 }
 400 
 401 #define EXPR_TYPE_INTEGER_FAILS                         \
 402         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 403         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 404         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 405         PCMK_XA_ATTRIBUTE "='num' "                     \
 406         PCMK_XA_VALUE "='11' />"
 407 
 408 static void
 409 type_integer_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411     assert_attr_expression(EXPR_TYPE_INTEGER_FAILS, pcmk_rc_op_unsatisfied);
 412 }
 413 
 414 #define EXPR_TYPE_INTEGER_TRUNCATION                    \
 415         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 416         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 417         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 418         PCMK_XA_ATTRIBUTE "='num' "                     \
 419         PCMK_XA_VALUE "='10.5' />"
 420 
 421 static void
 422 type_integer_truncation(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424     assert_attr_expression(EXPR_TYPE_INTEGER_TRUNCATION, pcmk_rc_ok);
 425 }
 426 
 427 #define EXPR_TYPE_NUMBER_PASSES                         \
 428         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 429         PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' "        \
 430         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 431         PCMK_XA_ATTRIBUTE "='num' "                     \
 432         PCMK_XA_VALUE "='10.0' />"
 433 
 434 static void
 435 type_number_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437     assert_attr_expression(EXPR_TYPE_NUMBER_PASSES, pcmk_rc_ok);
 438 }
 439 
 440 #define EXPR_TYPE_NUMBER_FAILS                          \
 441         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 442         PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' "        \
 443         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 444         PCMK_XA_ATTRIBUTE "='num' "                     \
 445         PCMK_XA_VALUE "='10.1' />"
 446 
 447 static void
 448 type_number_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 449 {
 450     assert_attr_expression(EXPR_TYPE_NUMBER_FAILS, pcmk_rc_op_unsatisfied);
 451 }
 452 
 453 #define EXPR_TYPE_VERSION_PASSES                        \
 454         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 455         PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' "       \
 456         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 457         PCMK_XA_ATTRIBUTE "='ver' "                     \
 458         PCMK_XA_VALUE "='3.4.9' />"
 459 
 460 static void
 461 type_version_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463     assert_attr_expression(EXPR_TYPE_VERSION_PASSES, pcmk_rc_ok);
 464 }
 465 
 466 #define EXPR_TYPE_VERSION_EQUALITY                      \
 467         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 468         PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' "       \
 469         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 470         PCMK_XA_ATTRIBUTE "='ver' "                     \
 471         PCMK_XA_VALUE "='3.5' />"
 472 
 473 static void
 474 type_version_equality(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 475 {
 476     assert_attr_expression(EXPR_TYPE_VERSION_EQUALITY, pcmk_rc_ok);
 477 }
 478 
 479 #define EXPR_TYPE_VERSION_FAILS                         \
 480         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 481         PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' "       \
 482         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 483         PCMK_XA_ATTRIBUTE "='ver' "                     \
 484         PCMK_XA_VALUE "='4.0' />"
 485 
 486 static void
 487 type_version_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489     assert_attr_expression(EXPR_TYPE_VERSION_FAILS, pcmk_rc_before_range);
 490 }
 491 
 492 /*
 493  * Test PCMK_XA_OPERATION
 494  */
 495 
 496 #define EXPR_OP_MISSING                                 \
 497         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 498         PCMK_XA_ATTRIBUTE "='foo' "                     \
 499         PCMK_XA_VALUE "='bar' />"
 500 
 501 static void
 502 op_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 503 {
 504     assert_attr_expression(EXPR_OP_MISSING, pcmk_rc_unpack_error);
 505 }
 506 
 507 #define EXPR_OP_INVALID                                 \
 508         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 509         PCMK_XA_ATTRIBUTE "='foo' "                     \
 510         PCMK_XA_OPERATION "='not-an-operation' "        \
 511         PCMK_XA_VALUE "='bar' />"
 512 
 513 static void
 514 op_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 515 {
 516     assert_attr_expression(EXPR_OP_INVALID, pcmk_rc_unpack_error);
 517 }
 518 
 519 #define EXPR_OP_LT_PASSES                               \
 520         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 521         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 522         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "       \
 523         PCMK_XA_ATTRIBUTE "='num' "                     \
 524         PCMK_XA_VALUE "='20' />"
 525 
 526 static void
 527 op_lt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 528 {
 529     assert_attr_expression(EXPR_OP_LT_PASSES, pcmk_rc_ok);
 530 }
 531 
 532 #define EXPR_OP_LT_FAILS                                \
 533         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 534         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 535         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "       \
 536         PCMK_XA_ATTRIBUTE "='num' "                     \
 537         PCMK_XA_VALUE "='2' />"
 538 
 539 static void
 540 op_lt_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 541 {
 542     assert_attr_expression(EXPR_OP_LT_FAILS, pcmk_rc_after_range);
 543 }
 544 
 545 #define EXPR_OP_GT_PASSES                               \
 546         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 547         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 548         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 549         PCMK_XA_ATTRIBUTE "='num' "                     \
 550         PCMK_XA_VALUE "='2' />"
 551 
 552 static void
 553 op_gt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555     assert_attr_expression(EXPR_OP_GT_PASSES, pcmk_rc_ok);
 556 }
 557 
 558 #define EXPR_OP_GT_FAILS                                \
 559         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 560         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 561         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 562         PCMK_XA_ATTRIBUTE "='num' "                     \
 563         PCMK_XA_VALUE "='20' />"
 564 
 565 static void
 566 op_gt_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 567 {
 568     assert_attr_expression(EXPR_OP_GT_FAILS, pcmk_rc_before_range);
 569 }
 570 
 571 #define EXPR_OP_LTE_LT_PASSES                           \
 572         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 573         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 574         PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' "      \
 575         PCMK_XA_ATTRIBUTE "='num' "                     \
 576         PCMK_XA_VALUE "='20' />"
 577 
 578 static void
 579 op_lte_lt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 580 {
 581     assert_attr_expression(EXPR_OP_LTE_LT_PASSES, pcmk_rc_ok);
 582 }
 583 
 584 #define EXPR_OP_LTE_EQ_PASSES                           \
 585         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 586         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 587         PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' "      \
 588         PCMK_XA_ATTRIBUTE "='num' "                     \
 589         PCMK_XA_VALUE "='10' />"
 590 
 591 static void
 592 op_lte_eq_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 593 {
 594     assert_attr_expression(EXPR_OP_LTE_EQ_PASSES, pcmk_rc_ok);
 595 }
 596 
 597 #define EXPR_OP_LTE_FAILS                               \
 598         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 599         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 600         PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' "      \
 601         PCMK_XA_ATTRIBUTE "='num' "                     \
 602         PCMK_XA_VALUE "='9' />"
 603 
 604 static void
 605 op_lte_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 606 {
 607     assert_attr_expression(EXPR_OP_LTE_FAILS, pcmk_rc_after_range);
 608 }
 609 
 610 #define EXPR_OP_GTE_GT_PASSES                           \
 611         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 612         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 613         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 614         PCMK_XA_ATTRIBUTE "='num' "                     \
 615         PCMK_XA_VALUE "='1' />"
 616 
 617 static void
 618 op_gte_gt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 619 {
 620     assert_attr_expression(EXPR_OP_GTE_GT_PASSES, pcmk_rc_ok);
 621 }
 622 
 623 #define EXPR_OP_GTE_EQ_PASSES                           \
 624         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 625         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 626         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 627         PCMK_XA_ATTRIBUTE "='num' "                     \
 628         PCMK_XA_VALUE "='10' />"
 629 
 630 static void
 631 op_gte_eq_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 632 {
 633     assert_attr_expression(EXPR_OP_GTE_EQ_PASSES, pcmk_rc_ok);
 634 }
 635 
 636 #define EXPR_OP_GTE_FAILS                               \
 637         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 638         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 639         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 640         PCMK_XA_ATTRIBUTE "='num' "                     \
 641         PCMK_XA_VALUE "='11' />"
 642 
 643 static void
 644 op_gte_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 645 {
 646     assert_attr_expression(EXPR_OP_GTE_FAILS, pcmk_rc_before_range);
 647 }
 648 
 649 // This also tests that string is used if values aren't parseable as numbers
 650 #define EXPR_OP_EQ_PASSES                               \
 651         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 652         PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' "        \
 653         PCMK_XA_ATTRIBUTE "='foo' "                     \
 654         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 655         PCMK_XA_VALUE "='bar' "                         \
 656         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 657 
 658 static void
 659 op_eq_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 660 {
 661     assert_attr_expression(EXPR_OP_EQ_PASSES, pcmk_rc_ok);
 662 }
 663 
 664 #define EXPR_EQ_EMPTY_VS_EMPTY_PASSES                   \
 665         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 666         PCMK_XA_ATTRIBUTE "='empty' "                   \
 667         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 668         PCMK_XA_VALUE "='' />"
 669 
 670 static void
 671 op_eq_empty_vs_empty_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 672 {
 673     assert_attr_expression(EXPR_EQ_EMPTY_VS_EMPTY_PASSES, pcmk_rc_ok);
 674 }
 675 
 676 #define EXPR_OP_EQ_FAILS                                \
 677         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 678         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 679         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 680         PCMK_XA_ATTRIBUTE "='num' "                     \
 681         PCMK_XA_VALUE "='bar' />"
 682 
 683 static void
 684 op_eq_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 685 {
 686     assert_attr_expression(EXPR_OP_EQ_FAILS, pcmk_rc_op_unsatisfied);
 687 }
 688 
 689 #define EXPR_EQ_UNDEFINED_VS_EMPTY_FAILS                \
 690         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 691         PCMK_XA_ATTRIBUTE "='boo' "                     \
 692         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 693         PCMK_XA_VALUE "='' />"
 694 
 695 static void
 696 op_eq_undefined_vs_empty_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 697 {
 698     assert_attr_expression(EXPR_EQ_UNDEFINED_VS_EMPTY_FAILS,
 699                            pcmk_rc_op_unsatisfied);
 700 }
 701 
 702 #define EXPR_OP_NE_PASSES                               \
 703         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 704         PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' "        \
 705         PCMK_XA_ATTRIBUTE "='foo' "                     \
 706         PCMK_XA_OPERATION "='" PCMK_VALUE_NE "' "       \
 707         PCMK_XA_VALUE "='bat' "                         \
 708         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 709 
 710 static void
 711 op_ne_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 712 {
 713     assert_attr_expression(EXPR_OP_NE_PASSES, pcmk_rc_ok);
 714 }
 715 
 716 #define EXPR_OP_NE_FAILS                                \
 717         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 718         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 719         PCMK_XA_OPERATION "='" PCMK_VALUE_NE "' "       \
 720         PCMK_XA_ATTRIBUTE "='num' "                     \
 721         PCMK_XA_VALUE "='10' />"
 722 
 723 static void
 724 op_ne_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 725 {
 726     assert_attr_expression(EXPR_OP_NE_FAILS, pcmk_rc_op_unsatisfied);
 727 }
 728 
 729 #define EXPR_OP_DEFINED_PASSES                          \
 730         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 731         PCMK_XA_ATTRIBUTE "='foo' "                     \
 732         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 733 
 734 static void
 735 op_defined_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 736 {
 737     assert_attr_expression(EXPR_OP_DEFINED_PASSES, pcmk_rc_ok);
 738 }
 739 
 740 #define EXPR_OP_DEFINED_EMPTY_PASSES                    \
 741         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 742         PCMK_XA_ATTRIBUTE "='empty' "                   \
 743         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 744 
 745 static void
 746 op_defined_empty_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 747 {
 748     assert_attr_expression(EXPR_OP_DEFINED_EMPTY_PASSES, pcmk_rc_ok);
 749 }
 750 
 751 #define EXPR_OP_DEFINED_FAILS                           \
 752         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 753         PCMK_XA_ATTRIBUTE "='boo' "                     \
 754         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 755 
 756 static void
 757 op_defined_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 758 {
 759     assert_attr_expression(EXPR_OP_DEFINED_FAILS, pcmk_rc_op_unsatisfied);
 760 }
 761 
 762 #define EXPR_OP_DEFINED_WITH_VALUE                      \
 763         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 764         PCMK_XA_ATTRIBUTE "='foo' "                     \
 765         PCMK_XA_VALUE "='bar' "                         \
 766         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 767 
 768 static void
 769 op_defined_with_value(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 770 {
 771     assert_attr_expression(EXPR_OP_DEFINED_WITH_VALUE, pcmk_rc_unpack_error);
 772 }
 773 
 774 #define EXPR_OP_UNDEFINED_PASSES                        \
 775         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 776         PCMK_XA_ATTRIBUTE "='boo' "                     \
 777         PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
 778 
 779 static void
 780 op_undefined_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 781 {
 782     assert_attr_expression(EXPR_OP_UNDEFINED_PASSES, pcmk_rc_ok);
 783 }
 784 
 785 #define EXPR_OP_UNDEFINED_FAILS                         \
 786         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 787         PCMK_XA_ATTRIBUTE "='foo' "                     \
 788         PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
 789 
 790 static void
 791 op_undefined_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 792 {
 793     assert_attr_expression(EXPR_OP_UNDEFINED_FAILS, pcmk_rc_op_unsatisfied);
 794 }
 795 
 796 #define EXPR_OP_UNDEFINED_EMPTY_FAILS                   \
 797         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 798         PCMK_XA_ATTRIBUTE "='empty' "                   \
 799         PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
 800 
 801 static void
 802 op_undefined_empty_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 803 {
 804     assert_attr_expression(EXPR_OP_UNDEFINED_EMPTY_FAILS,
 805                            pcmk_rc_op_unsatisfied);
 806 }
 807 
 808 
 809 /*
 810  * Test PCMK_XA_VALUE
 811  */
 812 
 813 #define EXPR_VALUE_MISSING_DEFINED_OK                   \
 814         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 815         PCMK_XA_ATTRIBUTE "='num' "                     \
 816         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 817 
 818 static void
 819 value_missing_defined_ok(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 820 {
 821     assert_attr_expression(EXPR_VALUE_MISSING_DEFINED_OK, pcmk_rc_ok);
 822 }
 823 
 824 #define EXPR_VALUE_MISSING_EQ_FAILS                     \
 825         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 826         PCMK_XA_ATTRIBUTE "='not-an-attr' "             \
 827         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' />"
 828 
 829 static void
 830 value_missing_eq_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 831 {
 832     assert_attr_expression(EXPR_VALUE_MISSING_EQ_FAILS, pcmk_rc_unpack_error);
 833 }
 834 
 835 
 836 #define expr_test(f) cmocka_unit_test_setup_teardown(f, setup, teardown)
 837 
 838 PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
 839                 cmocka_unit_test(null_invalid),
 840                 expr_test(id_missing),
 841                 expr_test(attr_missing),
 842                 expr_test(attr_with_submatch_passes),
 843                 expr_test(attr_with_submatch_fails),
 844                 expr_test(source_missing),
 845                 expr_test(source_invalid),
 846                 expr_test(source_literal_passes),
 847                 expr_test(source_literal_value_fails),
 848                 expr_test(source_literal_attr_fails),
 849                 expr_test(source_params_missing),
 850                 expr_test(source_params_passes),
 851                 expr_test(source_params_fails),
 852                 expr_test(source_meta_missing),
 853                 expr_test(source_meta_passes),
 854                 expr_test(source_meta_fails),
 855                 expr_test(type_default_number),
 856                 expr_test(type_default_int),
 857                 expr_test(type_invalid),
 858                 expr_test(type_string_passes),
 859                 expr_test(type_string_fails),
 860                 expr_test(type_integer_passes),
 861                 expr_test(type_integer_fails),
 862                 expr_test(type_integer_truncation),
 863                 expr_test(type_number_passes),
 864                 expr_test(type_number_fails),
 865                 expr_test(type_version_passes),
 866                 expr_test(type_version_equality),
 867                 expr_test(type_version_fails),
 868                 expr_test(op_missing),
 869                 expr_test(op_invalid),
 870                 expr_test(op_lt_passes),
 871                 expr_test(op_lt_fails),
 872                 expr_test(op_gt_passes),
 873                 expr_test(op_gt_fails),
 874                 expr_test(op_lte_lt_passes),
 875                 expr_test(op_lte_eq_passes),
 876                 expr_test(op_lte_fails),
 877                 expr_test(op_gte_gt_passes),
 878                 expr_test(op_gte_eq_passes),
 879                 expr_test(op_gte_fails),
 880                 expr_test(op_eq_passes),
 881                 expr_test(op_eq_empty_vs_empty_passes),
 882                 expr_test(op_eq_fails),
 883                 expr_test(op_eq_undefined_vs_empty_fails),
 884                 expr_test(op_ne_passes),
 885                 expr_test(op_ne_fails),
 886                 expr_test(op_defined_passes),
 887                 expr_test(op_defined_empty_passes),
 888                 expr_test(op_defined_fails),
 889                 expr_test(op_defined_with_value),
 890                 expr_test(op_undefined_passes),
 891                 expr_test(op_undefined_fails),
 892                 expr_test(op_undefined_empty_fails),
 893                 expr_test(value_missing_defined_ok),
 894                 expr_test(value_missing_eq_fails))

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