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_string_passes
  23. type_string_fails
  24. type_integer_passes
  25. type_integer_fails
  26. type_integer_truncation
  27. type_number_passes
  28. type_number_fails
  29. type_version_passes
  30. type_version_equality
  31. type_version_fails
  32. op_missing
  33. op_invalid
  34. op_lt_passes
  35. op_lt_fails
  36. op_gt_passes
  37. op_gt_fails
  38. op_lte_lt_passes
  39. op_lte_eq_passes
  40. op_lte_fails
  41. op_gte_gt_passes
  42. op_gte_eq_passes
  43. op_gte_fails
  44. op_eq_passes
  45. op_eq_fails
  46. op_ne_passes
  47. op_ne_fails
  48. op_defined_passes
  49. op_defined_fails
  50. op_defined_with_value
  51. op_undefined_passes
  52. op_undefined_fails
  53. value_missing_defined_ok
  54. value_missing_eq_ok

   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 
  66     return 0;
  67 }
  68 
  69 static int
  70 teardown(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72     g_hash_table_destroy(rule_input.rsc_params);
  73     g_hash_table_destroy(rule_input.rsc_meta);
  74     g_hash_table_destroy(rule_input.node_attrs);
  75     return 0;
  76 }
  77 
  78 /*!
  79  * \internal
  80  * \brief Run one test, comparing return value
  81  *
  82  * \param[in] xml_string    Node attribute expression XML as string
  83  * \param[in] reference_rc  Assert that evaluation result equals this
  84  */
  85 static void
  86 assert_attr_expression(const char *xml_string, int reference_rc)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88     xmlNode *xml = pcmk__xml_parse(xml_string);
  89 
  90     assert_int_equal(pcmk__evaluate_attr_expression(xml, &rule_input),
  91                      reference_rc);
  92     free_xml(xml);
  93 }
  94 
  95 
  96 /*
  97  * Invalid arguments
  98  */
  99 
 100 #define EXPR_SOURCE_LITERAL_PASSES                      \
 101         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 102         PCMK_XA_ATTRIBUTE "='foo' "                     \
 103         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 104         PCMK_XA_VALUE "='bar' "                         \
 105         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 106 
 107 static void
 108 null_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     xmlNode *xml = pcmk__xml_parse(EXPR_SOURCE_LITERAL_PASSES);
 111 
 112     assert_int_equal(pcmk__evaluate_attr_expression(NULL, NULL), EINVAL);
 113     assert_int_equal(pcmk__evaluate_attr_expression(xml, NULL), EINVAL);
 114     assert_int_equal(pcmk__evaluate_attr_expression(NULL, &rule_input), EINVAL);
 115 
 116     free_xml(xml);
 117 }
 118 
 119 
 120 /*
 121  * Test PCMK_XA_ID
 122  */
 123 
 124 #define EXPR_ID_MISSING                                 \
 125         "<" PCMK_XE_EXPRESSION " "                      \
 126         PCMK_XA_ATTRIBUTE "='foo' "                     \
 127         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 128         PCMK_XA_VALUE "='bar' />"
 129 
 130 static void
 131 id_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133     // Currently acceptable
 134     assert_attr_expression(EXPR_ID_MISSING, pcmk_rc_ok);
 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     // Currently treated as literal
 204     assert_attr_expression(EXPR_SOURCE_INVALID, pcmk_rc_ok);
 205 }
 206 
 207 static void
 208 source_literal_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     assert_attr_expression(EXPR_SOURCE_LITERAL_PASSES, pcmk_rc_ok);
 211 }
 212 
 213 #define EXPR_SOURCE_LITERAL_VALUE_FAILS                 \
 214         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 215         PCMK_XA_ATTRIBUTE "='foo' "                     \
 216         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 217         PCMK_XA_VALUE "='wrong-value' "                 \
 218         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 219 
 220 static void
 221 source_literal_value_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 222 {
 223     assert_attr_expression(EXPR_SOURCE_LITERAL_VALUE_FAILS,
 224                            pcmk_rc_op_unsatisfied);
 225 }
 226 
 227 #define EXPR_SOURCE_LITERAL_ATTR_FAILS                  \
 228         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 229         PCMK_XA_ATTRIBUTE "='not-an-attribute' "        \
 230         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 231         PCMK_XA_VALUE "='bar' "                         \
 232         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 233 
 234 static void
 235 source_literal_attr_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237     assert_attr_expression(EXPR_SOURCE_LITERAL_ATTR_FAILS,
 238                            pcmk_rc_op_unsatisfied);
 239 }
 240 
 241 #define EXPR_SOURCE_PARAM_MISSING                       \
 242         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 243         PCMK_XA_ATTRIBUTE "='foo' "                     \
 244         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 245         PCMK_XA_VALUE "='not-a-param' "                 \
 246         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
 247 
 248 static void
 249 source_params_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251     assert_attr_expression(EXPR_SOURCE_PARAM_MISSING, pcmk_rc_op_unsatisfied);
 252 }
 253 
 254 #define EXPR_SOURCE_PARAM_PASSES                        \
 255         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 256         PCMK_XA_ATTRIBUTE "='foo' "                     \
 257         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 258         PCMK_XA_VALUE "='foo-param' "                   \
 259         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
 260 
 261 static void
 262 source_params_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 263 {
 264     assert_attr_expression(EXPR_SOURCE_PARAM_PASSES, pcmk_rc_ok);
 265 }
 266 
 267 #define EXPR_SOURCE_PARAM_FAILS                         \
 268         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 269         PCMK_XA_ATTRIBUTE "='foo' "                     \
 270         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 271         PCMK_XA_VALUE "='myparam' "                     \
 272         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
 273 
 274 static void
 275 source_params_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 276 {
 277     assert_attr_expression(EXPR_SOURCE_PARAM_FAILS, pcmk_rc_op_unsatisfied);
 278 }
 279 
 280 #define EXPR_SOURCE_META_MISSING                        \
 281         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 282         PCMK_XA_ATTRIBUTE "='foo' "                     \
 283         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 284         PCMK_XA_VALUE "='not-a-meta' "                  \
 285         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
 286 
 287 static void
 288 source_meta_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 289 {
 290     assert_attr_expression(EXPR_SOURCE_META_MISSING, pcmk_rc_op_unsatisfied);
 291 }
 292 
 293 #define EXPR_SOURCE_META_PASSES                         \
 294         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 295         PCMK_XA_ATTRIBUTE "='foo' "                     \
 296         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 297         PCMK_XA_VALUE "='foo-meta' "                    \
 298         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
 299 
 300 static void
 301 source_meta_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303     assert_attr_expression(EXPR_SOURCE_META_PASSES, pcmk_rc_ok);
 304 }
 305 
 306 #define EXPR_SOURCE_META_FAILS                        \
 307         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 308         PCMK_XA_ATTRIBUTE "='foo' "                     \
 309         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 310         PCMK_XA_VALUE "='mymeta' "                      \
 311         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
 312 
 313 static void
 314 source_meta_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316     assert_attr_expression(EXPR_SOURCE_META_FAILS, pcmk_rc_op_unsatisfied);
 317 }
 318 
 319 
 320 /*
 321  * Test PCMK_XA_TYPE
 322  */
 323 
 324 #define EXPR_TYPE_DEFAULT_NUMBER                        \
 325         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 326         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 327         PCMK_XA_ATTRIBUTE "='num' "                     \
 328         PCMK_XA_VALUE "='2.5' />"
 329 
 330 static void
 331 type_default_number(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 332 {
 333     // Defaults to number for "gt" if either value contains a decimal point
 334     assert_attr_expression(EXPR_TYPE_DEFAULT_NUMBER, pcmk_rc_ok);
 335 }
 336 
 337 #define EXPR_TYPE_DEFAULT_INT                           \
 338         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 339         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 340         PCMK_XA_ATTRIBUTE "='num' "                     \
 341         PCMK_XA_VALUE "='2' />"
 342 
 343 static void
 344 type_default_int(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 345 {
 346     // Defaults to integer for "gt" if neither value contains a decimal point
 347     assert_attr_expression(EXPR_TYPE_DEFAULT_INT, pcmk_rc_ok);
 348 }
 349 
 350 #define EXPR_TYPE_STRING_PASSES                         \
 351         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 352         PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' "        \
 353         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 354         PCMK_XA_ATTRIBUTE "='foo' "                     \
 355         PCMK_XA_VALUE "='bar' />"
 356 
 357 static void
 358 type_string_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 359 {
 360     assert_attr_expression(EXPR_TYPE_STRING_PASSES, pcmk_rc_ok);
 361 }
 362 
 363 #define EXPR_TYPE_STRING_FAILS                          \
 364         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 365         PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' "        \
 366         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 367         PCMK_XA_ATTRIBUTE "='foo' "                     \
 368         PCMK_XA_VALUE "='bat' />"
 369 
 370 static void
 371 type_string_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373     assert_attr_expression(EXPR_TYPE_STRING_FAILS, pcmk_rc_op_unsatisfied);
 374 }
 375 
 376 #define EXPR_TYPE_INTEGER_PASSES                        \
 377         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 378         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 379         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 380         PCMK_XA_ATTRIBUTE "='num' "                     \
 381         PCMK_XA_VALUE "='10' />"
 382 
 383 static void
 384 type_integer_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386     assert_attr_expression(EXPR_TYPE_INTEGER_PASSES, pcmk_rc_ok);
 387 }
 388 
 389 #define EXPR_TYPE_INTEGER_FAILS                         \
 390         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 391         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 392         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 393         PCMK_XA_ATTRIBUTE "='num' "                     \
 394         PCMK_XA_VALUE "='11' />"
 395 
 396 static void
 397 type_integer_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 398 {
 399     assert_attr_expression(EXPR_TYPE_INTEGER_FAILS, pcmk_rc_op_unsatisfied);
 400 }
 401 
 402 #define EXPR_TYPE_INTEGER_TRUNCATION                    \
 403         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 404         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 405         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 406         PCMK_XA_ATTRIBUTE "='num' "                     \
 407         PCMK_XA_VALUE "='10.5' />"
 408 
 409 static void
 410 type_integer_truncation(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 411 {
 412     assert_attr_expression(EXPR_TYPE_INTEGER_TRUNCATION, pcmk_rc_ok);
 413 }
 414 
 415 #define EXPR_TYPE_NUMBER_PASSES                         \
 416         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 417         PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' "        \
 418         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 419         PCMK_XA_ATTRIBUTE "='num' "                     \
 420         PCMK_XA_VALUE "='10.0' />"
 421 
 422 static void
 423 type_number_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 424 {
 425     assert_attr_expression(EXPR_TYPE_NUMBER_PASSES, pcmk_rc_ok);
 426 }
 427 
 428 #define EXPR_TYPE_NUMBER_FAILS                          \
 429         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 430         PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' "        \
 431         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 432         PCMK_XA_ATTRIBUTE "='num' "                     \
 433         PCMK_XA_VALUE "='10.1' />"
 434 
 435 static void
 436 type_number_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 437 {
 438     assert_attr_expression(EXPR_TYPE_NUMBER_FAILS, pcmk_rc_op_unsatisfied);
 439 }
 440 
 441 #define EXPR_TYPE_VERSION_PASSES                        \
 442         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 443         PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' "       \
 444         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 445         PCMK_XA_ATTRIBUTE "='ver' "                     \
 446         PCMK_XA_VALUE "='3.4.9' />"
 447 
 448 static void
 449 type_version_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 450 {
 451     assert_attr_expression(EXPR_TYPE_VERSION_PASSES, pcmk_rc_ok);
 452 }
 453 
 454 #define EXPR_TYPE_VERSION_EQUALITY                      \
 455         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 456         PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' "       \
 457         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 458         PCMK_XA_ATTRIBUTE "='ver' "                     \
 459         PCMK_XA_VALUE "='3.5' />"
 460 
 461 static void
 462 type_version_equality(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 463 {
 464     assert_attr_expression(EXPR_TYPE_VERSION_EQUALITY, pcmk_rc_ok);
 465 }
 466 
 467 #define EXPR_TYPE_VERSION_FAILS                         \
 468         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 469         PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' "       \
 470         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 471         PCMK_XA_ATTRIBUTE "='ver' "                     \
 472         PCMK_XA_VALUE "='4.0' />"
 473 
 474 static void
 475 type_version_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 476 {
 477     assert_attr_expression(EXPR_TYPE_VERSION_FAILS, pcmk_rc_before_range);
 478 }
 479 
 480 /*
 481  * Test PCMK_XA_OPERATION
 482  */
 483 
 484 #define EXPR_OP_MISSING                                 \
 485         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 486         PCMK_XA_ATTRIBUTE "='foo' "                     \
 487         PCMK_XA_VALUE "='bar' />"
 488 
 489 static void
 490 op_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 491 {
 492     assert_attr_expression(EXPR_OP_MISSING, pcmk_rc_unpack_error);
 493 }
 494 
 495 #define EXPR_OP_INVALID                                 \
 496         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 497         PCMK_XA_ATTRIBUTE "='foo' "                     \
 498         PCMK_XA_OPERATION "='not-an-operation' "        \
 499         PCMK_XA_VALUE "='bar' />"
 500 
 501 static void
 502 op_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 503 {
 504     assert_attr_expression(EXPR_OP_INVALID, pcmk_rc_unpack_error);
 505 }
 506 
 507 #define EXPR_OP_LT_PASSES                               \
 508         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 509         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 510         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "       \
 511         PCMK_XA_ATTRIBUTE "='num' "                     \
 512         PCMK_XA_VALUE "='20' />"
 513 
 514 static void
 515 op_lt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517     assert_attr_expression(EXPR_OP_LT_PASSES, pcmk_rc_ok);
 518 }
 519 
 520 #define EXPR_OP_LT_FAILS                                \
 521         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 522         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 523         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "       \
 524         PCMK_XA_ATTRIBUTE "='num' "                     \
 525         PCMK_XA_VALUE "='2' />"
 526 
 527 static void
 528 op_lt_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530     assert_attr_expression(EXPR_OP_LT_FAILS, pcmk_rc_after_range);
 531 }
 532 
 533 #define EXPR_OP_GT_PASSES                               \
 534         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 535         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 536         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 537         PCMK_XA_ATTRIBUTE "='num' "                     \
 538         PCMK_XA_VALUE "='2' />"
 539 
 540 static void
 541 op_gt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 542 {
 543     assert_attr_expression(EXPR_OP_GT_PASSES, pcmk_rc_ok);
 544 }
 545 
 546 #define EXPR_OP_GT_FAILS                                \
 547         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 548         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 549         PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "       \
 550         PCMK_XA_ATTRIBUTE "='num' "                     \
 551         PCMK_XA_VALUE "='20' />"
 552 
 553 static void
 554 op_gt_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 555 {
 556     assert_attr_expression(EXPR_OP_GT_FAILS, pcmk_rc_before_range);
 557 }
 558 
 559 #define EXPR_OP_LTE_LT_PASSES                           \
 560         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 561         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 562         PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' "      \
 563         PCMK_XA_ATTRIBUTE "='num' "                     \
 564         PCMK_XA_VALUE "='20' />"
 565 
 566 static void
 567 op_lte_lt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 568 {
 569     assert_attr_expression(EXPR_OP_LTE_LT_PASSES, pcmk_rc_ok);
 570 }
 571 
 572 #define EXPR_OP_LTE_EQ_PASSES                           \
 573         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 574         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 575         PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' "      \
 576         PCMK_XA_ATTRIBUTE "='num' "                     \
 577         PCMK_XA_VALUE "='10' />"
 578 
 579 static void
 580 op_lte_eq_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 581 {
 582     assert_attr_expression(EXPR_OP_LTE_EQ_PASSES, pcmk_rc_ok);
 583 }
 584 
 585 #define EXPR_OP_LTE_FAILS                               \
 586         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 587         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 588         PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' "      \
 589         PCMK_XA_ATTRIBUTE "='num' "                     \
 590         PCMK_XA_VALUE "='9' />"
 591 
 592 static void
 593 op_lte_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 594 {
 595     assert_attr_expression(EXPR_OP_LTE_FAILS, pcmk_rc_after_range);
 596 }
 597 
 598 #define EXPR_OP_GTE_GT_PASSES                           \
 599         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 600         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 601         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 602         PCMK_XA_ATTRIBUTE "='num' "                     \
 603         PCMK_XA_VALUE "='1' />"
 604 
 605 static void
 606 op_gte_gt_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 607 {
 608     assert_attr_expression(EXPR_OP_GTE_GT_PASSES, pcmk_rc_ok);
 609 }
 610 
 611 #define EXPR_OP_GTE_EQ_PASSES                           \
 612         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 613         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 614         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 615         PCMK_XA_ATTRIBUTE "='num' "                     \
 616         PCMK_XA_VALUE "='10' />"
 617 
 618 static void
 619 op_gte_eq_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 620 {
 621     assert_attr_expression(EXPR_OP_GTE_EQ_PASSES, pcmk_rc_ok);
 622 }
 623 
 624 #define EXPR_OP_GTE_FAILS                               \
 625         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 626         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 627         PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' "      \
 628         PCMK_XA_ATTRIBUTE "='num' "                     \
 629         PCMK_XA_VALUE "='11' />"
 630 
 631 static void
 632 op_gte_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 633 {
 634     assert_attr_expression(EXPR_OP_GTE_FAILS, pcmk_rc_before_range);
 635 }
 636 
 637 // This also tests that string is used if values aren't parseable as numbers
 638 #define EXPR_OP_EQ_PASSES                               \
 639         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 640         PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' "        \
 641         PCMK_XA_ATTRIBUTE "='foo' "                     \
 642         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 643         PCMK_XA_VALUE "='bar' "                         \
 644         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 645 
 646 static void
 647 op_eq_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 648 {
 649     assert_attr_expression(EXPR_OP_EQ_PASSES, pcmk_rc_ok);
 650 }
 651 
 652 #define EXPR_OP_EQ_FAILS                                \
 653         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 654         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 655         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' "       \
 656         PCMK_XA_ATTRIBUTE "='num' "                     \
 657         PCMK_XA_VALUE "='bar' />"
 658 
 659 static void
 660 op_eq_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 661 {
 662     assert_attr_expression(EXPR_OP_EQ_FAILS, pcmk_rc_op_unsatisfied);
 663 }
 664 
 665 #define EXPR_OP_NE_PASSES                               \
 666         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 667         PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' "        \
 668         PCMK_XA_ATTRIBUTE "='foo' "                     \
 669         PCMK_XA_OPERATION "='" PCMK_VALUE_NE "' "       \
 670         PCMK_XA_VALUE "='bat' "                         \
 671         PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
 672 
 673 static void
 674 op_ne_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 675 {
 676     assert_attr_expression(EXPR_OP_NE_PASSES, pcmk_rc_ok);
 677 }
 678 
 679 #define EXPR_OP_NE_FAILS                                \
 680         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 681         PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' "       \
 682         PCMK_XA_OPERATION "='" PCMK_VALUE_NE "' "       \
 683         PCMK_XA_ATTRIBUTE "='num' "                     \
 684         PCMK_XA_VALUE "='10' />"
 685 
 686 static void
 687 op_ne_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 688 {
 689     assert_attr_expression(EXPR_OP_NE_FAILS, pcmk_rc_op_unsatisfied);
 690 }
 691 
 692 #define EXPR_OP_DEFINED_PASSES                          \
 693         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 694         PCMK_XA_ATTRIBUTE "='foo' "                     \
 695         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 696 
 697 static void
 698 op_defined_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 699 {
 700     assert_attr_expression(EXPR_OP_DEFINED_PASSES, pcmk_rc_ok);
 701 }
 702 
 703 #define EXPR_OP_DEFINED_FAILS                           \
 704         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 705         PCMK_XA_ATTRIBUTE "='boo' "                     \
 706         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 707 
 708 static void
 709 op_defined_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 710 {
 711     assert_attr_expression(EXPR_OP_DEFINED_FAILS, pcmk_rc_op_unsatisfied);
 712 }
 713 
 714 #define EXPR_OP_DEFINED_WITH_VALUE                      \
 715         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 716         PCMK_XA_ATTRIBUTE "='foo' "                     \
 717         PCMK_XA_VALUE "='bar' "                         \
 718         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 719 
 720 static void
 721 op_defined_with_value(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 722 {
 723     // Ill-formed but currently accepted
 724     assert_attr_expression(EXPR_OP_DEFINED_WITH_VALUE, pcmk_rc_ok);
 725 }
 726 
 727 #define EXPR_OP_UNDEFINED_PASSES                        \
 728         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 729         PCMK_XA_ATTRIBUTE "='boo' "                     \
 730         PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
 731 
 732 static void
 733 op_undefined_passes(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 734 {
 735     assert_attr_expression(EXPR_OP_UNDEFINED_PASSES, pcmk_rc_ok);
 736 }
 737 
 738 #define EXPR_OP_UNDEFINED_FAILS                         \
 739         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 740         PCMK_XA_ATTRIBUTE "='foo' "                     \
 741         PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
 742 
 743 static void
 744 op_undefined_fails(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 745 {
 746     assert_attr_expression(EXPR_OP_DEFINED_FAILS, pcmk_rc_op_unsatisfied);
 747 }
 748 
 749 
 750 /*
 751  * Test PCMK_XA_VALUE
 752  */
 753 
 754 #define EXPR_VALUE_MISSING_DEFINED_OK                   \
 755         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 756         PCMK_XA_ATTRIBUTE "='num' "                     \
 757         PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
 758 
 759 static void
 760 value_missing_defined_ok(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 761 {
 762     assert_attr_expression(EXPR_VALUE_MISSING_DEFINED_OK, pcmk_rc_ok);
 763 }
 764 
 765 #define EXPR_VALUE_MISSING_EQ_OK                        \
 766         "<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' "   \
 767         PCMK_XA_ATTRIBUTE "='not-an-attr' "             \
 768         PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' />"
 769 
 770 static void
 771 value_missing_eq_ok(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 772 {
 773     // Currently treated as NULL reference value
 774     assert_attr_expression(EXPR_VALUE_MISSING_EQ_OK, pcmk_rc_ok);
 775 }
 776 
 777 
 778 #define expr_test(f) cmocka_unit_test_setup_teardown(f, setup, teardown)
 779 
 780 PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
 781                 cmocka_unit_test(null_invalid),
 782                 expr_test(id_missing),
 783                 expr_test(attr_missing),
 784                 expr_test(attr_with_submatch_passes),
 785                 expr_test(attr_with_submatch_fails),
 786                 expr_test(source_missing),
 787                 expr_test(source_invalid),
 788                 expr_test(source_literal_passes),
 789                 expr_test(source_literal_value_fails),
 790                 expr_test(source_literal_attr_fails),
 791                 expr_test(source_params_missing),
 792                 expr_test(source_params_passes),
 793                 expr_test(source_params_fails),
 794                 expr_test(source_meta_missing),
 795                 expr_test(source_meta_passes),
 796                 expr_test(source_meta_fails),
 797                 expr_test(type_default_number),
 798                 expr_test(type_default_int),
 799                 expr_test(type_string_passes),
 800                 expr_test(type_string_fails),
 801                 expr_test(type_integer_passes),
 802                 expr_test(type_integer_fails),
 803                 expr_test(type_integer_truncation),
 804                 expr_test(type_number_passes),
 805                 expr_test(type_number_fails),
 806                 expr_test(type_version_passes),
 807                 expr_test(type_version_equality),
 808                 expr_test(type_version_fails),
 809                 expr_test(op_missing),
 810                 expr_test(op_invalid),
 811                 expr_test(op_lt_passes),
 812                 expr_test(op_lt_fails),
 813                 expr_test(op_gt_passes),
 814                 expr_test(op_gt_fails),
 815                 expr_test(op_lte_lt_passes),
 816                 expr_test(op_lte_eq_passes),
 817                 expr_test(op_lte_fails),
 818                 expr_test(op_gte_gt_passes),
 819                 expr_test(op_gte_eq_passes),
 820                 expr_test(op_gte_fails),
 821                 expr_test(op_eq_passes),
 822                 expr_test(op_eq_fails),
 823                 expr_test(op_ne_passes),
 824                 expr_test(op_ne_fails),
 825                 expr_test(op_defined_passes),
 826                 expr_test(op_defined_fails),
 827                 expr_test(op_defined_with_value),
 828                 expr_test(op_undefined_passes),
 829                 expr_test(op_undefined_fails),
 830                 expr_test(value_missing_defined_ok),
 831                 expr_test(value_missing_eq_ok))

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