On Fri, May 15, 2020 at 08:37:23PM +0000, Martin Wilck wrote: > On Thu, 2020-05-14 at 20:59 -0500, Benjamin Marzinski wrote: > > Signed-off-by: Benjamin Marzinski <bmarzins@xxxxxxxxxx> > > Two minor nits below, otherwise ack. Sure. I can fix those up. -Ben > > > --- > > tests/Makefile | 4 +- > > tests/valid.c | 424 > > +++++++++++++++++++++++++++++++++++++++++++++++++ > > 2 files changed, 427 insertions(+), 1 deletion(-) > > create mode 100644 tests/valid.c > > > > diff --git a/tests/Makefile b/tests/Makefile > > index 1b8706a7..125553b8 100644 > > --- a/tests/Makefile > > +++ b/tests/Makefile > > @@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) > > -I$(mpathcmddir) \ > > LIBDEPS += -L$(multipathdir) -L$(mpathcmddir) -lmultipath -lmpathcmd > > -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..b128b029 > > --- /dev/null > > +++ b/tests/valid.c > > @@ -0,0 +1,424 @@ > > +/* > > + * 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 "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) > > + strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE); > > + else > > + memset(pp->wwid, 0, WWID_SIZE); > > + 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_IS_FAILED, > > + STAGE_CHECK_WWIDS, > > + STAGE_UUID_PRESENT, > > +}; > > nice :-) > > > + > > +/* setup the test to continue past the given stage in > > is_path_valid() */ > > +static void setup_passing(char *name, char *wwid, bool > > check_multipathd, > > + unsigned int stage) > > +{ > > + will_return(__wrap_sysfs_is_multipathed, false); > > + if (stage == STAGE_IS_MULTIPATHED) > > + return; > > + if (check_multipathd) > > + will_return(__wrap___mpath_connect, true); > > + 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_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_mutlipaths */ > > typo > > > + 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)); > > + 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, true); > > + 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 > > */ > > + will_return(__wrap_sysfs_is_multipathed, false); > > + will_return(__wrap___mpath_connect, false); > > + will_return(__wrap___mpath_connect, EAGAIN); > > Here we may want a test that should succeeds with PATH_IS_VALID after > mpath_connect returns EAGAIN. > > > + 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)); > > + will_return(__wrap_sysfs_is_multipathed, false); > > + will_return(__wrap___mpath_connect, true); > > + 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, false, 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, false, 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, false, 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_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, false, STAGE_PATHINFO); > > + 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, false, STAGE_PATHINFO); > > + 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"; > > + > > + memset(&pp, 0, sizeof(pp)); > > + conf.find_multipaths = FIND_MULTIPATHS_GREEDY; > > + setup_passing(name, wwid, false, STAGE_IS_FAILED); > > + assert_int_equal(is_path_valid(name, &conf, &pp, false), > > + 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_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, false, 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, false), > > + 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, false, 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, false), > > + 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, false, 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, false, 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, false, 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, false, 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_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; > > +} > > -- > Dr. Martin Wilck <mwilck@xxxxxxxx>, Tel. +49 (0)911 74053 2107 > SUSE Software Solutions Germany GmbH > HRB 36809, AG Nürnberg GF: Felix > Imendörffer > -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel