pacemaker  2.1.9-49aab99839
Scalable High-Availability cluster resource manager
pcmk_evaluate_rule_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 
19 /*
20  * Shared data
21  */
22 
23 static pcmk_rule_input_t rule_input = {
25  .rsc_provider = "heartbeat",
26  .rsc_agent = "IPaddr2",
27  .op_name = PCMK_ACTION_MONITOR,
28  .op_interval_ms = 10000,
29 };
30 
31 
32 /*
33  * Test invalid arguments
34  */
35 
36 #define RULE_OP \
37  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' > " \
38  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
39  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
40  PCMK_XA_INTERVAL "='10s' />" \
41  "</" PCMK_XE_RULE ">"
42 
43 static void
44 null_invalid(void **state)
45 {
46  xmlNode *xml = NULL;
47  crm_time_t *next_change = crm_time_new_undefined();
48 
49  assert_int_equal(pcmk_evaluate_rule(NULL, NULL, next_change),
50  EINVAL);
51 
52  xml = pcmk__xml_parse(RULE_OP);
53  assert_int_equal(pcmk_evaluate_rule(xml, NULL, next_change), EINVAL);
54  free_xml(xml);
55 
56  assert_int_equal(pcmk_evaluate_rule(NULL, &rule_input, next_change),
57  EINVAL);
58 
59  crm_time_free(next_change);
60 }
61 
62 #define RULE_OP_MISSING_ID \
63  "<" PCMK_XE_RULE "> " \
64  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
65  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
66  PCMK_XA_INTERVAL "='10s' />" \
67  "</" PCMK_XE_RULE ">"
68 
69 static void
70 id_missing(void **state)
71 {
72  // Currently acceptable
73  xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID);
74  crm_time_t *next_change = crm_time_new_undefined();
75 
76  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change),
77  pcmk_rc_ok);
78 
79  crm_time_free(next_change);
80  free_xml(xml);
81 }
82 
83 #define RULE_IDREF_PARENT "<" PCMK_XE_CIB ">" RULE_OP "</" PCMK_XE_CIB ">"
84 
85 static void
86 good_idref(void **state)
87 {
88  xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
89  xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
90  crm_time_t *next_change = crm_time_new_undefined();
91 
92  crm_xml_add(rule_xml, PCMK_XA_ID_REF, "r");
93  assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
94  pcmk_rc_ok);
95 
96  crm_time_free(next_change);
97  free_xml(parent_xml);
98 }
99 
100 static void
101 bad_idref(void **state)
102 {
103  xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
104  xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
105  crm_time_t *next_change = crm_time_new_undefined();
106 
107  crm_xml_add(rule_xml, PCMK_XA_ID_REF, "x");
108  assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
110 
111  crm_time_free(next_change);
112  free_xml(parent_xml);
113 }
114 
115 #define RULE_EMPTY "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' />"
116 
117 static void
118 empty_default(void **state)
119 {
120  // Currently acceptable
121  xmlNode *xml = pcmk__xml_parse(RULE_EMPTY);
122 
123  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
124  pcmk_rc_ok);
125 
126  free_xml(xml);
127 }
128 
129 #define RULE_EMPTY_AND \
130  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
131  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' />"
132 
133 static void
134 empty_and(void **state)
135 {
136  // Currently acceptable
137  xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_AND);
138 
139  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
140  pcmk_rc_ok);
141 
142  free_xml(xml);
143 }
144 
145 #define RULE_EMPTY_OR \
146  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
147  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' />"
148 
149 static void
150 empty_or(void **state)
151 {
152  // Currently treated as unsatisfied
153  xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_OR);
154 
155  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
157 
158  free_xml(xml);
159 }
160 
161 #define RULE_DEFAULT_BOOLEAN_OP \
162  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' >" \
163  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
164  PCMK_XA_TYPE "='Dummy' />" \
165  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
166  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
167  PCMK_XA_INTERVAL "='10s' />" \
168  "</" PCMK_XE_RULE ">"
169 
170 static void
171 default_boolean_op(void **state)
172 {
173  // Defaults to PCMK_VALUE_AND
175 
176  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
178 
179  free_xml(xml);
180 }
181 
182 #define RULE_INVALID_BOOLEAN_OP \
183  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
184  PCMK_XA_BOOLEAN_OP "='not-an-op' >" \
185  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
186  PCMK_XA_TYPE "='Dummy' />" \
187  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
188  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
189  PCMK_XA_INTERVAL "='10s' />" \
190  "</" PCMK_XE_RULE ">"
191 
192 static void
193 invalid_boolean_op(void **state)
194 {
195  // Currently defaults to PCMK_VALUE_AND
197 
198  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
200 
201  free_xml(xml);
202 }
203 
204 #define RULE_AND_PASSES \
205  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
206  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
207  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
208  PCMK_XA_TYPE "='IPaddr2' />" \
209  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
210  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
211  PCMK_XA_INTERVAL "='10s' />" \
212  "</" PCMK_XE_RULE ">"
213 
214 static void
215 and_passes(void **state)
216 {
217  xmlNode *xml = pcmk__xml_parse(RULE_AND_PASSES);
218 
219  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
220 
221  free_xml(xml);
222 }
223 
224 #define RULE_LONELY_AND \
225  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
226  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
227  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
228  PCMK_XA_TYPE "='IPaddr2' />" \
229  "</" PCMK_XE_RULE ">"
230 
231 static void
232 lonely_and_passes(void **state)
233 {
234  xmlNode *xml = pcmk__xml_parse(RULE_LONELY_AND);
235 
236  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
237 
238  free_xml(xml);
239 }
240 
241 #define RULE_AND_ONE_FAILS \
242  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
243  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
244  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
245  PCMK_XA_TYPE "='Dummy' />" \
246  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
247  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
248  PCMK_XA_INTERVAL "='10s' />" \
249  "</" PCMK_XE_RULE ">"
250 
251 static void
252 and_one_fails(void **state)
253 {
254  xmlNode *xml = pcmk__xml_parse(RULE_AND_ONE_FAILS);
255 
256  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
258 
259  free_xml(xml);
260 }
261 
262 #define RULE_AND_TWO_FAIL \
263  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
264  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
265  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
266  PCMK_XA_TYPE "='Dummy' />" \
267  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
268  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
269  PCMK_XA_INTERVAL "='9s' />" \
270  "</" PCMK_XE_RULE ">"
271 
272 static void
273 and_two_fail(void **state)
274 {
275  xmlNode *xml = pcmk__xml_parse(RULE_AND_TWO_FAIL);
276 
277  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
279 
280  free_xml(xml);
281 }
282 
283 #define RULE_OR_ONE_PASSES \
284  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
285  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
286  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
287  PCMK_XA_TYPE "='Dummy' />" \
288  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
289  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
290  PCMK_XA_INTERVAL "='10s' />" \
291  "</" PCMK_XE_RULE ">"
292 
293 static void
294 or_one_passes(void **state)
295 {
296  xmlNode *xml = pcmk__xml_parse(RULE_OR_ONE_PASSES);
297 
298  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
299 
300  free_xml(xml);
301 }
302 
303 #define RULE_OR_TWO_PASS \
304  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
305  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
306  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
307  PCMK_XA_TYPE "='IPAddr2' />" \
308  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
309  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
310  PCMK_XA_INTERVAL "='10s' />" \
311  "</" PCMK_XE_RULE ">"
312 
313 static void
314 or_two_pass(void **state)
315 {
316  xmlNode *xml = pcmk__xml_parse(RULE_OR_TWO_PASS);
317 
318  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
319 
320  free_xml(xml);
321 }
322 
323 #define RULE_LONELY_OR \
324  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
325  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
326  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
327  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
328  PCMK_XA_INTERVAL "='10s' />" \
329  "</" PCMK_XE_RULE ">"
330 
331 static void
332 lonely_or_passes(void **state)
333 {
334  xmlNode *xml = pcmk__xml_parse(RULE_LONELY_OR);
335 
336  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
337 
338  free_xml(xml);
339 }
340 
341 #define RULE_OR_FAILS \
342  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
343  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
344  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
345  PCMK_XA_TYPE "='Dummy' />" \
346  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
347  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
348  PCMK_XA_INTERVAL "='20s' />" \
349  "</" PCMK_XE_RULE ">"
350 
351 static void
352 or_fails(void **state)
353 {
354  xmlNode *xml = pcmk__xml_parse(RULE_OR_FAILS);
355 
356  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
358 
359  free_xml(xml);
360 }
361 
363  cmocka_unit_test(null_invalid),
364  cmocka_unit_test(id_missing),
365  cmocka_unit_test(good_idref),
366  cmocka_unit_test(bad_idref),
367  cmocka_unit_test(empty_default),
368  cmocka_unit_test(empty_and),
369  cmocka_unit_test(empty_or),
370  cmocka_unit_test(default_boolean_op),
371  cmocka_unit_test(invalid_boolean_op),
372  cmocka_unit_test(and_passes),
373  cmocka_unit_test(lonely_and_passes),
374  cmocka_unit_test(and_one_fails),
375  cmocka_unit_test(and_two_fail),
376  cmocka_unit_test(or_one_passes),
377  cmocka_unit_test(or_two_pass),
378  cmocka_unit_test(lonely_or_passes),
379  cmocka_unit_test(or_fails))
crm_time_t * crm_time_new_undefined(void)
Allocate memory for an uninitialized time object.
Definition: iso8601.c:129
#define RULE_OR_TWO_PASS
Data used to evaluate a rule (any NULL items are ignored)
Definition: rules.h:57
#define RULE_INVALID_BOOLEAN_OP
struct crm_time_s crm_time_t
Definition: iso8601.h:32
#define PCMK_ACTION_MONITOR
Definition: actions.h:60
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:313
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)
#define PCMK_RESOURCE_CLASS_OCF
Definition: agents.h:27
#define RULE_AND_TWO_FAIL
#define PCMK_XA_ID_REF
Definition: xml_names.h:303
int pcmk_evaluate_rule(xmlNode *rule, const pcmk_rule_input_t *rule_input, crm_time_t *next_change)
Evaluate a single rule, including all its conditions.
Definition: rules.c:1386
#define RULE_OR_ONE_PASSES
#define RULE_EMPTY_AND
int pcmk__xml_test_setup_group(void **state)
Definition: unittest.c:85
Wrappers for and extensions to libxml2.
#define RULE_AND_ONE_FAILS
const char * rsc_standard
Resource standard that rule applies to.
Definition: rules.h:62
#define RULE_IDREF_PARENT
void free_xml(xmlNode *child)
Definition: xml.c:958
#define RULE_LONELY_AND
int pcmk__xml_test_teardown_group(void **state)
Definition: unittest.c:104
#define PCMK_XE_RULE
Definition: xml_names.h:191
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:245
#define RULE_AND_PASSES
#define RULE_OP_MISSING_ID
#define RULE_LONELY_OR
#define RULE_EMPTY_OR
#define RULE_OP
#define RULE_EMPTY
#define RULE_DEFAULT_BOOLEAN_OP
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml.c:770
#define RULE_OR_FAILS
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150