pacemaker  3.0.0-d8340737c4
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  pcmk__xml_free(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  xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID);
73  crm_time_t *next_change = crm_time_new_undefined();
74 
75  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change),
77 
78  crm_time_free(next_change);
79  pcmk__xml_free(xml);
80 }
81 
82 #define RULE_IDREF_PARENT "<" PCMK_XE_CIB ">" RULE_OP "</" PCMK_XE_CIB ">"
83 
84 static void
85 good_idref(void **state)
86 {
87  xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
88  xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
89  crm_time_t *next_change = crm_time_new_undefined();
90 
91  crm_xml_add(rule_xml, PCMK_XA_ID_REF, "r");
92  assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
93  pcmk_rc_ok);
94 
95  crm_time_free(next_change);
96  pcmk__xml_free(parent_xml);
97 }
98 
99 static void
100 bad_idref(void **state)
101 {
102  xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
103  xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
104  crm_time_t *next_change = crm_time_new_undefined();
105 
106  crm_xml_add(rule_xml, PCMK_XA_ID_REF, "x");
107  assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
109 
110  crm_time_free(next_change);
111  pcmk__xml_free(parent_xml);
112 }
113 
114 #define RULE_EMPTY "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' />"
115 
116 static void
117 empty_default(void **state)
118 {
119  // Currently acceptable
120  xmlNode *xml = pcmk__xml_parse(RULE_EMPTY);
121 
122  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
123  pcmk_rc_ok);
124 
125  pcmk__xml_free(xml);
126 }
127 
128 #define RULE_EMPTY_AND \
129  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
130  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' />"
131 
132 static void
133 empty_and(void **state)
134 {
135  // Currently acceptable
136  xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_AND);
137 
138  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
139  pcmk_rc_ok);
140 
141  pcmk__xml_free(xml);
142 }
143 
144 #define RULE_EMPTY_OR \
145  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
146  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' />"
147 
148 static void
149 empty_or(void **state)
150 {
151  xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_OR);
152 
153  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
154  pcmk_rc_ok);
155 
156  pcmk__xml_free(xml);
157 }
158 
159 #define RULE_DEFAULT_BOOLEAN_OP \
160  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' >" \
161  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
162  PCMK_XA_TYPE "='Dummy' />" \
163  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
164  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
165  PCMK_XA_INTERVAL "='10s' />" \
166  "</" PCMK_XE_RULE ">"
167 
168 static void
169 default_boolean_op(void **state)
170 {
171  // Defaults to PCMK_VALUE_AND
173 
174  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
176 
177  pcmk__xml_free(xml);
178 }
179 
180 #define RULE_INVALID_BOOLEAN_OP \
181  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
182  PCMK_XA_BOOLEAN_OP "='not-an-op' >" \
183  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
184  PCMK_XA_TYPE "='Dummy' />" \
185  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
186  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
187  PCMK_XA_INTERVAL "='10s' />" \
188  "</" PCMK_XE_RULE ">"
189 
190 static void
191 invalid_boolean_op(void **state)
192 {
194 
195  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
197 
198  pcmk__xml_free(xml);
199 }
200 
201 #define RULE_AND_PASSES \
202  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
203  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
204  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
205  PCMK_XA_TYPE "='IPaddr2' />" \
206  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
207  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
208  PCMK_XA_INTERVAL "='10s' />" \
209  "</" PCMK_XE_RULE ">"
210 
211 static void
212 and_passes(void **state)
213 {
214  xmlNode *xml = pcmk__xml_parse(RULE_AND_PASSES);
215 
216  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
217 
218  pcmk__xml_free(xml);
219 }
220 
221 #define RULE_LONELY_AND \
222  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
223  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
224  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
225  PCMK_XA_TYPE "='IPaddr2' />" \
226  "</" PCMK_XE_RULE ">"
227 
228 static void
229 lonely_and_passes(void **state)
230 {
231  xmlNode *xml = pcmk__xml_parse(RULE_LONELY_AND);
232 
233  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
234 
235  pcmk__xml_free(xml);
236 }
237 
238 #define RULE_AND_ONE_FAILS \
239  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
240  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
241  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
242  PCMK_XA_TYPE "='Dummy' />" \
243  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
244  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
245  PCMK_XA_INTERVAL "='10s' />" \
246  "</" PCMK_XE_RULE ">"
247 
248 static void
249 and_one_fails(void **state)
250 {
251  xmlNode *xml = pcmk__xml_parse(RULE_AND_ONE_FAILS);
252 
253  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
255 
256  pcmk__xml_free(xml);
257 }
258 
259 #define RULE_AND_TWO_FAIL \
260  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
261  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
262  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
263  PCMK_XA_TYPE "='Dummy' />" \
264  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
265  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
266  PCMK_XA_INTERVAL "='9s' />" \
267  "</" PCMK_XE_RULE ">"
268 
269 static void
270 and_two_fail(void **state)
271 {
272  xmlNode *xml = pcmk__xml_parse(RULE_AND_TWO_FAIL);
273 
274  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
276 
277  pcmk__xml_free(xml);
278 }
279 
280 #define RULE_OR_ONE_PASSES \
281  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
282  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
283  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
284  PCMK_XA_TYPE "='Dummy' />" \
285  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
286  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
287  PCMK_XA_INTERVAL "='10s' />" \
288  "</" PCMK_XE_RULE ">"
289 
290 static void
291 or_one_passes(void **state)
292 {
293  xmlNode *xml = pcmk__xml_parse(RULE_OR_ONE_PASSES);
294 
295  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
296 
297  pcmk__xml_free(xml);
298 }
299 
300 #define RULE_OR_TWO_PASS \
301  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
302  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
303  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
304  PCMK_XA_TYPE "='IPAddr2' />" \
305  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
306  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
307  PCMK_XA_INTERVAL "='10s' />" \
308  "</" PCMK_XE_RULE ">"
309 
310 static void
311 or_two_pass(void **state)
312 {
313  xmlNode *xml = pcmk__xml_parse(RULE_OR_TWO_PASS);
314 
315  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
316 
317  pcmk__xml_free(xml);
318 }
319 
320 #define RULE_LONELY_OR \
321  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
322  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
323  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
324  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
325  PCMK_XA_INTERVAL "='10s' />" \
326  "</" PCMK_XE_RULE ">"
327 
328 static void
329 lonely_or_passes(void **state)
330 {
331  xmlNode *xml = pcmk__xml_parse(RULE_LONELY_OR);
332 
333  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
334 
335  pcmk__xml_free(xml);
336 }
337 
338 #define RULE_OR_FAILS \
339  "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
340  PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
341  " <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
342  PCMK_XA_TYPE "='Dummy' />" \
343  " <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
344  PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
345  PCMK_XA_INTERVAL "='20s' />" \
346  "</" PCMK_XE_RULE ">"
347 
348 static void
349 or_fails(void **state)
350 {
351  xmlNode *xml = pcmk__xml_parse(RULE_OR_FAILS);
352 
353  assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
355 
356  pcmk__xml_free(xml);
357 }
358 
360  cmocka_unit_test(null_invalid),
361  cmocka_unit_test(id_missing),
362  cmocka_unit_test(good_idref),
363  cmocka_unit_test(bad_idref),
364  cmocka_unit_test(empty_default),
365  cmocka_unit_test(empty_and),
366  cmocka_unit_test(empty_or),
367  cmocka_unit_test(default_boolean_op),
368  cmocka_unit_test(invalid_boolean_op),
369  cmocka_unit_test(and_passes),
370  cmocka_unit_test(lonely_and_passes),
371  cmocka_unit_test(and_one_fails),
372  cmocka_unit_test(and_two_fail),
373  cmocka_unit_test(or_one_passes),
374  cmocka_unit_test(or_two_pass),
375  cmocka_unit_test(lonely_or_passes),
376  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:51
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)
#define PCMK_RESOURCE_CLASS_OCF
Definition: agents.h:27
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
#define RULE_AND_TWO_FAIL
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
#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:1303
#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
#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:168
#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
#define RULE_OR_FAILS
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150