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

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

DEFINITIONS

This source file includes following definitions.
  1. assert_date_expression
  2. null_invalid
  3. null_next_change_ok
  4. id_missing
  5. op_invalid
  6. lt_missing_end
  7. lt_invalid_end
  8. lt_valid
  9. gt_missing_start
  10. gt_invalid_start
  11. gt_valid
  12. range_missing
  13. range_invalid_start_invalid_end
  14. range_invalid_start_only
  15. range_valid_start_only
  16. range_invalid_end_only
  17. range_valid_end_only
  18. range_valid_start_invalid_end
  19. range_invalid_start_valid_end
  20. range_valid_start_valid_end
  21. range_valid_start_invalid_duration
  22. range_valid_start_valid_duration
  23. range_valid_start_duration_missing_id
  24. spec_missing
  25. spec_invalid
  26. spec_valid
  27. spec_missing_id

   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  * \internal
  22  * \brief Run one test, comparing return value and output argument
  23  *
  24  * \param[in] xml            Date expression XML
  25  * \param[in] now_s          Time to evaluate expression with (as string)
  26  * \param[in] next_change_s  If this and \p reference_s are not NULL, initialize
  27  *                           next change time with this time (as string),
  28  *                           and assert that its value after evaluation is the
  29  *                           reference
  30  * \param[in] reference_s    If not NULL, time (as string) that next change
  31  *                           should be after expression evaluation
  32  * \param[in] reference_rc   Assert that evaluation result equals this
  33  */
  34 static void
  35 assert_date_expression(const xmlNode *xml, const char *now_s,
     /* [previous][next][first][last][top][bottom][index][help] */
  36                        const char *next_change_s, const char *reference_s,
  37                        int reference_rc)
  38 {
  39     crm_time_t *now = NULL;
  40     crm_time_t *next_change = NULL;
  41     bool check_next_change = (next_change_s != NULL) && (reference_s != NULL);
  42 
  43     if (check_next_change) {
  44         next_change = crm_time_new(next_change_s);
  45     }
  46 
  47     now = crm_time_new(now_s);
  48     assert_int_equal(pcmk__evaluate_date_expression(xml, now, next_change),
  49                      reference_rc);
  50     crm_time_free(now);
  51 
  52     if (check_next_change) {
  53         crm_time_t *reference = crm_time_new(reference_s);
  54 
  55         assert_int_equal(crm_time_compare(next_change, reference), 0);
  56         crm_time_free(reference);
  57         crm_time_free(next_change);
  58     }
  59 }
  60 
  61 #define EXPR_LT_VALID                                   \
  62     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
  63         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "       \
  64         PCMK_XA_END "='2024-02-01 15:00:00' />"
  65 
  66 static void
  67 null_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
  70     crm_time_t *t = crm_time_new("2024-02-01");
  71 
  72     assert_int_equal(pcmk__evaluate_date_expression(NULL, NULL, NULL), EINVAL);
  73     assert_int_equal(pcmk__evaluate_date_expression(xml, NULL, NULL), EINVAL);
  74     assert_int_equal(pcmk__evaluate_date_expression(NULL, t, NULL), EINVAL);
  75 
  76     crm_time_free(t);
  77     free_xml(xml);
  78 }
  79 
  80 static void
  81 null_next_change_ok(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
  84 
  85     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_within_range);
  86     free_xml(xml);
  87 }
  88 
  89 #define EXPR_ID_MISSING                             \
  90     "<" PCMK_XE_DATE_EXPRESSION " "                 \
  91         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "   \
  92         PCMK_XA_END "='2024-02-01 15:00:00' />"
  93 
  94 static void
  95 id_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97     // Currently acceptable
  98     xmlNodePtr xml = pcmk__xml_parse(EXPR_ID_MISSING);
  99 
 100     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_within_range);
 101     free_xml(xml);
 102 }
 103 
 104 #define EXPR_OP_INVALID                                 \
 105     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 106         PCMK_XA_OPERATION "='not-a-choice' />"
 107 
 108 static void
 109 op_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111     xmlNodePtr xml = pcmk__xml_parse(EXPR_OP_INVALID);
 112 
 113     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 114     free_xml(xml);
 115 }
 116 
 117 #define EXPR_LT_MISSING_END                             \
 118     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 119         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' />"
 120 
 121 static void
 122 lt_missing_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_MISSING_END);
 125 
 126     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 127     free_xml(xml);
 128 }
 129 
 130 #define EXPR_LT_INVALID_END                             \
 131     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 132     PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "           \
 133     PCMK_XA_END "='not-a-datetime' />"
 134 
 135 static void
 136 lt_invalid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 137 {
 138     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_INVALID_END);
 139 
 140     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 141     free_xml(xml);
 142 }
 143 
 144 static void
 145 lt_valid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
 148 
 149     // Now and next change are both before end
 150     assert_date_expression(xml, "2023-01-01 05:00:00", "2024-02-01 10:00:00",
 151                            "2024-02-01 10:00:00", pcmk_rc_within_range);
 152 
 153     // Now is before end, next change is after end
 154     assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
 155                            "2024-02-01 15:00:00", pcmk_rc_within_range);
 156 
 157     // Now is equal to end, next change is after end
 158     assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 20:00:00",
 159                            "2024-02-01 20:00:00", pcmk_rc_after_range);
 160 
 161     // Now and next change are both after end
 162     assert_date_expression(xml, "2024-03-01 12:00:00", "2024-02-01 20:00:00",
 163                            "2024-02-01 20:00:00", pcmk_rc_after_range);
 164 
 165     free_xml(xml);
 166 }
 167 
 168 #define EXPR_GT_MISSING_START                           \
 169     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 170     PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' />"
 171 
 172 static void
 173 gt_missing_start(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175     xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_MISSING_START);
 176 
 177     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 178     free_xml(xml);
 179 }
 180 
 181 #define EXPR_GT_INVALID_START                           \
 182     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 183     PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "           \
 184     PCMK_XA_START "='not-a-datetime' />"
 185 
 186 static void
 187 gt_invalid_start(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 188 {
 189     xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_INVALID_START);
 190 
 191     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 192     free_xml(xml);
 193 }
 194 
 195 #define EXPR_GT_VALID                                   \
 196     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 197     PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "           \
 198     PCMK_XA_START "='2024-02-01 12:00:00' />"
 199 
 200 static void
 201 gt_valid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 202 {
 203     xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_VALID);
 204 
 205     // Now and next change are both before start
 206     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 207                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 208 
 209     // Now is before start, next change is after start
 210     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
 211                            "2024-02-01 12:00:01", pcmk_rc_before_range);
 212 
 213     // Now is equal to start, next change is after start
 214     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
 215                            "2024-02-01 12:00:01", pcmk_rc_before_range);
 216 
 217     // Now is one second after start, next change is after start
 218     assert_date_expression(xml, "2024-02-01 12:00:01", "2024-02-01 18:00:00",
 219                            "2024-02-01 18:00:00", pcmk_rc_within_range);
 220 
 221     // t is after start, next change is after start
 222     assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
 223                            "2024-04-04 04:04:04", pcmk_rc_within_range);
 224 
 225     free_xml(xml);
 226 }
 227 
 228 #define EXPR_RANGE_MISSING                              \
 229     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 230     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' />"
 231 
 232 static void
 233 range_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 234 {
 235     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_MISSING);
 236     crm_time_t *t = crm_time_new("2024-01-01");
 237 
 238     assert_int_equal(pcmk__evaluate_date_expression(xml, t, NULL),
 239                      pcmk_rc_undetermined);
 240 
 241     crm_time_free(t);
 242     free_xml(xml);
 243 }
 244 
 245 #define EXPR_RANGE_INVALID_START_INVALID_END            \
 246     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 247     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 248     PCMK_XA_START "='not-a-date' "                      \
 249     PCMK_XA_END "='not-a-date' />"
 250 
 251 static void
 252 range_invalid_start_invalid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_INVALID_END);
 255 
 256     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 257     free_xml(xml);
 258 }
 259 
 260 #define EXPR_RANGE_INVALID_START_ONLY                   \
 261     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 262     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 263     PCMK_XA_START "='not-a-date' />"
 264 
 265 static void
 266 range_invalid_start_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 267 {
 268     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_ONLY);
 269 
 270     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 271     free_xml(xml);
 272 }
 273 
 274 #define EXPR_RANGE_VALID_START_ONLY                     \
 275     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 276     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 277     PCMK_XA_START "='2024-02-01 12:00:00' />"
 278 
 279 static void
 280 range_valid_start_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_ONLY);
 283 
 284     // Now and next change are before start
 285     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 286                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 287 
 288     // Now is before start, next change is after start
 289     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
 290                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 291 
 292     // Now is equal to start, next change is after start
 293     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
 294                            "2024-02-01 18:00:00", pcmk_rc_within_range);
 295 
 296     // Now and next change are after start
 297     assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
 298                            "2024-04-04 04:04:04", pcmk_rc_within_range);
 299 
 300     free_xml(xml);
 301 }
 302 
 303 #define EXPR_RANGE_INVALID_END_ONLY                   \
 304     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 305     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 306     PCMK_XA_END "='not-a-date' />"
 307 
 308 static void
 309 range_invalid_end_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 310 {
 311     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_END_ONLY);
 312 
 313     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 314     free_xml(xml);
 315 }
 316 
 317 #define EXPR_RANGE_VALID_END_ONLY                     \
 318     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 319     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 320     PCMK_XA_END "='2024-02-01 15:00:00' />"
 321 
 322 static void
 323 range_valid_end_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 324 {
 325     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_END_ONLY);
 326 
 327     // Now and next change are before end
 328     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 329                            "2024-01-01 11:00:00", pcmk_rc_within_range);
 330 
 331     // Now is before end, next change is after end
 332     assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
 333                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 334 
 335     // Now is equal to end, next change is after end
 336     assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00",
 337                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 338 
 339     // Now and next change are after end
 340     assert_date_expression(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04",
 341                            "2024-04-04 04:04:04", pcmk_rc_after_range);
 342 
 343     free_xml(xml);
 344 }
 345 
 346 #define EXPR_RANGE_VALID_START_INVALID_END              \
 347     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 348     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 349     PCMK_XA_START "='2024-02-01 12:00:00' "             \
 350     PCMK_XA_END "='not-a-date' />"
 351 
 352 static void
 353 range_valid_start_invalid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 354 {
 355     // Currently treated same as start without end
 356     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_END);
 357 
 358     // Now and next change are before start
 359     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 360                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 361 
 362     // Now is before start, next change is after start
 363     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
 364                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 365 
 366     // Now is equal to start, next change is after start
 367     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
 368                            "2024-02-01 18:00:00", pcmk_rc_within_range);
 369 
 370     // Now and next change are after start
 371     assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
 372                            "2024-04-04 04:04:04", pcmk_rc_within_range);
 373 
 374     free_xml(xml);
 375 }
 376 
 377 #define EXPR_RANGE_INVALID_START_VALID_END              \
 378     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 379     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 380     PCMK_XA_START "='not-a-date' "                      \
 381     PCMK_XA_END "='2024-02-01 15:00:00' />"
 382 
 383 static void
 384 range_invalid_start_valid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386     // Currently treated same as end without start
 387     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_VALID_END);
 388 
 389     // Now and next change are before end
 390     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 391                            "2024-01-01 11:00:00", pcmk_rc_within_range);
 392 
 393     // Now is before end, next change is after end
 394     assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
 395                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 396 
 397     // Now is equal to end, next change is after end
 398     assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00",
 399                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 400 
 401     // Now and next change are after end
 402     assert_date_expression(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04",
 403                            "2024-04-04 04:04:04", pcmk_rc_after_range);
 404 
 405     free_xml(xml);
 406 }
 407 
 408 #define EXPR_RANGE_VALID_START_VALID_END                \
 409     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 410     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 411     PCMK_XA_START "='2024-02-01 12:00:00' "             \
 412     PCMK_XA_END "='2024-02-01 15:00:00' />"
 413 
 414 static void
 415 range_valid_start_valid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 416 {
 417     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_END);
 418 
 419     // Now and next change are before start
 420     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 421                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 422 
 423     // Now is before start, next change is between start and end
 424     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
 425                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 426 
 427     // Now is equal to start, next change is between start and end
 428     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
 429                            "2024-02-01 14:30:00", pcmk_rc_within_range);
 430 
 431     // Now is between start and end, next change is after end
 432     assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
 433                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 434 
 435     // Now is equal to end, next change is after end
 436     assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
 437                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 438 
 439     // Now and next change are after end
 440     assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
 441                            "2028-04-04 04:04:04", pcmk_rc_after_range);
 442 
 443     free_xml(xml);
 444 }
 445 
 446 #define EXPR_RANGE_VALID_START_INVALID_DURATION         \
 447     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 448     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 449     PCMK_XA_START "='2024-02-01 12:00:00'>"             \
 450     "<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' "         \
 451     PCMK_XA_HOURS "='not-a-number' />"                  \
 452     "</" PCMK_XE_DATE_EXPRESSION ">"
 453 
 454 static void
 455 range_valid_start_invalid_duration(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 456 {
 457     // Currently treated same as end equals start
 458     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_DURATION);
 459 
 460     // Now and next change are before start
 461     assert_date_expression(xml, "2024-02-01 04:30:05", "2024-01-01 11:00:00",
 462                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 463 
 464     // Now is before start, next change is after start
 465     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
 466                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 467 
 468     // Now is equal to start, next change is after start
 469     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
 470                            "2024-02-01 12:00:01", pcmk_rc_within_range);
 471 
 472     // Now and next change are after start
 473     assert_date_expression(xml, "2024-02-01 12:00:01", "2024-02-01 14:30:00",
 474                            "2024-02-01 14:30:00", pcmk_rc_after_range);
 475 
 476     free_xml(xml);
 477 }
 478 
 479 #define EXPR_RANGE_VALID_START_VALID_DURATION           \
 480     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 481     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 482     PCMK_XA_START "='2024-02-01 12:00:00'>"             \
 483     "<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' "         \
 484     PCMK_XA_HOURS "='3' />"                             \
 485     "</" PCMK_XE_DATE_EXPRESSION ">"
 486 
 487 static void
 488 range_valid_start_valid_duration(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_DURATION);
 491 
 492     // Now and next change are before start
 493     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 494                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 495 
 496     // Now is before start, next change is between start and end
 497     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
 498                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 499 
 500     // Now is equal to start, next change is between start and end
 501     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
 502                            "2024-02-01 14:30:00", pcmk_rc_within_range);
 503 
 504     // Now is between start and end, next change is after end
 505     assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
 506                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 507 
 508     // Now is equal to end, next change is after end
 509     assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
 510                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 511 
 512     // Now and next change are after end
 513     assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
 514                            "2028-04-04 04:04:04", pcmk_rc_after_range);
 515 
 516     free_xml(xml);
 517 }
 518 
 519 #define EXPR_RANGE_VALID_START_DURATION_MISSING_ID      \
 520     "<" PCMK_XE_DATE_EXPRESSION " "                     \
 521     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 522     PCMK_XA_START "='2024-02-01 12:00:00'>"             \
 523     "<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' "         \
 524     PCMK_XA_HOURS "='3' />"                             \
 525     "</" PCMK_XE_DATE_EXPRESSION ">"
 526 
 527 static void
 528 range_valid_start_duration_missing_id(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530     // Currently acceptable
 531     xmlNodePtr xml = NULL;
 532 
 533     xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_DURATION_MISSING_ID);
 534 
 535     // Now and next change are before start
 536     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 537                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 538 
 539     // Now is before start, next change is between start and end
 540     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
 541                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 542 
 543     // Now is equal to start, next change is between start and end
 544     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
 545                            "2024-02-01 14:30:00", pcmk_rc_within_range);
 546 
 547     // Now is between start and end, next change is after end
 548     assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
 549                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 550 
 551     // Now is equal to end, next change is after end
 552     assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
 553                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 554 
 555     // Now and next change are after end
 556     assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
 557                            "2028-04-04 04:04:04", pcmk_rc_after_range);
 558 
 559     free_xml(xml);
 560 }
 561 
 562 #define EXPR_SPEC_MISSING                               \
 563     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 564     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "' />"
 565 
 566 static void
 567 spec_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 568 {
 569     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING);
 570 
 571     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
 572     free_xml(xml);
 573 }
 574 
 575 #define EXPR_SPEC_INVALID                               \
 576     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 577     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>"    \
 578     "<" PCMK_XE_DATE_SPEC " " PCMK_XA_ID "='s' "        \
 579     PCMK_XA_MONTHS "='not-a-number'/>"                  \
 580     "</" PCMK_XE_DATE_EXPRESSION ">"
 581 
 582 static void
 583 spec_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 584 {
 585     // Currently treated as date_spec with no ranges (which passes)
 586     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_INVALID);
 587 
 588     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_ok);
 589     free_xml(xml);
 590 }
 591 
 592 #define EXPR_SPEC_VALID                                 \
 593     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 594     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>"    \
 595     "<" PCMK_XE_DATE_SPEC " " PCMK_XA_ID "='s' "        \
 596     PCMK_XA_MONTHS "='2'/>"                             \
 597     "</" PCMK_XE_DATE_EXPRESSION ">"
 598 
 599 static void
 600 spec_valid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602     // date_spec does not currently support next_change
 603     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_VALID);
 604 
 605     // Now is just before spec start
 606     assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL,
 607                            pcmk_rc_before_range);
 608 
 609     // Now matches spec start
 610     assert_date_expression(xml, "2024-02-01 00:00:00", NULL, NULL, pcmk_rc_ok);
 611 
 612     // Now is within spec range
 613     assert_date_expression(xml, "2024-02-22 22:22:22", NULL, NULL, pcmk_rc_ok);
 614 
 615     // Now matches spec end
 616     assert_date_expression(xml, "2024-02-29 23:59:59", NULL, NULL, pcmk_rc_ok);
 617 
 618     // Now is just past spec end
 619     assert_date_expression(xml, "2024-03-01 00:00:00", NULL, NULL,
 620                            pcmk_rc_after_range);
 621 
 622     free_xml(xml);
 623 }
 624 
 625 #define EXPR_SPEC_MISSING_ID                            \
 626     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 627     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>"    \
 628     "<" PCMK_XE_DATE_SPEC " "                           \
 629     PCMK_XA_MONTHS "='2'/>"                             \
 630     "</" PCMK_XE_DATE_EXPRESSION ">"
 631 
 632 static void
 633 spec_missing_id(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 634 {
 635     // Currently acceptable; date_spec does not currently support next_change
 636     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING_ID);
 637 
 638     // Now is just before spec start
 639     assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL,
 640                            pcmk_rc_before_range);
 641 
 642     // Now matches spec start
 643     assert_date_expression(xml, "2024-02-01 00:00:00", NULL, NULL, pcmk_rc_ok);
 644 
 645     // Now is within spec range
 646     assert_date_expression(xml, "2024-02-22 22:22:22", NULL, NULL, pcmk_rc_ok);
 647 
 648     // Now matches spec end
 649     assert_date_expression(xml, "2024-02-29 23:59:59", NULL, NULL, pcmk_rc_ok);
 650 
 651     // Now is just past spec end
 652     assert_date_expression(xml, "2024-03-01 00:00:00", NULL, NULL,
 653                            pcmk_rc_after_range);
 654 
 655     free_xml(xml);
 656 }
 657 
 658 PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
 659                 cmocka_unit_test(null_invalid),
 660                 cmocka_unit_test(null_next_change_ok),
 661                 cmocka_unit_test(id_missing),
 662                 cmocka_unit_test(op_invalid),
 663                 cmocka_unit_test(lt_missing_end),
 664                 cmocka_unit_test(lt_invalid_end),
 665                 cmocka_unit_test(lt_valid),
 666                 cmocka_unit_test(gt_missing_start),
 667                 cmocka_unit_test(gt_invalid_start),
 668                 cmocka_unit_test(gt_valid),
 669                 cmocka_unit_test(range_missing),
 670                 cmocka_unit_test(range_invalid_start_invalid_end),
 671                 cmocka_unit_test(range_invalid_start_only),
 672                 cmocka_unit_test(range_valid_start_only),
 673                 cmocka_unit_test(range_invalid_end_only),
 674                 cmocka_unit_test(range_valid_end_only),
 675                 cmocka_unit_test(range_valid_start_invalid_end),
 676                 cmocka_unit_test(range_invalid_start_valid_end),
 677                 cmocka_unit_test(range_valid_start_valid_end),
 678                 cmocka_unit_test(range_valid_start_invalid_duration),
 679                 cmocka_unit_test(range_valid_start_valid_duration),
 680                 cmocka_unit_test(range_valid_start_duration_missing_id),
 681                 cmocka_unit_test(spec_missing),
 682                 cmocka_unit_test(spec_invalid),
 683                 cmocka_unit_test(spec_valid),
 684                 cmocka_unit_test(spec_missing_id))

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