pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk__evaluate_attr_expression_test.c
Go to the documentation of this file.
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>
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
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)
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)
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 
86 static void
87 assert_attr_expression(const char *xml_string, int reference_rc)
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)
110 {
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)
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)
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)
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)
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)
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)
202 {
203  assert_attr_expression(EXPR_SOURCE_INVALID, pcmk_rc_unpack_error);
204 }
205 
206 static void
207 source_literal_passes(void **state)
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)
221 {
222  assert_attr_expression(EXPR_SOURCE_LITERAL_VALUE_FAILS,
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)
235 {
236  assert_attr_expression(EXPR_SOURCE_LITERAL_ATTR_FAILS,
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
697 {
698  assert_attr_expression(EXPR_EQ_UNDEFINED_VS_EMPTY_FAILS,
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)
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)
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)
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)
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)
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)
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)
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)
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)
803 {
804  assert_attr_expression(EXPR_OP_UNDEFINED_EMPTY_FAILS,
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)
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)
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 
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))
#define EXPR_VALUE_MISSING_EQ_FAILS
#define EXPR_VALUE_MISSING_DEFINED_OK
GHashTable * rsc_meta
Definition: rules.h:93
#define EXPR_TYPE_VERSION_FAILS
Data used to evaluate a rule (any NULL items are ignored)
Definition: rules.h:57
#define EXPR_SOURCE_META_PASSES
#define EXPR_TYPE_INTEGER_TRUNCATION
GHashTable * rsc_params
Definition: rules.h:86
#define EXPR_EQ_EMPTY_VS_EMPTY_PASSES
#define EXPR_OP_UNDEFINED_PASSES
G_GNUC_INTERNAL int pcmk__evaluate_attr_expression(const xmlNode *expression, const pcmk_rule_input_t *rule_input)
Definition: rules.c:957
#define EXPR_SOURCE_PARAM_FAILS
#define EXPR_TYPE_DEFAULT_NUMBER
#define EXPR_TYPE_VERSION_PASSES
#define EXPR_TYPE_NUMBER_FAILS
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)
#define EXPR_OP_DEFINED_WITH_VALUE
#define EXPR_SOURCE_PARAM_MISSING
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
#define EXPR_TYPE_STRING_PASSES
#define EXPR_SOURCE_LITERAL_VALUE_FAILS
#define EXPR_OP_DEFINED_EMPTY_PASSES
#define EXPR_OP_DEFINED_PASSES
int pcmk__xml_test_setup_group(void **state)
Definition: unittest.c:85
Wrappers for and extensions to libxml2.
#define EXPR_OP_UNDEFINED_FAILS
#define EXPR_SOURCE_LITERAL_ATTR_FAILS
#define EXPR_ATTR_SUBMATCH_PASSES
#define EXPR_SOURCE_LITERAL_PASSES
int pcmk__xml_test_teardown_group(void **state)
Definition: unittest.c:104
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:168
#define EXPR_TYPE_INTEGER_FAILS
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:685
#define EXPR_OP_UNDEFINED_EMPTY_FAILS
#define EXPR_TYPE_STRING_FAILS
GHashTable * node_attrs
Definition: rules.h:77
#define EXPR_TYPE_NUMBER_PASSES
#define EXPR_EQ_UNDEFINED_VS_EMPTY_FAILS
#define EXPR_TYPE_INTEGER_PASSES
#define EXPR_SOURCE_META_MISSING
#define EXPR_TYPE_VERSION_EQUALITY
#define EXPR_ATTR_SUBMATCH_FAILS
const char * rsc_id
Resource ID to compare against a location constraint&#39;s resource pattern.
Definition: rules.h:96
void pcmk__insert_dup(GHashTable *table, const char *name, const char *value)
Definition: strings.c:703
#define EXPR_SOURCE_PARAM_PASSES
#define EXPR_SOURCE_META_FAILS