diff options
Diffstat (limited to 'lib/pengine/tests')
-rw-r--r-- | lib/pengine/tests/Makefile.am | 1 | ||||
-rw-r--r-- | lib/pengine/tests/native/Makefile.am | 22 | ||||
-rw-r--r-- | lib/pengine/tests/native/native_find_rsc_test.c | 677 | ||||
-rw-r--r-- | lib/pengine/tests/native/pe_base_name_eq_test.c | 149 | ||||
-rw-r--r-- | lib/pengine/tests/rules/Makefile.am | 18 | ||||
-rw-r--r-- | lib/pengine/tests/rules/pe_cron_range_satisfied_test.c | 165 | ||||
-rw-r--r-- | lib/pengine/tests/status/Makefile.am | 22 | ||||
-rw-r--r-- | lib/pengine/tests/status/pe_find_node_any_test.c | 62 | ||||
-rw-r--r-- | lib/pengine/tests/status/pe_find_node_id_test.c | 51 | ||||
-rw-r--r-- | lib/pengine/tests/status/pe_find_node_test.c | 51 | ||||
-rw-r--r-- | lib/pengine/tests/status/pe_new_working_set_test.c | 46 | ||||
-rw-r--r-- | lib/pengine/tests/status/set_working_set_defaults_test.c | 46 | ||||
-rw-r--r-- | lib/pengine/tests/unpack/Makefile.am | 18 | ||||
-rw-r--r-- | lib/pengine/tests/unpack/pe_base_name_end_test.c | 36 | ||||
-rw-r--r-- | lib/pengine/tests/utils/Makefile.am | 21 | ||||
-rw-r--r-- | lib/pengine/tests/utils/pe__cmp_node_name_test.c | 55 | ||||
-rw-r--r-- | lib/pengine/tests/utils/pe__cmp_rsc_priority_test.c | 50 |
17 files changed, 1490 insertions, 0 deletions
diff --git a/lib/pengine/tests/Makefile.am b/lib/pengine/tests/Makefile.am new file mode 100644 index 0000000..4986ef2 --- /dev/null +++ b/lib/pengine/tests/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = rules native status unpack utils diff --git a/lib/pengine/tests/native/Makefile.am b/lib/pengine/tests/native/Makefile.am new file mode 100644 index 0000000..5046ff1 --- /dev/null +++ b/lib/pengine/tests/native/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2022 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# + +include $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +AM_CPPFLAGS += -I$(top_srcdir) +LDADD += $(top_builddir)/lib/pengine/libpe_status_test.la + +AM_TESTS_ENVIRONMENT += PCMK_CTS_CLI_DIR=$(top_srcdir)/cts/cli + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = native_find_rsc_test \ + pe_base_name_eq_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/pengine/tests/native/native_find_rsc_test.c b/lib/pengine/tests/native/native_find_rsc_test.c new file mode 100644 index 0000000..22aaf41 --- /dev/null +++ b/lib/pengine/tests/native/native_find_rsc_test.c @@ -0,0 +1,677 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/xml.h> +#include <crm/pengine/internal.h> +#include <crm/pengine/status.h> +#include <crm/pengine/pe_types.h> + +/* Needed to access replicas inside a bundle. */ +#define PE__VARIANT_BUNDLE 1 +#include <lib/pengine/variant.h> + +xmlNode *input = NULL; +pe_working_set_t *data_set = NULL; + +pe_node_t *cluster01, *cluster02, *httpd_bundle_0; +pe_resource_t *exim_group, *inactive_group, *promotable_clone, *inactive_clone; +pe_resource_t *httpd_bundle, *mysql_clone_group; + +static int +setup(void **state) { + char *path = NULL; + + crm_xml_init(); + + path = crm_strdup_printf("%s/crm_mon.xml", getenv("PCMK_CTS_CLI_DIR")); + input = filename2xml(path); + free(path); + + if (input == NULL) { + return 1; + } + + data_set = pe_new_working_set(); + + if (data_set == NULL) { + return 1; + } + + pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat); + data_set->input = input; + + cluster_status(data_set); + + /* Get references to the cluster nodes so we don't have to find them repeatedly. */ + cluster01 = pe_find_node(data_set->nodes, "cluster01"); + cluster02 = pe_find_node(data_set->nodes, "cluster02"); + httpd_bundle_0 = pe_find_node(data_set->nodes, "httpd-bundle-0"); + + /* Get references to several resources we use frequently. */ + for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "exim-group") == 0) { + exim_group = rsc; + } else if (strcmp(rsc->id, "httpd-bundle") == 0) { + httpd_bundle = rsc; + } else if (strcmp(rsc->id, "inactive-clone") == 0) { + inactive_clone = rsc; + } else if (strcmp(rsc->id, "inactive-group") == 0) { + inactive_group = rsc; + } else if (strcmp(rsc->id, "mysql-clone-group") == 0) { + mysql_clone_group = rsc; + } else if (strcmp(rsc->id, "promotable-clone") == 0) { + promotable_clone = rsc; + } + } + + return 0; +} + +static int +teardown(void **state) { + pe_free_working_set(data_set); + + return 0; +} + +static void +bad_args(void **state) { + pe_resource_t *rsc = (pe_resource_t *) g_list_first(data_set->resources)->data; + char *id = rsc->id; + char *name = NULL; + + assert_non_null(rsc); + + assert_null(native_find_rsc(NULL, "dummy", NULL, 0)); + assert_null(native_find_rsc(rsc, NULL, NULL, 0)); + + /* No resources exist with these names. */ + name = crm_strdup_printf("%sX", rsc->id); + assert_null(native_find_rsc(rsc, name, NULL, 0)); + free(name); + + name = crm_strdup_printf("x%s", rsc->id); + assert_null(native_find_rsc(rsc, name, NULL, 0)); + free(name); + + name = g_ascii_strup(rsc->id, -1); + assert_null(native_find_rsc(rsc, name, NULL, 0)); + g_free(name); + + /* Fails because resource ID is NULL. */ + rsc->id = NULL; + assert_null(native_find_rsc(rsc, id, NULL, 0)); + rsc->id = id; +} + +static void +primitive_rsc(void **state) { + pe_resource_t *dummy = NULL; + + /* Find the "dummy" resource, which is the only one with that ID in the set. */ + for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "dummy") == 0) { + dummy = rsc; + break; + } + } + + assert_non_null(dummy); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(dummy, native_find_rsc(dummy, "dummy", NULL, 0)); + assert_ptr_equal(dummy, native_find_rsc(dummy, "dummy", NULL, pe_find_current)); + + /* Fails because resource is not a clone (nor cloned). */ + assert_null(native_find_rsc(dummy, "dummy", NULL, pe_find_clone)); + assert_null(native_find_rsc(dummy, "dummy", cluster02, pe_find_clone)); + + /* Fails because dummy is not running on cluster01, even with the right flags. */ + assert_null(native_find_rsc(dummy, "dummy", cluster01, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(dummy, "dummy", cluster02, 0)); + + /* Passes because dummy is running on cluster02. */ + assert_ptr_equal(dummy, native_find_rsc(dummy, "dummy", cluster02, pe_find_current)); +} + +static void +group_rsc(void **state) { + assert_non_null(exim_group); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(exim_group, native_find_rsc(exim_group, "exim-group", NULL, 0)); + assert_ptr_equal(exim_group, native_find_rsc(exim_group, "exim-group", NULL, pe_find_current)); + + /* Fails because resource is not a clone (nor cloned). */ + assert_null(native_find_rsc(exim_group, "exim-group", NULL, pe_find_clone)); + assert_null(native_find_rsc(exim_group, "exim-group", cluster01, pe_find_clone)); + + /* Fails because none of exim-group's children are running on cluster01, even with the right flags. */ + assert_null(native_find_rsc(exim_group, "exim-group", cluster01, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(exim_group, "exim-group", cluster01, 0)); + + /* Passes because one of exim-group's children is running on cluster02. */ + assert_ptr_equal(exim_group, native_find_rsc(exim_group, "exim-group", cluster02, pe_find_current)); +} + +static void +inactive_group_rsc(void **state) { + assert_non_null(inactive_group); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(inactive_group, native_find_rsc(inactive_group, "inactive-group", NULL, 0)); + assert_ptr_equal(inactive_group, native_find_rsc(inactive_group, "inactive-group", NULL, pe_find_current)); + assert_ptr_equal(inactive_group, native_find_rsc(inactive_group, "inactive-group", NULL, pe_find_inactive)); + + /* Fails because resource is not a clone (nor cloned). */ + assert_null(native_find_rsc(inactive_group, "inactive-group", NULL, pe_find_clone)); + assert_null(native_find_rsc(inactive_group, "inactive-group", cluster01, pe_find_clone)); + + /* Fails because none of inactive-group's children are running. */ + assert_null(native_find_rsc(inactive_group, "inactive-group", cluster01, pe_find_current)); + assert_null(native_find_rsc(inactive_group, "inactive-group", cluster02, pe_find_current)); + + /* Passes because of flags. */ + assert_ptr_equal(inactive_group, native_find_rsc(inactive_group, "inactive-group", cluster01, pe_find_inactive)); + /* Passes because of flags. */ + assert_ptr_equal(inactive_group, native_find_rsc(inactive_group, "inactive-group", cluster02, pe_find_inactive)); +} + +static void +group_member_rsc(void **state) { + pe_resource_t *public_ip = NULL; + + /* Find the "Public-IP" resource, a member of "exim-group". */ + for (GList *iter = exim_group->children; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "Public-IP") == 0) { + public_ip = rsc; + break; + } + } + + assert_non_null(public_ip); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(public_ip, native_find_rsc(public_ip, "Public-IP", NULL, 0)); + assert_ptr_equal(public_ip, native_find_rsc(public_ip, "Public-IP", NULL, pe_find_current)); + + /* Fails because resource is not a clone (nor cloned). */ + assert_null(native_find_rsc(public_ip, "Public-IP", NULL, pe_find_clone)); + assert_null(native_find_rsc(public_ip, "Public-IP", cluster02, pe_find_clone)); + + /* Fails because Public-IP is not running on cluster01, even with the right flags. */ + assert_null(native_find_rsc(public_ip, "Public-IP", cluster01, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(public_ip, "Public-IP", cluster02, 0)); + + /* Passes because Public-IP is running on cluster02. */ + assert_ptr_equal(public_ip, native_find_rsc(public_ip, "Public-IP", cluster02, pe_find_current)); +} + +static void +inactive_group_member_rsc(void **state) { + pe_resource_t *inactive_dummy_1 = NULL; + + /* Find the "inactive-dummy-1" resource, a member of "inactive-group". */ + for (GList *iter = inactive_group->children; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "inactive-dummy-1") == 0) { + inactive_dummy_1 = rsc; + break; + } + } + + assert_non_null(inactive_dummy_1); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(inactive_dummy_1, native_find_rsc(inactive_dummy_1, "inactive-dummy-1", NULL, 0)); + assert_ptr_equal(inactive_dummy_1, native_find_rsc(inactive_dummy_1, "inactive-dummy-1", NULL, pe_find_current)); + + /* Fails because resource is not a clone (nor cloned). */ + assert_null(native_find_rsc(inactive_dummy_1, "inactive-dummy-1", NULL, pe_find_clone)); + assert_null(native_find_rsc(inactive_dummy_1, "inactive-dummy-1", cluster01, pe_find_clone)); + + /* Fails because inactive-dummy-1 is not running. */ + assert_null(native_find_rsc(inactive_dummy_1, "inactive-dummy-1", cluster01, pe_find_current)); + assert_null(native_find_rsc(inactive_dummy_1, "inactive-dummy-1", cluster02, pe_find_current)); + + /* Passes because of flags. */ + assert_ptr_equal(inactive_dummy_1, native_find_rsc(inactive_dummy_1, "inactive-dummy-1", cluster01, pe_find_inactive)); + /* Passes because of flags. */ + assert_ptr_equal(inactive_dummy_1, native_find_rsc(inactive_dummy_1, "inactive-dummy-1", cluster02, pe_find_inactive)); +} + +static void +clone_rsc(void **state) { + assert_non_null(promotable_clone); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", NULL, 0)); + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", NULL, pe_find_current)); + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", NULL, pe_find_clone)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(promotable_clone, "promotable-clone", cluster01, 0)); + + /* Passes because one of ping-clone's children is running on cluster01. */ + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", cluster01, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(promotable_clone, "promotable-clone", cluster02, 0)); + + /* Passes because one of ping_clone's children is running on cluster02. */ + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", cluster02, pe_find_current)); + + /* Passes for previous reasons, plus includes pe_find_clone check. */ + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", cluster01, pe_find_clone|pe_find_current)); + assert_ptr_equal(promotable_clone, native_find_rsc(promotable_clone, "promotable-clone", cluster02, pe_find_clone|pe_find_current)); +} + +static void +inactive_clone_rsc(void **state) { + assert_non_null(inactive_clone); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(inactive_clone, native_find_rsc(inactive_clone, "inactive-clone", NULL, 0)); + assert_ptr_equal(inactive_clone, native_find_rsc(inactive_clone, "inactive-clone", NULL, pe_find_current)); + assert_ptr_equal(inactive_clone, native_find_rsc(inactive_clone, "inactive-clone", NULL, pe_find_clone)); + assert_ptr_equal(inactive_clone, native_find_rsc(inactive_clone, "inactive-clone", NULL, pe_find_inactive)); + + /* Fails because none of inactive-clone's children are running. */ + assert_null(native_find_rsc(inactive_clone, "inactive-clone", cluster01, pe_find_current|pe_find_clone)); + assert_null(native_find_rsc(inactive_clone, "inactive-clone", cluster02, pe_find_current|pe_find_clone)); + + /* Passes because of flags. */ + assert_ptr_equal(inactive_clone, native_find_rsc(inactive_clone, "inactive-clone", cluster01, pe_find_inactive)); + /* Passes because of flags. */ + assert_ptr_equal(inactive_clone, native_find_rsc(inactive_clone, "inactive-clone", cluster02, pe_find_inactive)); +} + +static void +clone_instance_rsc(void **state) { + pe_resource_t *promotable_0 = NULL; + pe_resource_t *promotable_1 = NULL; + + /* Find the "promotable-rsc:0" and "promotable-rsc:1" resources, members of "promotable-clone". */ + for (GList *iter = promotable_clone->children; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "promotable-rsc:0") == 0) { + promotable_0 = rsc; + } else if (strcmp(rsc->id, "promotable-rsc:1") == 0) { + promotable_1 = rsc; + } + } + + assert_non_null(promotable_0); + assert_non_null(promotable_1); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc:0", NULL, 0)); + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc:0", NULL, pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc:1", NULL, 0)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc:1", NULL, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(promotable_0, "promotable-rsc:0", cluster02, 0)); + assert_null(native_find_rsc(promotable_1, "promotable-rsc:1", cluster01, 0)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc:0", cluster02, pe_find_current)); + assert_null(native_find_rsc(promotable_0, "promotable-rsc:0", cluster01, pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc:1", cluster01, pe_find_current)); + assert_null(native_find_rsc(promotable_1, "promotable-rsc:1", cluster02, pe_find_current)); + + /* Passes because NULL was passed for node and primitive name was given, with correct flags. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc", NULL, pe_find_clone)); + + /* Passes because pe_find_any matches any instance's base name. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc", NULL, pe_find_any)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc", NULL, pe_find_any)); + + /* Passes because pe_find_anon matches. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc", NULL, pe_find_anon)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc", NULL, pe_find_anon)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc", cluster02, pe_find_any|pe_find_current)); + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc", cluster02, pe_find_anon|pe_find_current)); + assert_null(native_find_rsc(promotable_0, "promotable-rsc", cluster01, pe_find_any|pe_find_current)); + assert_null(native_find_rsc(promotable_0, "promotable-rsc", cluster01, pe_find_anon|pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc", cluster01, pe_find_any|pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc", cluster01, pe_find_anon|pe_find_current)); + assert_null(native_find_rsc(promotable_1, "promotable-rsc", cluster02, pe_find_any|pe_find_current)); + assert_null(native_find_rsc(promotable_1, "promotable-rsc", cluster02, pe_find_anon|pe_find_current)); + + /* Fails because incorrect flags were given along with primitive name. */ + assert_null(native_find_rsc(promotable_0, "promotable-rsc", NULL, pe_find_current)); + assert_null(native_find_rsc(promotable_1, "promotable-rsc", NULL, pe_find_current)); + + /* And then we check failure possibilities again, except passing promotable_clone + * instead of promotable_X as the first argument to native_find_rsc. + */ + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(promotable_clone, "promotable-rsc:0", cluster02, 0)); + assert_null(native_find_rsc(promotable_clone, "promotable-rsc:1", cluster01, 0)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_clone, "promotable-rsc:0", cluster02, pe_find_current)); + assert_ptr_equal(promotable_0, native_find_rsc(promotable_clone, "promotable-rsc", cluster02, pe_find_any|pe_find_current)); + assert_ptr_equal(promotable_0, native_find_rsc(promotable_clone, "promotable-rsc", cluster02, pe_find_anon|pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_clone, "promotable-rsc:1", cluster01, pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_clone, "promotable-rsc", cluster01, pe_find_any|pe_find_current)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_clone, "promotable-rsc", cluster01, pe_find_anon|pe_find_current)); +} + +static void +renamed_rsc(void **state) { + pe_resource_t *promotable_0 = NULL; + pe_resource_t *promotable_1 = NULL; + + /* Find the "promotable-rsc:0" and "promotable-rsc:1" resources, members of "promotable-clone". */ + for (GList *iter = promotable_clone->children; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "promotable-rsc:0") == 0) { + promotable_0 = rsc; + } else if (strcmp(rsc->id, "promotable-rsc:1") == 0) { + promotable_1 = rsc; + } + } + + assert_non_null(promotable_0); + assert_non_null(promotable_1); + + /* Passes because pe_find_renamed means the base name matches clone_name. */ + assert_ptr_equal(promotable_0, native_find_rsc(promotable_0, "promotable-rsc", NULL, pe_find_renamed)); + assert_ptr_equal(promotable_1, native_find_rsc(promotable_1, "promotable-rsc", NULL, pe_find_renamed)); +} + +static void +bundle_rsc(void **state) { + assert_non_null(httpd_bundle); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(httpd_bundle, native_find_rsc(httpd_bundle, "httpd-bundle", NULL, 0)); + assert_ptr_equal(httpd_bundle, native_find_rsc(httpd_bundle, "httpd-bundle", NULL, pe_find_current)); + + /* Fails because resource is not a clone (nor cloned). */ + assert_null(native_find_rsc(httpd_bundle, "httpd-bundle", NULL, pe_find_clone)); + assert_null(native_find_rsc(httpd_bundle, "httpd-bundle", cluster01, pe_find_clone)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(httpd_bundle, "httpd-bundle", cluster01, 0)); + + /* Passes because one of httpd_bundle's children is running on cluster01. */ + assert_ptr_equal(httpd_bundle, native_find_rsc(httpd_bundle, "httpd-bundle", cluster01, pe_find_current)); +} + +static void +bundle_replica_rsc(void **state) { + pe__bundle_variant_data_t *bundle_data = NULL; + pe__bundle_replica_t *replica_0 = NULL; + + pe_resource_t *ip_0 = NULL; + pe_resource_t *child_0 = NULL; + pe_resource_t *container_0 = NULL; + pe_resource_t *remote_0 = NULL; + + get_bundle_variant_data(bundle_data, httpd_bundle); + replica_0 = (pe__bundle_replica_t *) bundle_data->replicas->data; + + ip_0 = replica_0->ip; + child_0 = replica_0->child; + container_0 = replica_0->container; + remote_0 = replica_0->remote; + + assert_non_null(ip_0); + assert_non_null(child_0); + assert_non_null(container_0); + assert_non_null(remote_0); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(ip_0, native_find_rsc(ip_0, "httpd-bundle-ip-192.168.122.131", NULL, 0)); + assert_ptr_equal(child_0, native_find_rsc(child_0, "httpd:0", NULL, 0)); + assert_ptr_equal(container_0, native_find_rsc(container_0, "httpd-bundle-docker-0", NULL, 0)); + assert_ptr_equal(remote_0, native_find_rsc(remote_0, "httpd-bundle-0", NULL, 0)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(ip_0, "httpd-bundle-ip-192.168.122.131", cluster01, 0)); + assert_null(native_find_rsc(child_0, "httpd:0", httpd_bundle_0, 0)); + assert_null(native_find_rsc(container_0, "httpd-bundle-docker-0", cluster01, 0)); + assert_null(native_find_rsc(remote_0, "httpd-bundle-0", cluster01, 0)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(ip_0, native_find_rsc(ip_0, "httpd-bundle-ip-192.168.122.131", cluster01, pe_find_current)); + assert_null(native_find_rsc(ip_0, "httpd-bundle-ip-192.168.122.131", cluster02, pe_find_current)); + assert_null(native_find_rsc(ip_0, "httpd-bundle-ip-192.168.122.131", httpd_bundle_0, pe_find_current)); + assert_ptr_equal(child_0, native_find_rsc(child_0, "httpd:0", httpd_bundle_0, pe_find_current)); + assert_null(native_find_rsc(child_0, "httpd:0", cluster01, pe_find_current)); + assert_null(native_find_rsc(child_0, "httpd:0", cluster02, pe_find_current)); + assert_ptr_equal(container_0, native_find_rsc(container_0, "httpd-bundle-docker-0", cluster01, pe_find_current)); + assert_null(native_find_rsc(container_0, "httpd-bundle-docker-0", cluster02, pe_find_current)); + assert_null(native_find_rsc(container_0, "httpd-bundle-docker-0", httpd_bundle_0, pe_find_current)); + assert_ptr_equal(remote_0, native_find_rsc(remote_0, "httpd-bundle-0", cluster01, pe_find_current)); + assert_null(native_find_rsc(remote_0, "httpd-bundle-0", cluster02, pe_find_current)); + assert_null(native_find_rsc(remote_0, "httpd-bundle-0", httpd_bundle_0, pe_find_current)); + + /* Passes because pe_find_any matches any replica's base name. */ + assert_ptr_equal(child_0, native_find_rsc(child_0, "httpd", NULL, pe_find_any)); + + /* Passes because pe_find_anon matches. */ + assert_ptr_equal(child_0, native_find_rsc(child_0, "httpd", NULL, pe_find_anon)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(child_0, native_find_rsc(child_0, "httpd", httpd_bundle_0, pe_find_any|pe_find_current)); + assert_ptr_equal(child_0, native_find_rsc(child_0, "httpd", httpd_bundle_0, pe_find_anon|pe_find_current)); + assert_null(native_find_rsc(child_0, "httpd", cluster01, pe_find_any|pe_find_current)); + assert_null(native_find_rsc(child_0, "httpd", cluster01, pe_find_anon|pe_find_current)); + assert_null(native_find_rsc(child_0, "httpd", cluster02, pe_find_any|pe_find_current)); + assert_null(native_find_rsc(child_0, "httpd", cluster02, pe_find_anon|pe_find_current)); + + /* Fails because incorrect flags were given along with base name. */ + assert_null(native_find_rsc(child_0, "httpd", NULL, pe_find_current)); + + /* And then we check failure possibilities again, except passing httpd-bundle + * instead of X_0 as the first argument to native_find_rsc. + */ + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(httpd_bundle, "httpd-bundle-ip-192.168.122.131", cluster01, 0)); + assert_null(native_find_rsc(httpd_bundle, "httpd:0", httpd_bundle_0, 0)); + assert_null(native_find_rsc(httpd_bundle, "httpd-bundle-docker-0", cluster01, 0)); + assert_null(native_find_rsc(httpd_bundle, "httpd-bundle-0", cluster01, 0)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(ip_0, native_find_rsc(httpd_bundle, "httpd-bundle-ip-192.168.122.131", cluster01, pe_find_current)); + assert_ptr_equal(child_0, native_find_rsc(httpd_bundle, "httpd:0", httpd_bundle_0, pe_find_current)); + assert_ptr_equal(container_0, native_find_rsc(httpd_bundle, "httpd-bundle-docker-0", cluster01, pe_find_current)); + assert_ptr_equal(remote_0, native_find_rsc(httpd_bundle, "httpd-bundle-0", cluster01, pe_find_current)); +} + +static void +clone_group_rsc(void **rsc) { + assert_non_null(mysql_clone_group); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", NULL, 0)); + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", NULL, pe_find_current)); + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", NULL, pe_find_clone)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(mysql_clone_group, "mysql-clone-group", cluster01, 0)); + + /* Passes because one of mysql-clone-group's children is running on cluster01. */ + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", cluster01, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(mysql_clone_group, "mysql-clone-group", cluster02, 0)); + + /* Passes because one of mysql-clone-group's children is running on cluster02. */ + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", cluster02, pe_find_current)); + + /* Passes for previous reasons, plus includes pe_find_clone check. */ + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", cluster01, pe_find_clone|pe_find_current)); + assert_ptr_equal(mysql_clone_group, native_find_rsc(mysql_clone_group, "mysql-clone-group", cluster02, pe_find_clone|pe_find_current)); +} + +static void +clone_group_instance_rsc(void **rsc) { + pe_resource_t *mysql_group_0 = NULL; + pe_resource_t *mysql_group_1 = NULL; + + /* Find the "mysql-group:0" and "mysql-group:1" resources, members of "mysql-clone-group". */ + for (GList *iter = mysql_clone_group->children; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "mysql-group:0") == 0) { + mysql_group_0 = rsc; + } else if (strcmp(rsc->id, "mysql-group:1") == 0) { + mysql_group_1 = rsc; + } + } + + assert_non_null(mysql_group_0); + assert_non_null(mysql_group_1); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group:0", NULL, 0)); + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group:0", NULL, pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group:1", NULL, 0)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group:1", NULL, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(mysql_group_0, "mysql-group:0", cluster02, 0)); + assert_null(native_find_rsc(mysql_group_1, "mysql-group:1", cluster01, 0)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group:0", cluster02, pe_find_current)); + assert_null(native_find_rsc(mysql_group_0, "mysql-group:0", cluster01, pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group:1", cluster01, pe_find_current)); + assert_null(native_find_rsc(mysql_group_1, "mysql-group:1", cluster02, pe_find_current)); + + /* Passes because NULL was passed for node and base name was given, with correct flags. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group" , NULL, pe_find_clone)); + + /* Passes because pe_find_any matches any base name. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group" , NULL, pe_find_any)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group" , NULL, pe_find_any)); + + /* Passes because pe_find_anon matches. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group" , NULL, pe_find_anon)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group" , NULL, pe_find_anon)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group", cluster02, pe_find_any|pe_find_current)); + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_group_0, "mysql-group", cluster02, pe_find_anon|pe_find_current)); + assert_null(native_find_rsc(mysql_group_0, "mysql-group", cluster01, pe_find_any|pe_find_current)); + assert_null(native_find_rsc(mysql_group_0, "mysql-group", cluster01, pe_find_anon|pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group", cluster01, pe_find_any|pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_group_1, "mysql-group", cluster01, pe_find_anon|pe_find_current)); + assert_null(native_find_rsc(mysql_group_1, "mysql-group", cluster02, pe_find_any|pe_find_current)); + assert_null(native_find_rsc(mysql_group_1, "mysql-group", cluster02, pe_find_anon|pe_find_current)); + + /* Fails because incorrect flags were given along with base name. */ + assert_null(native_find_rsc(mysql_group_0, "mysql-group", NULL, pe_find_current)); + assert_null(native_find_rsc(mysql_group_1, "mysql-group", NULL, pe_find_current)); + + /* And then we check failure possibilities again, except passing mysql_clone_group + * instead of mysql_group_X as the first argument to native_find_rsc. + */ + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(mysql_clone_group, "mysql-group:0", cluster02, 0)); + assert_null(native_find_rsc(mysql_clone_group, "mysql-group:1", cluster01, 0)); + + /* Check that the resource is running on the node we expect. */ + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_clone_group, "mysql-group:0", cluster02, pe_find_current)); + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_clone_group, "mysql-group", cluster02, pe_find_any|pe_find_current)); + assert_ptr_equal(mysql_group_0, native_find_rsc(mysql_clone_group, "mysql-group", cluster02, pe_find_anon|pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_clone_group, "mysql-group:1", cluster01, pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_clone_group, "mysql-group", cluster01, pe_find_any|pe_find_current)); + assert_ptr_equal(mysql_group_1, native_find_rsc(mysql_clone_group, "mysql-group", cluster01, pe_find_anon|pe_find_current)); +} + +static void +clone_group_member_rsc(void **state) { + pe_resource_t *mysql_proxy = NULL; + + /* Find the "mysql-proxy" resource, a member of "mysql-group". */ + for (GList *iter = mysql_clone_group->children; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "mysql-group:0") == 0) { + for (GList *iter2 = rsc->children; iter2 != NULL; iter2 = iter2->next) { + pe_resource_t *child = (pe_resource_t *) iter2->data; + + if (strcmp(child->id, "mysql-proxy:0") == 0) { + mysql_proxy = child; + break; + } + } + + break; + } + } + + assert_non_null(mysql_proxy); + + /* Passes because NULL was passed for node, regardless of flags. */ + assert_ptr_equal(mysql_proxy, native_find_rsc(mysql_proxy, "mysql-proxy:0", NULL, 0)); + assert_ptr_equal(mysql_proxy, native_find_rsc(mysql_proxy, "mysql-proxy:0", NULL, pe_find_current)); + + /* Passes because resource's parent is a clone. */ + assert_ptr_equal(mysql_proxy, native_find_rsc(mysql_proxy, "mysql-proxy:0", NULL, pe_find_clone)); + assert_ptr_equal(mysql_proxy, native_find_rsc(mysql_proxy, "mysql-proxy:0", cluster02, pe_find_clone|pe_find_current)); + + /* Fails because mysql-proxy:0 is not running on cluster01, even with the right flags. */ + assert_null(native_find_rsc(mysql_proxy, "mysql-proxy:0", cluster01, pe_find_current)); + + /* Fails because pe_find_current is required if a node is given. */ + assert_null(native_find_rsc(mysql_proxy, "mysql-proxy:0", cluster02, 0)); + + /* Passes because mysql-proxy:0 is running on cluster02. */ + assert_ptr_equal(mysql_proxy, native_find_rsc(mysql_proxy, "mysql-proxy:0", cluster02, pe_find_current)); +} + +/* TODO: Add tests for finding on allocated node (passing a node without + * pe_find_current, after scheduling, for a resource that is starting/stopping/moving. + */ +PCMK__UNIT_TEST(setup, teardown, + cmocka_unit_test(bad_args), + cmocka_unit_test(primitive_rsc), + cmocka_unit_test(group_rsc), + cmocka_unit_test(inactive_group_rsc), + cmocka_unit_test(group_member_rsc), + cmocka_unit_test(inactive_group_member_rsc), + cmocka_unit_test(clone_rsc), + cmocka_unit_test(inactive_clone_rsc), + cmocka_unit_test(clone_instance_rsc), + cmocka_unit_test(renamed_rsc), + cmocka_unit_test(bundle_rsc), + cmocka_unit_test(bundle_replica_rsc), + cmocka_unit_test(clone_group_rsc), + cmocka_unit_test(clone_group_instance_rsc), + cmocka_unit_test(clone_group_member_rsc)) diff --git a/lib/pengine/tests/native/pe_base_name_eq_test.c b/lib/pengine/tests/native/pe_base_name_eq_test.c new file mode 100644 index 0000000..67a62f8 --- /dev/null +++ b/lib/pengine/tests/native/pe_base_name_eq_test.c @@ -0,0 +1,149 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <crm/common/xml.h> +#include <crm/pengine/internal.h> +#include <crm/pengine/status.h> +#include <crm/pengine/pe_types.h> + +xmlNode *input = NULL; +pe_working_set_t *data_set = NULL; + +pe_resource_t *exim_group, *promotable_0, *promotable_1, *dummy; +pe_resource_t *httpd_bundle, *mysql_group_0, *mysql_group_1; + +static int +setup(void **state) { + char *path = NULL; + + crm_xml_init(); + + path = crm_strdup_printf("%s/crm_mon.xml", getenv("PCMK_CTS_CLI_DIR")); + input = filename2xml(path); + free(path); + + if (input == NULL) { + return 1; + } + + data_set = pe_new_working_set(); + + if (data_set == NULL) { + return 1; + } + + pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat); + data_set->input = input; + + cluster_status(data_set); + + /* Get references to several resources we use frequently. */ + for (GList *iter = data_set->resources; iter != NULL; iter = iter->next) { + pe_resource_t *rsc = (pe_resource_t *) iter->data; + + if (strcmp(rsc->id, "dummy") == 0) { + dummy = rsc; + } else if (strcmp(rsc->id, "exim-group") == 0) { + exim_group = rsc; + } else if (strcmp(rsc->id, "httpd-bundle") == 0) { + httpd_bundle = rsc; + } else if (strcmp(rsc->id, "mysql-clone-group") == 0) { + for (GList *iter = rsc->children; iter != NULL; iter = iter->next) { + pe_resource_t *child = (pe_resource_t *) iter->data; + + if (strcmp(child->id, "mysql-group:0") == 0) { + mysql_group_0 = child; + } else if (strcmp(child->id, "mysql-group:1") == 0) { + mysql_group_1 = child; + } + } + } else if (strcmp(rsc->id, "promotable-clone") == 0) { + for (GList *iter = rsc->children; iter != NULL; iter = iter->next) { + pe_resource_t *child = (pe_resource_t *) iter->data; + + if (strcmp(child->id, "promotable-rsc:0") == 0) { + promotable_0 = child; + } else if (strcmp(child->id, "promotable-rsc:1") == 0) { + promotable_1 = child; + } + } + } + } + + return 0; +} + +static int +teardown(void **state) { + pe_free_working_set(data_set); + + return 0; +} + +static void +bad_args(void **state) { + char *id = dummy->id; + + assert_false(pe_base_name_eq(NULL, "dummy")); + assert_false(pe_base_name_eq(dummy, NULL)); + + dummy->id = NULL; + assert_false(pe_base_name_eq(dummy, "dummy")); + dummy->id = id; +} + +static void +primitive_rsc(void **state) { + assert_true(pe_base_name_eq(dummy, "dummy")); + assert_false(pe_base_name_eq(dummy, "DUMMY")); + assert_false(pe_base_name_eq(dummy, "dUmMy")); + assert_false(pe_base_name_eq(dummy, "dummy0")); + assert_false(pe_base_name_eq(dummy, "dummy:0")); +} + +static void +group_rsc(void **state) { + assert_true(pe_base_name_eq(exim_group, "exim-group")); + assert_false(pe_base_name_eq(exim_group, "EXIM-GROUP")); + assert_false(pe_base_name_eq(exim_group, "exim-group0")); + assert_false(pe_base_name_eq(exim_group, "exim-group:0")); + assert_false(pe_base_name_eq(exim_group, "Public-IP")); +} + +static void +clone_rsc(void **state) { + assert_true(pe_base_name_eq(promotable_0, "promotable-rsc")); + assert_true(pe_base_name_eq(promotable_1, "promotable-rsc")); + + assert_false(pe_base_name_eq(promotable_0, "promotable-rsc:0")); + assert_false(pe_base_name_eq(promotable_1, "promotable-rsc:1")); + assert_false(pe_base_name_eq(promotable_0, "PROMOTABLE-RSC")); + assert_false(pe_base_name_eq(promotable_1, "PROMOTABLE-RSC")); + assert_false(pe_base_name_eq(promotable_0, "Promotable-rsc")); + assert_false(pe_base_name_eq(promotable_1, "Promotable-rsc")); +} + +static void +bundle_rsc(void **state) { + assert_true(pe_base_name_eq(httpd_bundle, "httpd-bundle")); + assert_false(pe_base_name_eq(httpd_bundle, "HTTPD-BUNDLE")); + assert_false(pe_base_name_eq(httpd_bundle, "httpd")); + assert_false(pe_base_name_eq(httpd_bundle, "httpd-docker-0")); +} + +PCMK__UNIT_TEST(setup, teardown, + cmocka_unit_test(bad_args), + cmocka_unit_test(primitive_rsc), + cmocka_unit_test(group_rsc), + cmocka_unit_test(clone_rsc), + cmocka_unit_test(bundle_rsc)) diff --git a/lib/pengine/tests/rules/Makefile.am b/lib/pengine/tests/rules/Makefile.am new file mode 100644 index 0000000..261ec16 --- /dev/null +++ b/lib/pengine/tests/rules/Makefile.am @@ -0,0 +1,18 @@ +# +# Copyright 2020-2021 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# + +include $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +LDADD += $(top_builddir)/lib/pengine/libpe_rules_test.la + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pe_cron_range_satisfied_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/pengine/tests/rules/pe_cron_range_satisfied_test.c b/lib/pengine/tests/rules/pe_cron_range_satisfied_test.c new file mode 100644 index 0000000..a8ba6cf --- /dev/null +++ b/lib/pengine/tests/rules/pe_cron_range_satisfied_test.c @@ -0,0 +1,165 @@ +/* + * Copyright 2020-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <glib.h> + +#include <crm/msg_xml.h> +#include <crm/common/unittest_internal.h> +#include <crm/common/xml.h> +#include <crm/pengine/rules_internal.h> + +static void +run_one_test(const char *t, const char *x, int expected) { + crm_time_t *tm = crm_time_new(t); + xmlNodePtr xml = string2xml(x); + + assert_int_equal(pe_cron_range_satisfied(tm, xml), expected); + + crm_time_free(tm); + free_xml(xml); +} + +static void +no_time_given(void **state) { + assert_int_equal(pe_cron_range_satisfied(NULL, NULL), pcmk_rc_op_unsatisfied); +} + +static void +any_time_satisfies_empty_spec(void **state) { + crm_time_t *tm = crm_time_new(NULL); + + assert_int_equal(pe_cron_range_satisfied(tm, NULL), pcmk_rc_ok); + + crm_time_free(tm); +} + +static void +time_satisfies_year_spec(void **state) { + run_one_test("2020-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='2020'/>", + pcmk_rc_ok); +} + +static void +time_after_year_spec(void **state) { + run_one_test("2020-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='2019'/>", + pcmk_rc_after_range); +} + +static void +time_satisfies_year_range(void **state) { + run_one_test("2020-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='2010-2030'/>", + pcmk_rc_ok); +} + +static void +time_before_year_range(void **state) { + run_one_test("2000-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='2010-2030'/>", + pcmk_rc_before_range); +} + +static void +time_after_year_range(void **state) { + run_one_test("2020-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='2010-2015'/>", + pcmk_rc_after_range); +} + +static void +range_without_start_year_passes(void **state) { + run_one_test("2010-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='-2020'/>", + pcmk_rc_ok); +} + +static void +range_without_end_year_passes(void **state) { + run_one_test("2010-01-01", + "<date_spec " XML_ATTR_ID "='spec' years='2000-'/>", + pcmk_rc_ok); + run_one_test("2000-10-01", + "<date_spec " XML_ATTR_ID "='spec' years='2000-'/>", + pcmk_rc_ok); +} + +static void +yeardays_satisfies(void **state) { + run_one_test("2020-01-30", + "<date_spec " XML_ATTR_ID "='spec' yeardays='30'/>", + pcmk_rc_ok); +} + +static void +time_after_yeardays_spec(void **state) { + run_one_test("2020-02-15", + "<date_spec " XML_ATTR_ID "='spec' yeardays='40'/>", + pcmk_rc_after_range); +} + +static void +yeardays_feb_29_satisfies(void **state) { + run_one_test("2016-02-29", + "<date_spec " XML_ATTR_ID "='spec' yeardays='60'/>", + pcmk_rc_ok); +} + +static void +exact_ymd_satisfies(void **state) { + run_one_test("2001-12-31", + "<date_spec " XML_ATTR_ID "='spec' years='2001' months='12' " + "monthdays='31'/>", + pcmk_rc_ok); +} + +static void +range_in_month_satisfies(void **state) { + run_one_test("2001-06-10", + "<date_spec " XML_ATTR_ID "='spec' years='2001' months='6' " + "monthdays='1-10'/>", + pcmk_rc_ok); +} + +static void +exact_ymd_after_range(void **state) { + run_one_test("2001-12-31", + "<date_spec " XML_ATTR_ID "='spec' years='2001' months='12' " + "monthdays='30'/>", + pcmk_rc_after_range); +} + +static void +time_after_monthdays_range(void **state) { + run_one_test("2001-06-10", + "<date_spec " XML_ATTR_ID "='spec' years='2001' months='6' " + "monthdays='11-15'/>", + pcmk_rc_before_range); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(no_time_given), + cmocka_unit_test(any_time_satisfies_empty_spec), + cmocka_unit_test(time_satisfies_year_spec), + cmocka_unit_test(time_after_year_spec), + cmocka_unit_test(time_satisfies_year_range), + cmocka_unit_test(time_before_year_range), + cmocka_unit_test(time_after_year_range), + cmocka_unit_test(range_without_start_year_passes), + cmocka_unit_test(range_without_end_year_passes), + cmocka_unit_test(yeardays_satisfies), + cmocka_unit_test(time_after_yeardays_spec), + cmocka_unit_test(yeardays_feb_29_satisfies), + cmocka_unit_test(exact_ymd_satisfies), + cmocka_unit_test(range_in_month_satisfies), + cmocka_unit_test(exact_ymd_after_range), + cmocka_unit_test(time_after_monthdays_range)) diff --git a/lib/pengine/tests/status/Makefile.am b/lib/pengine/tests/status/Makefile.am new file mode 100644 index 0000000..3f95496 --- /dev/null +++ b/lib/pengine/tests/status/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2022 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# + +include $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +LDADD += $(top_builddir)/lib/pengine/libpe_status_test.la + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pe_find_node_any_test \ + pe_find_node_id_test \ + pe_find_node_test \ + pe_new_working_set_test \ + set_working_set_defaults_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/pengine/tests/status/pe_find_node_any_test.c b/lib/pengine/tests/status/pe_find_node_any_test.c new file mode 100644 index 0000000..b911424 --- /dev/null +++ b/lib/pengine/tests/status/pe_find_node_any_test.c @@ -0,0 +1,62 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +static void +empty_list(void **state) { + assert_null(pe_find_node_any(NULL, NULL, NULL)); + assert_null(pe_find_node_any(NULL, NULL, "cluster1")); + assert_null(pe_find_node_any(NULL, "id1", NULL)); + assert_null(pe_find_node_any(NULL, "id1", "cluster1")); +} + +static void +non_null_list(void **state) { + GList *nodes = NULL; + + pe_node_t *a = calloc(1, sizeof(pe_node_t)); + pe_node_t *b = calloc(1, sizeof(pe_node_t)); + + a->details = calloc(1, sizeof(struct pe_node_shared_s)); + a->details->uname = "cluster1"; + a->details->id = "id1"; + b->details = calloc(1, sizeof(struct pe_node_shared_s)); + b->details->uname = "cluster2"; + b->details->id = "id2"; + + nodes = g_list_append(nodes, a); + nodes = g_list_append(nodes, b); + + assert_ptr_equal(b, pe_find_node_any(nodes, "id2", NULL)); + assert_ptr_equal(b, pe_find_node_any(nodes, "ID2", NULL)); + + assert_ptr_equal(a, pe_find_node_any(nodes, "xyz", "cluster1")); + assert_ptr_equal(a, pe_find_node_any(nodes, NULL, "cluster1")); + + assert_null(pe_find_node_any(nodes, "id10", NULL)); + assert_null(pe_find_node_any(nodes, "nodeid1", NULL)); + assert_null(pe_find_node_any(nodes, NULL, "cluster10")); + assert_null(pe_find_node_any(nodes, NULL, "nodecluster1")); + assert_null(pe_find_node_any(nodes, "id3", "cluster3")); + assert_null(pe_find_node_any(nodes, NULL, NULL)); + + free(a->details); + free(a); + free(b->details); + free(b); + g_list_free(nodes); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_list), + cmocka_unit_test(non_null_list)) diff --git a/lib/pengine/tests/status/pe_find_node_id_test.c b/lib/pengine/tests/status/pe_find_node_id_test.c new file mode 100644 index 0000000..832a40a --- /dev/null +++ b/lib/pengine/tests/status/pe_find_node_id_test.c @@ -0,0 +1,51 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +static void +empty_list(void **state) { + assert_null(pe_find_node_id(NULL, NULL)); + assert_null(pe_find_node_id(NULL, "id1")); +} + +static void +non_null_list(void **state) { + GList *nodes = NULL; + + pe_node_t *a = calloc(1, sizeof(pe_node_t)); + pe_node_t *b = calloc(1, sizeof(pe_node_t)); + + a->details = calloc(1, sizeof(struct pe_node_shared_s)); + a->details->id = "id1"; + b->details = calloc(1, sizeof(struct pe_node_shared_s)); + b->details->id = "id2"; + + nodes = g_list_append(nodes, a); + nodes = g_list_append(nodes, b); + + assert_ptr_equal(a, pe_find_node_id(nodes, "id1")); + assert_null(pe_find_node_id(nodes, "id10")); + assert_null(pe_find_node_id(nodes, "nodeid1")); + assert_ptr_equal(b, pe_find_node_id(nodes, "ID2")); + assert_null(pe_find_node_id(nodes, "xyz")); + + free(a->details); + free(a); + free(b->details); + free(b); + g_list_free(nodes); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_list), + cmocka_unit_test(non_null_list)) diff --git a/lib/pengine/tests/status/pe_find_node_test.c b/lib/pengine/tests/status/pe_find_node_test.c new file mode 100644 index 0000000..7c7ea30 --- /dev/null +++ b/lib/pengine/tests/status/pe_find_node_test.c @@ -0,0 +1,51 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +static void +empty_list(void **state) { + assert_null(pe_find_node(NULL, NULL)); + assert_null(pe_find_node(NULL, "cluster1")); +} + +static void +non_null_list(void **state) { + GList *nodes = NULL; + + pe_node_t *a = calloc(1, sizeof(pe_node_t)); + pe_node_t *b = calloc(1, sizeof(pe_node_t)); + + a->details = calloc(1, sizeof(struct pe_node_shared_s)); + a->details->uname = "cluster1"; + b->details = calloc(1, sizeof(struct pe_node_shared_s)); + b->details->uname = "cluster2"; + + nodes = g_list_append(nodes, a); + nodes = g_list_append(nodes, b); + + assert_ptr_equal(a, pe_find_node(nodes, "cluster1")); + assert_null(pe_find_node(nodes, "cluster10")); + assert_null(pe_find_node(nodes, "nodecluster1")); + assert_ptr_equal(b, pe_find_node(nodes, "CLUSTER2")); + assert_null(pe_find_node(nodes, "xyz")); + + free(a->details); + free(a); + free(b->details); + free(b); + g_list_free(nodes); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_list), + cmocka_unit_test(non_null_list)) diff --git a/lib/pengine/tests/status/pe_new_working_set_test.c b/lib/pengine/tests/status/pe_new_working_set_test.c new file mode 100644 index 0000000..cf2df4f --- /dev/null +++ b/lib/pengine/tests/status/pe_new_working_set_test.c @@ -0,0 +1,46 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +#include "mock_private.h" + +static void +calloc_fails(void **state) { + pcmk__mock_calloc = true; // calloc() will return NULL + + expect_value(__wrap_calloc, nmemb, 1); + expect_value(__wrap_calloc, size, sizeof(pe_working_set_t)); + assert_null(pe_new_working_set()); + + pcmk__mock_calloc = false; // Use real calloc() +} + +static void +calloc_succeeds(void **state) { + pe_working_set_t *data_set = pe_new_working_set(); + + /* Nothing else to test about this function, as all it does is call + * set_working_set_defaults which is also a public function and should + * get its own unit test. + */ + assert_non_null(data_set); + + /* Avoid calling pe_free_working_set here so we don't artificially + * inflate the coverage numbers. + */ + free(data_set); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(calloc_fails), + cmocka_unit_test(calloc_succeeds)) diff --git a/lib/pengine/tests/status/set_working_set_defaults_test.c b/lib/pengine/tests/status/set_working_set_defaults_test.c new file mode 100644 index 0000000..c822278 --- /dev/null +++ b/lib/pengine/tests/status/set_working_set_defaults_test.c @@ -0,0 +1,46 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> +#include <crm/pengine/pe_types.h> +#include <crm/pengine/status.h> + +#include "mock_private.h" + +static void +check_defaults(void **state) { + uint32_t flags; + pe_working_set_t *data_set = calloc(1, sizeof(pe_working_set_t)); + + set_working_set_defaults(data_set); + + flags = pe_flag_stop_rsc_orphans|pe_flag_symmetric_cluster|pe_flag_stop_action_orphans; + + if (!strcmp(PCMK__CONCURRENT_FENCING_DEFAULT, "true")) { + flags |= pe_flag_concurrent_fencing; + } + + + assert_null(data_set->priv); + assert_int_equal(data_set->order_id, 1); + assert_int_equal(data_set->action_id, 1); + assert_int_equal(data_set->no_quorum_policy, no_quorum_stop); + assert_int_equal(data_set->flags, flags); + + /* Avoid calling pe_free_working_set here so we don't artificially + * inflate the coverage numbers. + */ + free(data_set); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(check_defaults)) diff --git a/lib/pengine/tests/unpack/Makefile.am b/lib/pengine/tests/unpack/Makefile.am new file mode 100644 index 0000000..baa8633 --- /dev/null +++ b/lib/pengine/tests/unpack/Makefile.am @@ -0,0 +1,18 @@ +# +# Copyright 2022 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# + +include $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +LDADD += $(top_builddir)/lib/pengine/libpe_status_test.la + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pe_base_name_end_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/pengine/tests/unpack/pe_base_name_end_test.c b/lib/pengine/tests/unpack/pe_base_name_end_test.c new file mode 100644 index 0000000..6f1c165 --- /dev/null +++ b/lib/pengine/tests/unpack/pe_base_name_end_test.c @@ -0,0 +1,36 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +static void +bad_args(void **state) { + assert_null(pe_base_name_end(NULL)); + assert_null(pe_base_name_end("")); +} + +static void +no_suffix(void **state) { + assert_string_equal(pe_base_name_end("rsc"), "c"); + assert_string_equal(pe_base_name_end("rsc0"), "0"); +} + +static void +has_suffix(void **state) { + assert_string_equal(pe_base_name_end("rsc:0"), "c:0"); + assert_string_equal(pe_base_name_end("rsc:100"), "c:100"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_args), + cmocka_unit_test(no_suffix), + cmocka_unit_test(has_suffix)) diff --git a/lib/pengine/tests/utils/Makefile.am b/lib/pengine/tests/utils/Makefile.am new file mode 100644 index 0000000..4a3e8a2 --- /dev/null +++ b/lib/pengine/tests/utils/Makefile.am @@ -0,0 +1,21 @@ +# +# Copyright 2022 the Pacemaker project contributors +# +# The version control history for this file may have further details. +# +# This source code is licensed under the GNU General Public License version 2 +# or later (GPLv2+) WITHOUT ANY WARRANTY. +# + +include $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +AM_CPPFLAGS += -I$(top_srcdir)/lib/pengine +LDADD += $(top_builddir)/lib/pengine/libpe_status_test.la + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + pe__cmp_node_name_test \ + pe__cmp_rsc_priority_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/pengine/tests/utils/pe__cmp_node_name_test.c b/lib/pengine/tests/utils/pe__cmp_node_name_test.c new file mode 100644 index 0000000..45d87ee --- /dev/null +++ b/lib/pengine/tests/utils/pe__cmp_node_name_test.c @@ -0,0 +1,55 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +struct pe_node_shared_s node1_details; +struct pe_node_shared_s node2_details; + +pe_node_t node1 = {.details = &node1_details}; +pe_node_t node2 = {.details = &node2_details}; + +static void +nodes_equal(void **state) +{ + assert_int_equal(pe__cmp_node_name(NULL, NULL), 0); + + node1.details->uname = "node10"; + node2.details->uname = "node10"; + assert_int_equal(pe__cmp_node_name(&node1, &node2), 0); +} + +static void +node1_first(void **state) +{ + assert_int_equal(pe__cmp_node_name(NULL, &node2), -1); + + // The heavy testing is done in pcmk__numeric_strcasecmp()'s unit tests + node1.details->uname = "node9"; + node2.details->uname = "node10"; + assert_int_equal(pe__cmp_node_name(&node1, &node2), -1); +} + +static void +node2_first(void **state) +{ + assert_int_equal(pe__cmp_node_name(&node1, NULL), 1); + + node1.details->uname = "node10"; + node2.details->uname = "node9"; + assert_int_equal(pe__cmp_node_name(&node1, &node2), 1); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(nodes_equal), + cmocka_unit_test(node1_first), + cmocka_unit_test(node2_first)) diff --git a/lib/pengine/tests/utils/pe__cmp_rsc_priority_test.c b/lib/pengine/tests/utils/pe__cmp_rsc_priority_test.c new file mode 100644 index 0000000..669e7a9 --- /dev/null +++ b/lib/pengine/tests/utils/pe__cmp_rsc_priority_test.c @@ -0,0 +1,50 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/pengine/internal.h> + +#include "pe_status_private.h" + +pe_resource_t rsc1; +pe_resource_t rsc2; + +static void +rscs_equal(void **state) +{ + rsc1.priority = 0; + rsc2.priority = 0; + assert_int_equal(pe__cmp_rsc_priority(NULL, NULL), 0); + assert_int_equal(pe__cmp_rsc_priority(&rsc1, &rsc2), 0); +} + +static void +rsc1_first(void **state) +{ + rsc1.priority = 1; + rsc2.priority = 0; + assert_int_equal(pe__cmp_rsc_priority(&rsc1, NULL), -1); + assert_int_equal(pe__cmp_rsc_priority(&rsc1, &rsc2), -1); +} + +static void +rsc2_first(void **state) +{ + rsc1.priority = 0; + rsc2.priority = 1; + assert_int_equal(pe__cmp_rsc_priority(NULL, &rsc2), 1); + assert_int_equal(pe__cmp_rsc_priority(&rsc1, &rsc2), 1); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(rscs_equal), + cmocka_unit_test(rsc1_first), + cmocka_unit_test(rsc2_first)) |