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     pcmk__xml_free(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     pcmk__xml_free(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     xmlNodePtr xml = pcmk__xml_parse(EXPR_ID_MISSING);
  98 
  99     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 100     pcmk__xml_free(xml);
 101 }
 102 
 103 #define EXPR_OP_INVALID                                 \
 104     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 105         PCMK_XA_OPERATION "='not-a-choice' />"
 106 
 107 static void
 108 op_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110     xmlNodePtr xml = pcmk__xml_parse(EXPR_OP_INVALID);
 111 
 112     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 113     pcmk__xml_free(xml);
 114 }
 115 
 116 #define EXPR_LT_MISSING_END                             \
 117     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 118         PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' />"
 119 
 120 static void
 121 lt_missing_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_MISSING_END);
 124 
 125     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 126     pcmk__xml_free(xml);
 127 }
 128 
 129 #define EXPR_LT_INVALID_END                             \
 130     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 131     PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' "           \
 132     PCMK_XA_END "='not-a-datetime' />"
 133 
 134 static void
 135 lt_invalid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_INVALID_END);
 138 
 139     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 140     pcmk__xml_free(xml);
 141 }
 142 
 143 static void
 144 lt_valid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 145 {
 146     xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
 147 
 148     // Now and next change are both before end
 149     assert_date_expression(xml, "2023-01-01 05:00:00", "2024-02-01 10:00:00",
 150                            "2024-02-01 10:00:00", pcmk_rc_within_range);
 151 
 152     // Now is before end, next change is after end
 153     assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
 154                            "2024-02-01 15:00:00", pcmk_rc_within_range);
 155 
 156     // Now is equal to end, next change is after end
 157     assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 20:00:00",
 158                            "2024-02-01 20:00:00", pcmk_rc_after_range);
 159 
 160     // Now and next change are both after end
 161     assert_date_expression(xml, "2024-03-01 12:00:00", "2024-02-01 20:00:00",
 162                            "2024-02-01 20:00:00", pcmk_rc_after_range);
 163 
 164     pcmk__xml_free(xml);
 165 }
 166 
 167 #define EXPR_GT_MISSING_START                           \
 168     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 169     PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' />"
 170 
 171 static void
 172 gt_missing_start(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174     xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_MISSING_START);
 175 
 176     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 177     pcmk__xml_free(xml);
 178 }
 179 
 180 #define EXPR_GT_INVALID_START                           \
 181     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 182     PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "           \
 183     PCMK_XA_START "='not-a-datetime' />"
 184 
 185 static void
 186 gt_invalid_start(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188     xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_INVALID_START);
 189 
 190     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 191     pcmk__xml_free(xml);
 192 }
 193 
 194 #define EXPR_GT_VALID                                   \
 195     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 196     PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' "           \
 197     PCMK_XA_START "='2024-02-01 12:00:00' />"
 198 
 199 static void
 200 gt_valid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 201 {
 202     xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_VALID);
 203 
 204     // Now and next change are both before start
 205     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 206                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 207 
 208     // Now is before start, next change is after start
 209     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
 210                            "2024-02-01 12:00:01", pcmk_rc_before_range);
 211 
 212     // Now is equal to start, next change is after start
 213     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
 214                            "2024-02-01 12:00:01", pcmk_rc_before_range);
 215 
 216     // Now is one second after start, next change is after start
 217     assert_date_expression(xml, "2024-02-01 12:00:01", "2024-02-01 18:00:00",
 218                            "2024-02-01 18:00:00", pcmk_rc_within_range);
 219 
 220     // t is after start, next change is after start
 221     assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
 222                            "2024-04-04 04:04:04", pcmk_rc_within_range);
 223 
 224     pcmk__xml_free(xml);
 225 }
 226 
 227 #define EXPR_RANGE_MISSING                              \
 228     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 229     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' />"
 230 
 231 static void
 232 range_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_MISSING);
 235     crm_time_t *t = crm_time_new("2024-01-01");
 236 
 237     assert_int_equal(pcmk__evaluate_date_expression(xml, t, NULL),
 238                      pcmk_rc_unpack_error);
 239 
 240     crm_time_free(t);
 241     pcmk__xml_free(xml);
 242 }
 243 
 244 #define EXPR_RANGE_INVALID_START_INVALID_END            \
 245     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 246     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 247     PCMK_XA_START "='not-a-date' "                      \
 248     PCMK_XA_END "='not-a-date' />"
 249 
 250 static void
 251 range_invalid_start_invalid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_INVALID_END);
 254 
 255     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 256     pcmk__xml_free(xml);
 257 }
 258 
 259 #define EXPR_RANGE_INVALID_START_ONLY                   \
 260     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 261     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 262     PCMK_XA_START "='not-a-date' />"
 263 
 264 static void
 265 range_invalid_start_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_ONLY);
 268 
 269     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 270     pcmk__xml_free(xml);
 271 }
 272 
 273 #define EXPR_RANGE_VALID_START_ONLY                     \
 274     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 275     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 276     PCMK_XA_START "='2024-02-01 12:00:00' />"
 277 
 278 static void
 279 range_valid_start_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_ONLY);
 282 
 283     // Now and next change are before start
 284     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 285                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 286 
 287     // Now is before start, next change is after start
 288     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
 289                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 290 
 291     // Now is equal to start, next change is after start
 292     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
 293                            "2024-02-01 18:00:00", pcmk_rc_within_range);
 294 
 295     // Now and next change are after start
 296     assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
 297                            "2024-04-04 04:04:04", pcmk_rc_within_range);
 298 
 299     pcmk__xml_free(xml);
 300 }
 301 
 302 #define EXPR_RANGE_INVALID_END_ONLY                   \
 303     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 304     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 305     PCMK_XA_END "='not-a-date' />"
 306 
 307 static void
 308 range_invalid_end_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 309 {
 310     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_END_ONLY);
 311 
 312     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 313     pcmk__xml_free(xml);
 314 }
 315 
 316 #define EXPR_RANGE_VALID_END_ONLY                     \
 317     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 318     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 319     PCMK_XA_END "='2024-02-01 15:00:00' />"
 320 
 321 static void
 322 range_valid_end_only(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 323 {
 324     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_END_ONLY);
 325 
 326     // Now and next change are before end
 327     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 328                            "2024-01-01 11:00:00", pcmk_rc_within_range);
 329 
 330     // Now is before end, next change is after end
 331     assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
 332                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 333 
 334     // Now is equal to end, next change is after end
 335     assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00",
 336                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 337 
 338     // Now and next change are after end
 339     assert_date_expression(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04",
 340                            "2024-04-04 04:04:04", pcmk_rc_after_range);
 341 
 342     pcmk__xml_free(xml);
 343 }
 344 
 345 #define EXPR_RANGE_VALID_START_INVALID_END              \
 346     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 347     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 348     PCMK_XA_START "='2024-02-01 12:00:00' "             \
 349     PCMK_XA_END "='not-a-date' />"
 350 
 351 static void
 352 range_valid_start_invalid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_END);
 355 
 356     assert_date_expression(xml, "2024-01-01 04:30:05", NULL, NULL,
 357                            pcmk_rc_unpack_error);
 358     pcmk__xml_free(xml);
 359 }
 360 
 361 #define EXPR_RANGE_INVALID_START_VALID_END              \
 362     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 363     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 364     PCMK_XA_START "='not-a-date' "                      \
 365     PCMK_XA_END "='2024-02-01 15:00:00' />"
 366 
 367 static void
 368 range_invalid_start_valid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_VALID_END);
 371 
 372     assert_date_expression(xml, "2024-01-01 04:30:05", NULL, NULL,
 373                            pcmk_rc_unpack_error);
 374     pcmk__xml_free(xml);
 375 }
 376 
 377 #define EXPR_RANGE_VALID_START_VALID_END                \
 378     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 379     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 380     PCMK_XA_START "='2024-02-01 12:00:00' "             \
 381     PCMK_XA_END "='2024-02-01 15:00:00' />"
 382 
 383 static void
 384 range_valid_start_valid_end(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_END);
 387 
 388     // Now and next change are before start
 389     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 390                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 391 
 392     // Now is before start, next change is between start and end
 393     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
 394                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 395 
 396     // Now is equal to start, next change is between start and end
 397     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
 398                            "2024-02-01 14:30:00", pcmk_rc_within_range);
 399 
 400     // Now is between start and end, next change is after end
 401     assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
 402                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 403 
 404     // Now is equal to end, next change is after end
 405     assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
 406                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 407 
 408     // Now and next change are after end
 409     assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
 410                            "2028-04-04 04:04:04", pcmk_rc_after_range);
 411 
 412     pcmk__xml_free(xml);
 413 }
 414 
 415 #define EXPR_RANGE_VALID_START_INVALID_DURATION         \
 416     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 417     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 418     PCMK_XA_START "='2024-02-01 12:00:00'>"             \
 419     "<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' "         \
 420     PCMK_XA_HOURS "='not-a-number' />"                  \
 421     "</" PCMK_XE_DATE_EXPRESSION ">"
 422 
 423 static void
 424 range_valid_start_invalid_duration(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 425 {
 426     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_DURATION);
 427 
 428     assert_date_expression(xml, "2024-02-01 04:30:05", NULL, NULL,
 429                            pcmk_rc_unpack_error);
 430     pcmk__xml_free(xml);
 431 }
 432 
 433 #define EXPR_RANGE_VALID_START_VALID_DURATION           \
 434     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 435     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 436     PCMK_XA_START "='2024-02-01 12:00:00'>"             \
 437     "<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' "         \
 438     PCMK_XA_HOURS "='3' />"                             \
 439     "</" PCMK_XE_DATE_EXPRESSION ">"
 440 
 441 static void
 442 range_valid_start_valid_duration(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 443 {
 444     xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_DURATION);
 445 
 446     // Now and next change are before start
 447     assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
 448                            "2024-01-01 11:00:00", pcmk_rc_before_range);
 449 
 450     // Now is before start, next change is between start and end
 451     assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
 452                            "2024-02-01 12:00:00", pcmk_rc_before_range);
 453 
 454     // Now is equal to start, next change is between start and end
 455     assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
 456                            "2024-02-01 14:30:00", pcmk_rc_within_range);
 457 
 458     // Now is between start and end, next change is after end
 459     assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
 460                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 461 
 462     // Now is equal to end, next change is after end
 463     assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
 464                            "2024-02-01 15:00:01", pcmk_rc_within_range);
 465 
 466     // Now and next change are after end
 467     assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
 468                            "2028-04-04 04:04:04", pcmk_rc_after_range);
 469 
 470     pcmk__xml_free(xml);
 471 }
 472 
 473 #define EXPR_RANGE_VALID_START_DURATION_MISSING_ID      \
 474     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='d' "  \
 475     PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' "     \
 476     PCMK_XA_START "='2024-02-01 12:00:00'>"             \
 477     "<" PCMK_XE_DURATION " " PCMK_XA_HOURS "='3' />"    \
 478     "</" PCMK_XE_DATE_EXPRESSION ">"
 479 
 480 static void
 481 range_valid_start_duration_missing_id(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 482 {
 483     xmlNodePtr xml = NULL;
 484 
 485     xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_DURATION_MISSING_ID);
 486 
 487     assert_date_expression(xml, "2024-02-01 04:30:05", NULL, NULL,
 488                            pcmk_rc_unpack_error);
 489     pcmk__xml_free(xml);
 490 }
 491 
 492 #define EXPR_SPEC_MISSING                               \
 493     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 494     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "' />"
 495 
 496 static void
 497 spec_missing(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 498 {
 499     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING);
 500 
 501     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 502     pcmk__xml_free(xml);
 503 }
 504 
 505 #define EXPR_SPEC_INVALID                               \
 506     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 507     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>"    \
 508     "<" PCMK_XE_DATE_SPEC " " PCMK_XA_ID "='s' "        \
 509     PCMK_XA_MONTHS "='not-a-number'/>"                  \
 510     "</" PCMK_XE_DATE_EXPRESSION ">"
 511 
 512 static void
 513 spec_invalid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 514 {
 515     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_INVALID);
 516 
 517     assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_unpack_error);
 518     pcmk__xml_free(xml);
 519 }
 520 
 521 #define EXPR_SPEC_VALID                                 \
 522     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 523     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>"    \
 524     "<" PCMK_XE_DATE_SPEC " " PCMK_XA_ID "='s' "        \
 525     PCMK_XA_MONTHS "='2'/>"                             \
 526     "</" PCMK_XE_DATE_EXPRESSION ">"
 527 
 528 static void
 529 spec_valid(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 530 {
 531     // date_spec does not currently support next_change
 532     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_VALID);
 533 
 534     // Now is just before spec start
 535     assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL,
 536                            pcmk_rc_before_range);
 537 
 538     // Now matches spec start
 539     assert_date_expression(xml, "2024-02-01 00:00:00", NULL, NULL, pcmk_rc_ok);
 540 
 541     // Now is within spec range
 542     assert_date_expression(xml, "2024-02-22 22:22:22", NULL, NULL, pcmk_rc_ok);
 543 
 544     // Now matches spec end
 545     assert_date_expression(xml, "2024-02-29 23:59:59", NULL, NULL, pcmk_rc_ok);
 546 
 547     // Now is just past spec end
 548     assert_date_expression(xml, "2024-03-01 00:00:00", NULL, NULL,
 549                            pcmk_rc_after_range);
 550 
 551     pcmk__xml_free(xml);
 552 }
 553 
 554 #define EXPR_SPEC_MISSING_ID                            \
 555     "<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' "  \
 556     PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>"    \
 557     "<" PCMK_XE_DATE_SPEC " "                           \
 558     PCMK_XA_MONTHS "='2'/>"                             \
 559     "</" PCMK_XE_DATE_EXPRESSION ">"
 560 
 561 static void
 562 spec_missing_id(void **state)
     /* [previous][next][first][last][top][bottom][index][help] */
 563 {
 564     xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING_ID);
 565 
 566     assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL,
 567                            pcmk_rc_unpack_error);
 568     pcmk__xml_free(xml);
 569 }
 570 
 571 PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
 572                 cmocka_unit_test(null_invalid),
 573                 cmocka_unit_test(null_next_change_ok),
 574                 cmocka_unit_test(id_missing),
 575                 cmocka_unit_test(op_invalid),
 576                 cmocka_unit_test(lt_missing_end),
 577                 cmocka_unit_test(lt_invalid_end),
 578                 cmocka_unit_test(lt_valid),
 579                 cmocka_unit_test(gt_missing_start),
 580                 cmocka_unit_test(gt_invalid_start),
 581                 cmocka_unit_test(gt_valid),
 582                 cmocka_unit_test(range_missing),
 583                 cmocka_unit_test(range_invalid_start_invalid_end),
 584                 cmocka_unit_test(range_invalid_start_only),
 585                 cmocka_unit_test(range_valid_start_only),
 586                 cmocka_unit_test(range_invalid_end_only),
 587                 cmocka_unit_test(range_valid_end_only),
 588                 cmocka_unit_test(range_valid_start_invalid_end),
 589                 cmocka_unit_test(range_invalid_start_valid_end),
 590                 cmocka_unit_test(range_valid_start_valid_end),
 591                 cmocka_unit_test(range_valid_start_invalid_duration),
 592                 cmocka_unit_test(range_valid_start_valid_duration),
 593                 cmocka_unit_test(range_valid_start_duration_missing_id),
 594                 cmocka_unit_test(spec_missing),
 595                 cmocka_unit_test(spec_invalid),
 596                 cmocka_unit_test(spec_valid),
 597                 cmocka_unit_test(spec_missing_id))

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