[dm-devel] [PATCH 4/6] Unit tests for is_path_valid()

Benjamin Marzinski bmarzins at redhat.com
Mon May 18 18:57:49 UTC 2020


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 at redhat.com>
> 
> 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 at suse.com>, Tel. +49 (0)911 74053 2107
> SUSE  Software Solutions Germany GmbH
> HRB 36809, AG Nürnberg GF: Felix
> Imendörffer
> 




More information about the dm-devel mailing list