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

Martin Wilck Martin.Wilck at suse.com
Fri May 15 20:37:23 UTC 2020


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.

> ---
>  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