Signed-off-by: Benjamin Marzinski <bmarz...@redhat.com>
---
 tests/Makefile |   4 +-
 tests/valid.c  | 486 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 489 insertions(+), 1 deletion(-)
 create mode 100644 tests/valid.c

diff --git a/tests/Makefile b/tests/Makefile
index 77ff3249..7fc261c3 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \
 LIBDEPS += -L$(multipathdir) -lmultipath -lcmocka
 
 TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
-        alias directio
+        alias directio valid
 
 .SILENT: $(TESTS:%=%.o)
 .PRECIOUS: $(TESTS:%=%-test)
@@ -50,6 +50,8 @@ vpd-test_OBJDEPS :=  ../libmultipath/discovery.o
 vpd-test_LIBDEPS := -ludev -lpthread -ldl
 alias-test_TESTDEPS := test-log.o
 alias-test_LIBDEPS := -lpthread -ldl
+valid-test_OBJDEPS := ../libmultipath/valid.o
+valid-test_LIBDEPS := -ludev -lpthread -ldl
 ifneq ($(DIO_TEST_DEV),)
 directio-test_LIBDEPS := -laio
 endif
diff --git a/tests/valid.c b/tests/valid.c
new file mode 100644
index 00000000..693c72c5
--- /dev/null
+++ b/tests/valid.c
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2020 Benjamin Marzinski, Redhat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <cmocka.h>
+#include "globals.c"
+#include "util.h"
+#include "discovery.h"
+#include "wwids.h"
+#include "blacklist.h"
+#include "valid.h"
+
+int test_fd;
+struct udev_device {
+       int unused;
+} test_udev;
+
+bool __wrap_sysfs_is_multipathed(struct path *pp, bool set_wwid)
+{
+       bool is_multipathed = mock_type(bool);
+       assert_non_null(pp);
+       assert_int_not_equal(strlen(pp->dev), 0);
+       if (is_multipathed && set_wwid)
+               strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE);
+       return is_multipathed;
+}
+
+int __wrap___mpath_connect(int nonblocking)
+{
+       bool connected = mock_type(bool);
+       assert_int_equal(nonblocking, 1);
+       if (connected)
+               return test_fd;
+       errno = mock_type(int);
+       return -1;
+}
+
+int __wrap_systemd_service_enabled(const char *dev)
+{
+       return (int)mock_type(bool);
+}
+
+/* There's no point in checking the return value here */
+int __wrap_mpath_disconnect(int fd)
+{
+       assert_int_equal(fd, test_fd);
+       return 0;
+}
+
+struct udev_device *__wrap_udev_device_new_from_subsystem_sysname(struct udev 
*udev, const char *subsystem, const char *sysname)
+{
+       bool passed = mock_type(bool);
+       assert_string_equal(sysname, mock_ptr_type(char *));
+       if (passed)
+               return &test_udev;
+       return NULL;
+}
+
+int __wrap_pathinfo(struct path *pp, struct config *conf, int mask)
+{
+       int ret = mock_type(int);
+       assert_string_equal(pp->dev, mock_ptr_type(char *));
+       assert_int_equal(mask, DI_SYSFS | DI_WWID | DI_BLACKLIST);
+       if (ret == PATHINFO_OK) {
+               pp->uid_attribute = "ID_TEST";
+               strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE);
+       } else
+               memset(pp->wwid, 0, WWID_SIZE);
+       return ret;
+}
+
+int __wrap_filter_property(struct config *conf, struct udev_device *udev,
+                          int lvl, const char *uid_attribute)
+{
+       int ret = mock_type(int);
+       assert_string_equal(uid_attribute, "ID_TEST");
+       return ret;
+}
+
+int __wrap_is_failed_wwid(const char *wwid)
+{
+       int ret = mock_type(int);
+       assert_string_equal(wwid, mock_ptr_type(char *));
+       return ret;
+}
+
+int __wrap_check_wwids_file(char *wwid, int write_wwid)
+{
+       bool passed = mock_type(bool);
+       assert_int_equal(write_wwid, 0);
+       assert_string_equal(wwid, mock_ptr_type(char *));
+       if (passed)
+               return 0;
+       else
+               return -1;
+}
+
+int __wrap_dm_map_present_by_uuid(const char *uuid)
+{
+       int ret = mock_type(int);
+       assert_string_equal(uuid, mock_ptr_type(char *));
+       return ret;
+}
+
+enum {
+       STAGE_IS_MULTIPATHED,
+       STAGE_CHECK_MULTIPATHD,
+       STAGE_GET_UDEV_DEVICE,
+       STAGE_PATHINFO,
+       STAGE_FILTER_PROPERTY,
+       STAGE_IS_FAILED,
+       STAGE_CHECK_WWIDS,
+       STAGE_UUID_PRESENT,
+};
+
+enum {
+       CHECK_MPATHD_RUNNING,
+       CHECK_MPATHD_EAGAIN,
+       CHECK_MPATHD_ENABLED,
+       CHECK_MPATHD_SKIP,
+};
+
+/* setup the test to continue past the given stage in is_path_valid() */
+static void setup_passing(char *name, char *wwid, unsigned int 
check_multipathd,
+                         unsigned int stage)
+{
+       will_return(__wrap_sysfs_is_multipathed, false);
+       if (stage == STAGE_IS_MULTIPATHED)
+               return;
+       if (check_multipathd == CHECK_MPATHD_RUNNING)
+               will_return(__wrap___mpath_connect, true);
+       else if (check_multipathd == CHECK_MPATHD_EAGAIN) {
+               will_return(__wrap___mpath_connect, false);
+               will_return(__wrap___mpath_connect, EAGAIN);
+       } else if (check_multipathd == CHECK_MPATHD_ENABLED) {
+               will_return(__wrap___mpath_connect, false);
+               will_return(__wrap___mpath_connect, ECONNREFUSED);
+               will_return(__wrap_systemd_service_enabled, true);
+       }
+       /* nothing for CHECK_MPATHD_SKIP */
+       if (stage == STAGE_CHECK_MULTIPATHD)
+               return;
+       will_return(__wrap_udev_device_new_from_subsystem_sysname, true);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname,
+                   name);
+       if (stage == STAGE_GET_UDEV_DEVICE)
+               return;
+       will_return(__wrap_pathinfo, PATHINFO_OK);
+       will_return(__wrap_pathinfo, name);
+       will_return(__wrap_pathinfo, wwid);
+       if (stage == STAGE_PATHINFO)
+               return;
+       will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST_EXCEPT);
+       if (stage == STAGE_FILTER_PROPERTY)
+               return;
+       will_return(__wrap_is_failed_wwid, WWID_IS_NOT_FAILED);
+       will_return(__wrap_is_failed_wwid, wwid);
+       if (stage == STAGE_IS_FAILED)
+               return;
+       will_return(__wrap_check_wwids_file, false);
+       will_return(__wrap_check_wwids_file, wwid);
+       if (stage == STAGE_CHECK_WWIDS)
+               return;
+       will_return(__wrap_dm_map_present_by_uuid, 0);
+       will_return(__wrap_dm_map_present_by_uuid, wwid);
+}
+
+static void test_bad_arguments(void **state)
+{
+       struct path pp;
+       char too_long[FILE_NAME_SIZE + 1];
+
+       memset(&pp, 0, sizeof(pp));
+       /* test NULL pointers */
+       assert_int_equal(is_path_valid("test", &conf, NULL, true),
+                        PATH_IS_ERROR);
+       assert_int_equal(is_path_valid("test", NULL, &pp, true),
+                        PATH_IS_ERROR);
+       assert_int_equal(is_path_valid(NULL, &conf, &pp, true),
+                        PATH_IS_ERROR);
+       /* test undefined find_multipaths */
+       conf.find_multipaths = FIND_MULTIPATHS_UNDEF;
+       assert_int_equal(is_path_valid("test", &conf, &pp, true),
+                        PATH_IS_ERROR);
+       /* test name too long */
+       memset(too_long, 'x', sizeof(too_long));
+       too_long[sizeof(too_long) - 1] = '\0';
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       assert_int_equal(is_path_valid(too_long, &conf, &pp, true),
+                        PATH_IS_ERROR);
+}
+
+static void test_sysfs_is_multipathed(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test_wwid";
+
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       /* test for already existing multiapthed device */
+       will_return(__wrap_sysfs_is_multipathed, true);
+       will_return(__wrap_sysfs_is_multipathed, wwid);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_VALID_NO_CHECK);
+       assert_string_equal(pp.dev, name);
+       assert_string_equal(pp.wwid, wwid);
+       /* test for wwid device with empty wwid */
+       will_return(__wrap_sysfs_is_multipathed, true);
+       will_return(__wrap_sysfs_is_multipathed, "");
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_ERROR);
+}
+
+static void test_check_multipathd(void **state)
+{
+       struct path pp;
+       char *name = "test";
+
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       /* test failed check to see if multipathd is active */
+       will_return(__wrap_sysfs_is_multipathed, false);
+       will_return(__wrap___mpath_connect, false);
+       will_return(__wrap___mpath_connect, ECONNREFUSED);
+       will_return(__wrap_systemd_service_enabled, false);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_NOT_VALID);
+       assert_string_equal(pp.dev, name);
+       /* test pass because service is enabled. fail getting udev */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, NULL, CHECK_MPATHD_ENABLED, STAGE_CHECK_MULTIPATHD);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname, false);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname,
+                   name);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_ERROR);
+       assert_string_equal(pp.dev, name);
+       /* test pass because connect returned EAGAIN. fail getting udev */
+       setup_passing(name, NULL, CHECK_MPATHD_EAGAIN, STAGE_CHECK_MULTIPATHD);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname, false);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname,
+                   name);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_ERROR);
+       /* test pass because connect succeeded. fail getting udev */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, NULL, CHECK_MPATHD_RUNNING, STAGE_CHECK_MULTIPATHD);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname, false);
+       will_return(__wrap_udev_device_new_from_subsystem_sysname,
+                   name);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_ERROR);
+       assert_string_equal(pp.dev, name);
+}
+
+static void test_pathinfo(void **state)
+{
+       struct path pp;
+       char *name = "test";
+
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       /* Test pathinfo blacklisting device */
+       setup_passing(name, NULL, CHECK_MPATHD_SKIP, STAGE_GET_UDEV_DEVICE);
+       will_return(__wrap_pathinfo, PATHINFO_SKIPPED);
+       will_return(__wrap_pathinfo, name);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       /* Test pathinfo failing */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, NULL, CHECK_MPATHD_SKIP, STAGE_GET_UDEV_DEVICE);
+       will_return(__wrap_pathinfo, PATHINFO_FAILED);
+       will_return(__wrap_pathinfo, name);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_ERROR);
+       /* Test blank wwid */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, NULL, CHECK_MPATHD_SKIP, STAGE_GET_UDEV_DEVICE);
+       will_return(__wrap_pathinfo, PATHINFO_OK);
+       will_return(__wrap_pathinfo, name);
+       will_return(__wrap_pathinfo, "");
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+}
+
+static void test_filter_property(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test-wwid";
+
+       /* test blacklist property */
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO);
+       will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+       /* test missing property */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO);
+       will_return(__wrap_filter_property, MATCH_PROPERTY_BLIST_MISSING);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       /* test MATCH_NOTHING fail on is_failed_wwid */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_PATHINFO);
+       will_return(__wrap_filter_property, MATCH_NOTHING);
+       will_return(__wrap_is_failed_wwid, WWID_IS_FAILED);
+       will_return(__wrap_is_failed_wwid, wwid);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+}
+
+static void test_is_failed_wwid(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test-wwid";
+
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       /* Test wwid failed */
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_FILTER_PROPERTY);
+       will_return(__wrap_is_failed_wwid, WWID_IS_FAILED);
+       will_return(__wrap_is_failed_wwid, wwid);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+       /* test is_failed_wwid error */
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_FILTER_PROPERTY);
+       will_return(__wrap_is_failed_wwid, WWID_FAILED_ERROR);
+       will_return(__wrap_is_failed_wwid, wwid);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_ERROR);
+}
+
+static void test_greedy(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test-wwid";
+
+       /* test greedy success with checking multipathd */
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_GREEDY;
+       setup_passing(name, wwid, CHECK_MPATHD_RUNNING, STAGE_IS_FAILED);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_VALID);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+       /* test greedy success without checking multiapthd */
+       memset(&pp, 0, sizeof(pp));
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_IS_FAILED);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_VALID);
+}
+
+static void test_check_wwids(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test-wwid";
+
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       setup_passing(name, wwid, CHECK_MPATHD_EAGAIN, STAGE_IS_FAILED);
+       will_return(__wrap_check_wwids_file, true);
+       will_return(__wrap_check_wwids_file, wwid);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_VALID_NO_CHECK);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+}
+
+static void test_check_uuid_present(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test-wwid";
+
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       setup_passing(name, wwid, CHECK_MPATHD_ENABLED, STAGE_CHECK_WWIDS);
+       will_return(__wrap_dm_map_present_by_uuid, 1);
+       will_return(__wrap_dm_map_present_by_uuid, wwid);
+       assert_int_equal(is_path_valid(name, &conf, &pp, true),
+                        PATH_IS_VALID);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+}
+
+
+static void test_find_multipaths(void **state)
+{
+       struct path pp;
+       char *name = "test";
+       char *wwid = "test-wwid";
+
+       /* test find_multipaths = FIND_MULTIPATHS_STRICT */
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_STRICT;
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+       /* test find_multipaths = FIND_MULTIPATHS_OFF */
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_OFF;
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       /* test find_multipaths = FIND_MULTIPATHS_ON */
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_ON;
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_NOT_VALID);
+       /* test find_multipaths = FIND_MULTIPATHS_SMART */
+       memset(&pp, 0, sizeof(pp));
+       conf.find_multipaths = FIND_MULTIPATHS_SMART;
+       setup_passing(name, wwid, CHECK_MPATHD_SKIP, STAGE_UUID_PRESENT);
+       assert_int_equal(is_path_valid(name, &conf, &pp, false),
+                        PATH_IS_MAYBE_VALID);
+       assert_string_equal(pp.dev, name);
+       assert_ptr_equal(pp.udev, &test_udev);
+       assert_string_equal(pp.wwid, wwid);
+}
+
+int test_valid(void)
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_bad_arguments),
+               cmocka_unit_test(test_sysfs_is_multipathed),
+               cmocka_unit_test(test_check_multipathd),
+               cmocka_unit_test(test_pathinfo),
+               cmocka_unit_test(test_filter_property),
+               cmocka_unit_test(test_is_failed_wwid),
+               cmocka_unit_test(test_greedy),
+               cmocka_unit_test(test_check_wwids),
+               cmocka_unit_test(test_check_uuid_present),
+               cmocka_unit_test(test_find_multipaths),
+       };
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+int main(void)
+{
+       int ret = 0;
+       ret += test_valid();
+       return ret;
+}
-- 
2.17.2

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel

Reply via email to