Blame tests/hwtable.c

Packit Service 0af388
/* Set BROKEN to 1 to treat broken behavior as success */
Packit Service 0af388
#define BROKEN 1
Packit Service 0af388
#define VERBOSITY 2
Packit Service 0af388
Packit Service 0af388
#include <stdbool.h>
Packit Service 0af388
#include <stdarg.h>
Packit Service 0af388
#include <stddef.h>
Packit Service 0af388
#include <setjmp.h>
Packit Service 0af388
#include <stdlib.h>
Packit Service 0af388
#include <cmocka.h>
Packit Service 0af388
#include <libudev.h>
Packit Service 0af388
#include <sys/stat.h>
Packit Service 0af388
#include <fcntl.h>
Packit Service 0af388
#include <unistd.h>
Packit Service 0af388
#include <stdio.h>
Packit Service 0af388
#include <errno.h>
Packit Service 0af388
#include <limits.h>
Packit Service 0af388
#include <sys/sysmacros.h>
Packit Service 0af388
#include "structs.h"
Packit Service 0af388
#include "structs_vec.h"
Packit Service 0af388
#include "config.h"
Packit Service 0af388
#include "debug.h"
Packit Service 0af388
#include "defaults.h"
Packit Service 0af388
#include "pgpolicies.h"
Packit Service 0af388
#include "test-lib.h"
Packit Service 0af388
#include "print.h"
Packit Service 0af388
#include "util.h"
Packit Service 0af388
Packit Service 0af388
#define N_CONF_FILES 2
Packit Service 0af388
Packit Service 0af388
static const char tmplate[] = "/tmp/hwtable-XXXXXX";
Packit Service 0af388
/* pretend new dm, use minio_rq */
Packit Service 0af388
static const unsigned int dm_tgt_version[3] = { 1, 1, 1 };
Packit Service 0af388
Packit Service 0af388
struct key_value {
Packit Service 0af388
	const char *key;
Packit Service 0af388
	const char *value;
Packit Service 0af388
};
Packit Service 0af388
Packit Service 0af388
struct hwt_state {
Packit Service 0af388
	char *tmpname;
Packit Service 0af388
	char *dirname;
Packit Service 0af388
	FILE *config_file;
Packit Service 0af388
	FILE *conf_dir_file[N_CONF_FILES];
Packit Service 0af388
	struct vectors *vecs;
Packit Service 0af388
	void (*test)(const struct hwt_state *);
Packit Service 0af388
	const char *test_name;
Packit Service 0af388
};
Packit Service 0af388
Packit Service 0af388
#define SET_TEST_FUNC(hwt, func) do {		\
Packit Service 0af388
		hwt->test = func;		\
Packit Service 0af388
		hwt->test_name = #func;		\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
static struct config *_conf;
Packit Service 0af388
struct udev *udev;
Packit Service 0af388
int logsink = -1;
Packit Service 0af388
Packit Service 0af388
struct config *get_multipath_config(void)
Packit Service 0af388
{
Packit Service 0af388
	return _conf;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
void put_multipath_config(void *arg)
Packit Service 0af388
{}
Packit Service 0af388
Packit Service 0af388
void make_config_file_path(char *buf, int buflen,
Packit Service 0af388
			  const struct hwt_state *hwt, int i)
Packit Service 0af388
{
Packit Service 0af388
	static const char fn_template[] = "%s/test-%02d.conf";
Packit Service 0af388
Packit Service 0af388
	if (i == -1)
Packit Service 0af388
		/* main config file */
Packit Service 0af388
		snprintf(buf, buflen, fn_template, hwt->tmpname, 0);
Packit Service 0af388
	else
Packit Service 0af388
		snprintf(buf, buflen, fn_template, hwt->dirname, i);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void reset_vecs(struct vectors *vecs)
Packit Service 0af388
{
Packit Service 0af388
	remove_maps(vecs);
Packit Service 0af388
	free_pathvec(vecs->pathvec, FREE_PATHS);
Packit Service 0af388
Packit Service 0af388
	vecs->pathvec = vector_alloc();
Packit Service 0af388
	assert_ptr_not_equal(vecs->pathvec, NULL);
Packit Service 0af388
	vecs->mpvec = vector_alloc();
Packit Service 0af388
	assert_ptr_not_equal(vecs->mpvec, NULL);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void free_hwt(struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	char buf[PATH_MAX];
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	if (hwt->config_file != NULL)
Packit Service 0af388
		fclose(hwt->config_file);
Packit Service 0af388
	for (i = 0; i < N_CONF_FILES; i++) {
Packit Service 0af388
		if (hwt->conf_dir_file[i] != NULL)
Packit Service 0af388
			fclose(hwt->conf_dir_file[i]);
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
	if (hwt->tmpname != NULL) {
Packit Service 0af388
		make_config_file_path(buf, sizeof(buf), hwt, -1);
Packit Service 0af388
		unlink(buf);
Packit Service 0af388
		rmdir(hwt->tmpname);
Packit Service 0af388
		free(hwt->tmpname);
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
	if (hwt->dirname != NULL) {
Packit Service 0af388
		for (i = 0; i < N_CONF_FILES; i++) {
Packit Service 0af388
			make_config_file_path(buf, sizeof(buf), hwt, i);
Packit Service 0af388
			unlink(buf);
Packit Service 0af388
		}
Packit Service 0af388
		rmdir(hwt->dirname);
Packit Service 0af388
		free(hwt->dirname);
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
	if (hwt->vecs != NULL) {
Packit Service 0af388
		if (hwt->vecs->mpvec != NULL)
Packit Service 0af388
			remove_maps(hwt->vecs);
Packit Service 0af388
		if (hwt->vecs->pathvec != NULL)
Packit Service 0af388
			free_pathvec(hwt->vecs->pathvec, FREE_PATHS);
Packit Service 0af388
		pthread_mutex_destroy(&hwt->vecs->lock.mutex);
Packit Service 0af388
		free(hwt->vecs);
Packit Service 0af388
	}
Packit Service 0af388
	free(hwt);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt;
Packit Service 0af388
	char buf[PATH_MAX];
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	*state = NULL;
Packit Service 0af388
	hwt = calloc(1, sizeof(*hwt));
Packit Service 0af388
	if (hwt == NULL)
Packit Service 0af388
		return -1;
Packit Service 0af388
Packit Service 0af388
	snprintf(buf, sizeof(buf), "%s", tmplate);
Packit Service 0af388
	if (mkdtemp(buf) == NULL) {
Packit Service 0af388
		condlog(0, "mkdtemp: %s", strerror(errno));
Packit Service 0af388
		goto err;
Packit Service 0af388
	}
Packit Service 0af388
	hwt->tmpname = strdup(buf);
Packit Service 0af388
Packit Service 0af388
	snprintf(buf, sizeof(buf), "%s", tmplate);
Packit Service 0af388
	if (mkdtemp(buf) == NULL) {
Packit Service 0af388
		condlog(0, "mkdtemp (2): %s", strerror(errno));
Packit Service 0af388
		goto err;
Packit Service 0af388
	}
Packit Service 0af388
	hwt->dirname = strdup(buf);
Packit Service 0af388
Packit Service 0af388
	make_config_file_path(buf, sizeof(buf), hwt, -1);
Packit Service 0af388
	hwt->config_file = fopen(buf, "w+");
Packit Service 0af388
	if (hwt->config_file == NULL)
Packit Service 0af388
		goto err;
Packit Service 0af388
Packit Service 0af388
	for (i = 0; i < N_CONF_FILES; i++) {
Packit Service 0af388
		make_config_file_path(buf, sizeof(buf), hwt, i);
Packit Service 0af388
		hwt->conf_dir_file[i] = fopen(buf, "w+");
Packit Service 0af388
		if (hwt->conf_dir_file[i] == NULL)
Packit Service 0af388
			goto err;
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
	hwt->vecs = calloc(1, sizeof(*hwt->vecs));
Packit Service 0af388
	if (hwt->vecs == NULL)
Packit Service 0af388
		goto err;
Packit Service 0af388
	pthread_mutex_init(&hwt->vecs->lock.mutex, NULL);
Packit Service 0af388
	hwt->vecs->pathvec = vector_alloc();
Packit Service 0af388
	hwt->vecs->mpvec = vector_alloc();
Packit Service 0af388
	if (hwt->vecs->pathvec == NULL || hwt->vecs->mpvec == NULL)
Packit Service 0af388
		goto err;
Packit Service 0af388
Packit Service 0af388
	*state = hwt;
Packit Service 0af388
	return 0;
Packit Service 0af388
Packit Service 0af388
err:
Packit Service 0af388
	free_hwt(hwt);
Packit Service 0af388
	return -1;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int teardown(void **state)
Packit Service 0af388
{
Packit Service 0af388
	if (state == NULL || *state == NULL)
Packit Service 0af388
		return -1;
Packit Service 0af388
Packit Service 0af388
	free_hwt(*state);
Packit Service 0af388
	*state = NULL;
Packit Service 0af388
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Helpers for creating the config file(s)
Packit Service 0af388
 */
Packit Service 0af388
Packit Service 0af388
static void reset_config(FILE *ff)
Packit Service 0af388
{
Packit Service 0af388
	if (ff == NULL)
Packit Service 0af388
		return;
Packit Service 0af388
	rewind(ff);
Packit Service 0af388
	if (ftruncate(fileno(ff), 0) == -1)
Packit Service 0af388
		condlog(1, "ftruncate: %s", strerror(errno));
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void reset_configs(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	reset_config(hwt->config_file);
Packit Service 0af388
	for (i = 0; i < N_CONF_FILES; i++)
Packit Service 0af388
		reset_config(hwt->conf_dir_file[i]);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void write_key_values(FILE *ff, int nkv, const struct key_value *kv)
Packit Service 0af388
{
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	for (i = 0; i < nkv; i++) {
Packit Service 0af388
		if (strchr(kv[i].value, ' ') == NULL &&
Packit Service 0af388
		    strchr(kv[i].value, '\"') == NULL)
Packit Service 0af388
			fprintf(ff, "\t%s %s\n", kv[i].key, kv[i].value);
Packit Service 0af388
		else
Packit Service 0af388
			fprintf(ff, "\t%s \"%s\"\n", kv[i].key, kv[i].value);
Packit Service 0af388
	}
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void begin_section(FILE *ff, const char *section)
Packit Service 0af388
{
Packit Service 0af388
	fprintf(ff, "%s {\n", section);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void end_section(FILE *ff)
Packit Service 0af388
{
Packit Service 0af388
	fprintf(ff, "}\n");
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void write_section(FILE *ff, const char *section,
Packit Service 0af388
			  int nkv, const struct key_value *kv)
Packit Service 0af388
{
Packit Service 0af388
	begin_section(ff, section);
Packit Service 0af388
	write_key_values(ff, nkv, kv);
Packit Service 0af388
	end_section(ff);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void write_defaults(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	static const char bindings_name[] = "bindings";
Packit Service 0af388
	static struct key_value defaults[] = {
Packit Service 0af388
		{ "config_dir", NULL },
Packit Service 0af388
		{ "bindings_file", NULL },
Packit Service 0af388
		{ "multipath_dir", NULL },
Packit Service 0af388
		{ "detect_prio", "no" },
Packit Service 0af388
		{ "detect_checker", "no" },
Packit Service 0af388
	};
Packit Service 0af388
	char buf[sizeof(tmplate) + sizeof(bindings_name)];
Packit Service 0af388
	char dirbuf[PATH_MAX];
Packit Service 0af388
Packit Service 0af388
	snprintf(buf, sizeof(buf), "%s/%s", hwt->tmpname, bindings_name);
Packit Service 0af388
	defaults[0].value = hwt->dirname;
Packit Service 0af388
	defaults[1].value = buf;
Packit Service 0af388
	assert_ptr_not_equal(getcwd(dirbuf, sizeof(dirbuf)), NULL);
Packit Service 0af388
	strncat(dirbuf, "/lib", sizeof(dirbuf) - 5);
Packit Service 0af388
	defaults[2].value = dirbuf;
Packit Service 0af388
	write_section(hwt->config_file, "defaults",
Packit Service 0af388
		      ARRAY_SIZE(defaults), defaults);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void begin_config(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	reset_configs(hwt);
Packit Service 0af388
	write_defaults(hwt);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void begin_section_all(const struct hwt_state *hwt, const char *section)
Packit Service 0af388
{
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	begin_section(hwt->config_file, section);
Packit Service 0af388
	for (i = 0; i < N_CONF_FILES; i++)
Packit Service 0af388
		begin_section(hwt->conf_dir_file[i], section);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void end_section_all(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	end_section(hwt->config_file);
Packit Service 0af388
	for (i = 0; i < N_CONF_FILES; i++)
Packit Service 0af388
		end_section(hwt->conf_dir_file[i]);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void finish_config(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	int i;
Packit Service 0af388
Packit Service 0af388
	fflush(hwt->config_file);
Packit Service 0af388
	for (i = 0; i < N_CONF_FILES; i++) {
Packit Service 0af388
		fflush(hwt->conf_dir_file[i]);
Packit Service 0af388
	}
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static void write_device(FILE *ff, int nkv, const struct key_value *kv)
Packit Service 0af388
{
Packit Service 0af388
	write_section(ff, "device", nkv, kv);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Some macros to avoid boilerplace code
Packit Service 0af388
 */
Packit Service 0af388
Packit Service 0af388
#define CHECK_STATE(state) ({ \
Packit Service 0af388
	assert_ptr_not_equal(state, NULL); \
Packit Service 0af388
	assert_ptr_not_equal(*(state), NULL);	\
Packit Service 0af388
	*state; })
Packit Service 0af388
Packit Service 0af388
#define WRITE_EMPTY_CONF(hwt) do {				\
Packit Service 0af388
		begin_config(hwt);				\
Packit Service 0af388
		finish_config(hwt);				\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
#define WRITE_ONE_DEVICE(hwt, kv) do {					\
Packit Service 0af388
		begin_config(hwt);					\
Packit Service 0af388
		begin_section_all(hwt, "devices");			\
Packit Service 0af388
		write_device(hwt->config_file, ARRAY_SIZE(kv), kv);	\
Packit Service 0af388
		end_section_all(hwt);					\
Packit Service 0af388
		finish_config(hwt);					\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
#define WRITE_TWO_DEVICES(hwt, kv1, kv2) do {				\
Packit Service 0af388
		begin_config(hwt);					\
Packit Service 0af388
		begin_section_all(hwt, "devices");			\
Packit Service 0af388
		write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);	\
Packit Service 0af388
		write_device(hwt->config_file, ARRAY_SIZE(kv2), kv2);	\
Packit Service 0af388
		end_section_all(hwt);					\
Packit Service 0af388
		finish_config(hwt);					\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
#define WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2) do {			\
Packit Service 0af388
		begin_config(hwt);					\
Packit Service 0af388
		begin_section_all(hwt, "devices");			\
Packit Service 0af388
		write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);	\
Packit Service 0af388
		write_device(hwt->conf_dir_file[0],			\
Packit Service 0af388
			     ARRAY_SIZE(kv2), kv2);			\
Packit Service 0af388
		end_section_all(hwt);					\
Packit Service 0af388
		finish_config(hwt);					\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
#define LOAD_CONFIG(hwt) ({ \
Packit Service 0af388
	char buf[PATH_MAX];	   \
Packit Service 0af388
	struct config *__cf;						\
Packit Service 0af388
									\
Packit Service 0af388
	make_config_file_path(buf, sizeof(buf), hwt, -1);		\
Packit Service 0af388
	__cf = load_config(buf);					\
Packit Service 0af388
	assert_ptr_not_equal(__cf, NULL);				\
Packit Service 0af388
	assert_ptr_not_equal(__cf->hwtable, NULL);			\
Packit Service 0af388
	__cf->verbosity = VERBOSITY;					\
Packit Service 0af388
	memcpy(&__cf->version, dm_tgt_version, sizeof(__cf->version));	\
Packit Service 0af388
	__cf; })
Packit Service 0af388
Packit Service 0af388
#define FREE_CONFIG(conf) do {			\
Packit Service 0af388
		free_config(conf);		\
Packit Service 0af388
		conf = NULL;			\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
static void replace_config(const struct hwt_state *hwt,
Packit Service 0af388
			   const char *conf_str)
Packit Service 0af388
{
Packit Service 0af388
	FREE_CONFIG(_conf);
Packit Service 0af388
	reset_configs(hwt);
Packit Service 0af388
	fprintf(hwt->config_file, "%s", conf_str);
Packit Service 0af388
	fflush(hwt->config_file);
Packit Service 0af388
	_conf = LOAD_CONFIG(hwt);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
#define TEST_PROP(prop, val) do {				\
Packit Service 0af388
		if (val == NULL)				\
Packit Service 0af388
			assert_ptr_equal(prop, NULL);		\
Packit Service 0af388
		else {						\
Packit Service 0af388
			assert_ptr_not_equal(prop, NULL);	\
Packit Service 0af388
			assert_string_equal(prop, val);		\
Packit Service 0af388
		}						\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
#if BROKEN
Packit Service 0af388
#define TEST_PROP_BROKEN(name, prop, bad, good) do {			\
Packit Service 0af388
		condlog(1, "%s: WARNING: Broken test for %s == \"%s\" on line %d, should be \"%s\"", \
Packit Service 0af388
			__func__, name, bad ? bad : "NULL",		\
Packit Service 0af388
			__LINE__, good ? good : "NULL");			\
Packit Service 0af388
		TEST_PROP(prop, bad);					\
Packit Service 0af388
	} while (0)
Packit Service 0af388
#else
Packit Service 0af388
#define TEST_PROP_BROKEN(name, prop, bad, good) TEST_PROP(prop, good)
Packit Service 0af388
#endif
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Some predefined key/value pairs
Packit Service 0af388
 */
Packit Service 0af388
Packit Service 0af388
static const char _wwid[] = "wwid";
Packit Service 0af388
static const char _vendor[] = "vendor";
Packit Service 0af388
static const char _product[] = "product";
Packit Service 0af388
static const char _prio[] = "prio";
Packit Service 0af388
static const char _checker[] = "path_checker";
Packit Service 0af388
static const char _getuid[] = "getuid_callout";
Packit Service 0af388
static const char _uid_attr[] = "uid_attribute";
Packit Service 0af388
static const char _bl_product[] = "product_blacklist";
Packit Service 0af388
static const char _minio[] = "rr_min_io_rq";
Packit Service 0af388
static const char _no_path_retry[] = "no_path_retry";
Packit Service 0af388
Packit Service 0af388
/* Device identifiers */
Packit Service 0af388
static const struct key_value vnd_foo = { _vendor, "foo" };
Packit Service 0af388
static const struct key_value prd_bar = { _product, "bar" };
Packit Service 0af388
static const struct key_value prd_bam = { _product, "bam" };
Packit Service 0af388
static const struct key_value prd_baq = { _product, "\"bar\"" };
Packit Service 0af388
static const struct key_value prd_baqq = { _product, "\"\"bar\"\"" };
Packit Service 0af388
static const struct key_value prd_barz = { _product, "barz" };
Packit Service 0af388
static const struct key_value vnd_boo = { _vendor, "boo" };
Packit Service 0af388
static const struct key_value prd_baz = { _product, "baz" };
Packit Service 0af388
static const struct key_value wwid_test = { _wwid, default_wwid };
Packit Service 0af388
Packit Service 0af388
/* Regular expresssions */
Packit Service 0af388
static const struct key_value vnd__oo = { _vendor, ".oo" };
Packit Service 0af388
static const struct key_value vnd_t_oo = { _vendor, "^.oo" };
Packit Service 0af388
static const struct key_value prd_ba_ = { _product, "ba." };
Packit Service 0af388
static const struct key_value prd_ba_s = { _product, "(bar|baz|ba\\.)$" };
Packit Service 0af388
/* Pathological cases, see below */
Packit Service 0af388
static const struct key_value prd_barx = { _product, "ba[[rxy]" };
Packit Service 0af388
static const struct key_value prd_bazy = { _product, "ba[zy]" };
Packit Service 0af388
static const struct key_value prd_bazy1 = { _product, "ba(z|y)" };
Packit Service 0af388
Packit Service 0af388
/* Properties */
Packit Service 0af388
static const struct key_value prio_emc = { _prio, "emc" };
Packit Service 0af388
static const struct key_value prio_hds = { _prio, "hds" };
Packit Service 0af388
static const struct key_value prio_rdac = { _prio, "rdac" };
Packit Service 0af388
static const struct key_value chk_hp = { _checker, "hp_sw" };
Packit Service 0af388
static const struct key_value gui_foo = { _getuid, "/tmp/foo" };
Packit Service 0af388
static const struct key_value uid_baz = { _uid_attr, "BAZ_ATTR" };
Packit Service 0af388
static const struct key_value bl_bar = { _bl_product, "bar" };
Packit Service 0af388
static const struct key_value bl_baz = { _bl_product, "baz" };
Packit Service 0af388
static const struct key_value bl_barx = { _bl_product, "ba[[rxy]" };
Packit Service 0af388
static const struct key_value bl_bazy = { _bl_product, "ba[zy]" };
Packit Service 0af388
static const struct key_value minio_99 = { _minio, "99" };
Packit Service 0af388
static const struct key_value npr_37 = { _no_path_retry, "37" };
Packit Service 0af388
static const struct key_value npr_queue = { _no_path_retry, "queue" };
Packit Service 0af388
Packit Service 0af388
/***** BEGIN TESTS SECTION *****/
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Dump the configuration, subistitute the dumped configuration
Packit Service 0af388
 * for the current one, and verify that the result is identical.
Packit Service 0af388
 */
Packit Service 0af388
static void replicate_config(const struct hwt_state *hwt, bool local)
Packit Service 0af388
{
Packit Service 0af388
	char *cfg1, *cfg2;
Packit Service 0af388
	vector hwtable;
Packit Service 0af388
	struct config *conf;
Packit Service 0af388
Packit Service 0af388
	condlog(3, "--- %s: replicating %s configuration", __func__,
Packit Service 0af388
		local ? "local" : "full");
Packit Service 0af388
Packit Service 0af388
	conf = get_multipath_config();
Packit Service 0af388
	if (!local)
Packit Service 0af388
		/* "full" configuration */
Packit Service 0af388
		cfg1 = snprint_config(conf, NULL, NULL, NULL);
Packit Service 0af388
	else {
Packit Service 0af388
		/* "local" configuration */
Packit Service 0af388
		hwtable = get_used_hwes(hwt->vecs->pathvec);
Packit Service 0af388
		cfg1 = snprint_config(conf, NULL, hwtable, hwt->vecs->mpvec);
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
	assert_non_null(cfg1);
Packit Service 0af388
	put_multipath_config(conf);
Packit Service 0af388
Packit Service 0af388
	replace_config(hwt, cfg1);
Packit Service 0af388
Packit Service 0af388
	/*
Packit Service 0af388
	 * The local configuration adds multipath entries, and may move device
Packit Service 0af388
	 * entries for local devices to the end of the list. Identical config
Packit Service 0af388
	 * strings therefore can't be expected in the "local" case.
Packit Service 0af388
	 * That doesn't matter. The important thing is that, with the reloaded
Packit Service 0af388
	 * configuration, the test case still passes.
Packit Service 0af388
	 */
Packit Service 0af388
	if (local) {
Packit Service 0af388
		free(cfg1);
Packit Service 0af388
		return;
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
	conf = get_multipath_config();
Packit Service 0af388
	cfg2 = snprint_config(conf, NULL, NULL, NULL);
Packit Service 0af388
	assert_non_null(cfg2);
Packit Service 0af388
	put_multipath_config(conf);
Packit Service 0af388
Packit Service 0af388
// #define DBG_CONFIG 1
Packit Service 0af388
#ifdef DBG_CONFIG
Packit Service 0af388
#define DUMP_CFG_STR(x) do {						\
Packit Service 0af388
		FILE *tmp = fopen("/tmp/hwtable-" #x ".txt", "w");	\
Packit Service 0af388
		fprintf(tmp, "%s", x);					\
Packit Service 0af388
		fclose(tmp);						\
Packit Service 0af388
	} while (0)
Packit Service 0af388
Packit Service 0af388
	DUMP_CFG_STR(cfg1);
Packit Service 0af388
	DUMP_CFG_STR(cfg2);
Packit Service 0af388
#endif
Packit Service 0af388
Packit Service 0af388
	assert_int_equal(strlen(cfg2), strlen(cfg1));
Packit Service 0af388
	assert_string_equal(cfg2, cfg1);
Packit Service 0af388
	free(cfg1);
Packit Service 0af388
	free(cfg2);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Run hwt->test three times; once with the constructed configuration,
Packit Service 0af388
 * once after re-reading the full dumped configuration, and once with the
Packit Service 0af388
 * dumped local configuration.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: test passes every time.
Packit Service 0af388
 */
Packit Service 0af388
static void test_driver(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct hwt_state *hwt;
Packit Service 0af388
Packit Service 0af388
	hwt = CHECK_STATE(state);
Packit Service 0af388
	_conf = LOAD_CONFIG(hwt);
Packit Service 0af388
	hwt->test(hwt);
Packit Service 0af388
Packit Service 0af388
	replicate_config(hwt, false);
Packit Service 0af388
	reset_vecs(hwt->vecs);
Packit Service 0af388
	hwt->test(hwt);
Packit Service 0af388
Packit Service 0af388
	replicate_config(hwt, true);
Packit Service 0af388
	reset_vecs(hwt->vecs);
Packit Service 0af388
	hwt->test(hwt);
Packit Service 0af388
Packit Service 0af388
	reset_vecs(hwt->vecs);
Packit Service 0af388
	FREE_CONFIG(_conf);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Sanity check for the test itself, because defaults may be changed
Packit Service 0af388
 * in libmultipath.
Packit Service 0af388
 *
Packit Service 0af388
 * Our checking for match or non-match relies on the defaults being
Packit Service 0af388
 * different from what our device sections contain.
Packit Service 0af388
 */
Packit Service 0af388
static void test_sanity_globals(void **state)
Packit Service 0af388
{
Packit Service 0af388
	assert_string_not_equal(prio_emc.value, DEFAULT_PRIO);
Packit Service 0af388
	assert_string_not_equal(prio_hds.value, DEFAULT_PRIO);
Packit Service 0af388
	assert_string_not_equal(chk_hp.value, DEFAULT_CHECKER);
Packit Service 0af388
	assert_int_not_equal(MULTIBUS, DEFAULT_PGPOLICY);
Packit Service 0af388
	assert_int_not_equal(NO_PATH_RETRY_QUEUE, DEFAULT_NO_PATH_RETRY);
Packit Service 0af388
	assert_int_not_equal(atoi(minio_99.value), DEFAULT_MINIO_RQ);
Packit Service 0af388
	assert_int_not_equal(atoi(npr_37.value), DEFAULT_NO_PATH_RETRY);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Regression test for internal hwtable. NVME is an example of two entries
Packit Service 0af388
 * in the built-in hwtable, one if which matches a subset of the other.
Packit Service 0af388
 */
Packit Service 0af388
static void test_internal_nvme(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
	struct multipath *mp;
Packit Service 0af388
Packit Service 0af388
	/*
Packit Service 0af388
	 * Generic NVMe: expect defaults for pgpolicy and no_path_retry
Packit Service 0af388
	 */
Packit Service 0af388
	pp = mock_path("NVME", "NoName");
Packit Service 0af388
	mp = mock_multipath(pp);
Packit Service 0af388
	assert_ptr_not_equal(mp, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), NONE);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, DEFAULT_NVME_UID_ATTRIBUTE);
Packit Service 0af388
	assert_int_equal(mp->pgpolicy, DEFAULT_PGPOLICY);
Packit Service 0af388
	assert_int_equal(mp->no_path_retry, DEFAULT_NO_PATH_RETRY);
Packit Service 0af388
	assert_int_equal(mp->retain_hwhandler, RETAIN_HWHANDLER_OFF);
Packit Service 0af388
Packit Service 0af388
	/*
Packit Service 0af388
	 * NetApp NVMe: expect special values for pgpolicy and no_path_retry
Packit Service 0af388
	 */
Packit Service 0af388
	pp = mock_path_wwid("NVME", "NetApp ONTAP Controller",
Packit Service 0af388
			    default_wwid_1);
Packit Service 0af388
	mp = mock_multipath(pp);
Packit Service 0af388
	assert_ptr_not_equal(mp, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), NONE);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, "ID_WWN");
Packit Service 0af388
	assert_int_equal(mp->pgpolicy, MULTIBUS);
Packit Service 0af388
	assert_int_equal(mp->no_path_retry, NO_PATH_RETRY_QUEUE);
Packit Service 0af388
	assert_int_equal(mp->retain_hwhandler, RETAIN_HWHANDLER_OFF);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_internal_nvme(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_EMPTY_CONF(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_internal_nvme);
Packit Service 0af388
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Device section with a simple entry qith double quotes ('foo:"bar"')
Packit Service 0af388
 */
Packit Service 0af388
static void test_quoted_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:"bar" matches */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baq.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_quoted_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kv[] = { vnd_foo, prd_baqq, prio_emc };
Packit Service 0af388
Packit Service 0af388
	WRITE_ONE_DEVICE(hwt, kv);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_quoted_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Device section with a single simple entry ("foo:bar")
Packit Service 0af388
 */
Packit Service 0af388
static void test_string_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
Packit Service 0af388
	/* boo:bar doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_string_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kv[] = { vnd_foo, prd_bar, prio_emc };
Packit Service 0af388
Packit Service 0af388
	WRITE_ONE_DEVICE(hwt, kv);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_string_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Device section with a broken entry (no product)
Packit Service 0af388
 * It should be ignored.
Packit Service 0af388
 */
Packit Service 0af388
static void test_broken_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:bar doesn't match, as hwentry is ignored */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
Packit Service 0af388
	/* boo:bar doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_broken_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kv[] = { vnd_foo, prio_emc };
Packit Service 0af388
Packit Service 0af388
	WRITE_ONE_DEVICE(hwt, kv);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_broken_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Like test_broken_hwe, but in config_dir file.
Packit Service 0af388
 */
Packit Service 0af388
static int setup_broken_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kv[] = { vnd_foo, prio_emc };
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "devices");
Packit Service 0af388
	write_device(hwt->conf_dir_file[0], ARRAY_SIZE(kv), kv);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	hwt->test = test_broken_hwe;
Packit Service 0af388
	hwt->test_name = "test_broken_hwe_dir";
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Device section with a single regex entry ("^.foo:(bar|baz|ba\.)$")
Packit Service 0af388
 */
Packit Service 0af388
static void test_regex_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:baz matches */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
Packit Service 0af388
	/* boo:baz matches */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:BAR doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, "BAR");
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
Packit Service 0af388
	/* bboo:bar doesn't match */
Packit Service 0af388
	pp = mock_path("bboo", prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_regex_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kv[] = { vnd_t_oo, prd_ba_s, prio_emc };
Packit Service 0af388
Packit Service 0af388
	WRITE_ONE_DEVICE(hwt, kv);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_regex_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two device entries, kv1 is a regex match ("^.foo:(bar|baz|ba\.)$"),
Packit Service 0af388
 * kv2 a string match (foo:bar) which matches a subset of the regex.
Packit Service 0af388
 * Both are added to the main config file.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: Devices matching both get properties from both, kv2 taking
Packit Service 0af388
 * precedence. Devices matching kv1 only just get props from kv1.
Packit Service 0af388
 */
Packit Service 0af388
static void test_regex_string_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* boo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* .oo:ba. matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd__oo.value, prd_ba_.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* .foo:(bar|baz|ba\.) doesn't match */
Packit Service 0af388
	pp = mock_path(vnd__oo.value, prd_ba_s.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches kv2 and kv1 */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_regex_string_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kv1[] = { vnd_t_oo, prd_ba_s, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_regex_string_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two device entries, kv1 is a regex match ("^.foo:(bar|baz|ba\.)$"),
Packit Service 0af388
 * kv2 a string match (foo:bar) which matches a subset of the regex.
Packit Service 0af388
 * kv1 is added to the main config file, kv2 to a config_dir file.
Packit Service 0af388
 * This case is more important as you may think, because it's equivalent
Packit Service 0af388
 * to kv1 being in the built-in hwtable and kv2 in multipath.conf.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: Devices matching kv2 (and thus, both) get properties
Packit Service 0af388
 * from both, kv2 taking precedence.
Packit Service 0af388
 * Devices matching kv1 only just get props from kv1.
Packit Service 0af388
 */
Packit Service 0af388
static void test_regex_string_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* boo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* .oo:ba. matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd__oo.value, prd_ba_.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* .oo:(bar|baz|ba\.)$ doesn't match */
Packit Service 0af388
	pp = mock_path(vnd__oo.value, prd_ba_s.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches kv2 */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	/* Later match takes prio */
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_regex_string_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_t_oo, prd_ba_s, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_regex_string_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Three device entries, kv1 is a regex match and kv2 and kv3 string
Packit Service 0af388
 * matches, where kv3 is a substring of kv2. All in different config
Packit Service 0af388
 * files.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: Devices matching kv3 get props from all, devices matching
Packit Service 0af388
 * kv2 from kv2 and kv1, and devices matching kv1 only just from kv1.
Packit Service 0af388
 */
Packit Service 0af388
static void test_regex_2_strings_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* boo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches kv2 and kv1 */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, uid_baz.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:barz matches kv3 and kv2 and kv1 */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_barz.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_rdac.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_regex_2_strings_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_ba_, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, uid_baz };
Packit Service 0af388
	const struct key_value kv3[] = { vnd_foo, prd_barz,
Packit Service 0af388
					 prio_rdac, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "devices");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_device(hwt->conf_dir_file[0], ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv3), kv3);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_regex_2_strings_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Like test_regex_string_hwe_dir, but the order of kv1 and kv2 is exchanged.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: Devices matching kv1 (and thus, both) get properties
Packit Service 0af388
 * from both, kv1 taking precedence.
Packit Service 0af388
 * Devices matching kv1 only just get props from kv1.
Packit Service 0af388
 */
Packit Service 0af388
static void test_string_regex_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches kv2 and kv1 */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* boo:baz matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd_boo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* .oo:ba. matches kv1 */
Packit Service 0af388
	pp = mock_path(vnd__oo.value, prd_ba_.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* .oo:(bar|baz|ba\.)$ doesn't match */
Packit Service 0af388
	pp = mock_path(vnd__oo.value, prd_ba_s.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_string_regex_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_t_oo, prd_ba_s, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv2, kv1);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_string_regex_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, trival regex ("string").
Packit Service 0af388
 * Both are added to the main config file.
Packit Service 0af388
 * These entries are NOT merged.
Packit Service 0af388
 * This could happen in a large multipath.conf file.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_ident_strings_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_strings_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_strings_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, trival regex ("string").
Packit Service 0af388
 * Both are added to an extra config file.
Packit Service 0af388
 * This could happen in a large multipath.conf file.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_ident_strings_both_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_strings_both_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "devices");
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_strings_both_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, trival regex ("string").
Packit Service 0af388
 * Both are added to an extra config file.
Packit Service 0af388
 * An empty entry kv0 with the same string exists in the main config file.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_ident_strings_both_dir_w_prev(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_strings_both_dir_w_prev(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	const struct key_value kv0[] = { vnd_foo, prd_bar };
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "devices");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv0), kv0);
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_strings_both_dir_w_prev);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, trival regex ("string").
Packit Service 0af388
 * kv1 is added to the main config file, kv2 to a config_dir file.
Packit Service 0af388
 * These entries are merged.
Packit Service 0af388
 * This case is more important as you may think, because it's equivalent
Packit Service 0af388
 * to kv1 being in the built-in hwtable and kv2 in multipath.conf.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_ident_strings_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_strings_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_strings_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Like test_2_ident_strings_hwe_dir, but this time the config_dir file
Packit Service 0af388
 * contains an additional, empty entry (kv0).
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from kv1 and kv2, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_3_ident_strings_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_3_ident_strings_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv0[] = { vnd_foo, prd_bar };
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "devices");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv0), kv0);
Packit Service 0af388
	write_device(hwt->conf_dir_file[1], ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_3_ident_strings_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, non-trival regex that matches
Packit Service 0af388
 * itself (string ".oo" matches regex ".oo").
Packit Service 0af388
 * kv1 is added to the main config file, kv2 to a config_dir file.
Packit Service 0af388
 * This case is more important as you may think, because it's equivalent
Packit Service 0af388
 * to kv1 being in the built-in hwtable and kv2 in multipath.conf.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_ident_self_matching_re_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_self_matching_re_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd__oo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd__oo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_self_matching_re_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, non-trival regex that matches
Packit Service 0af388
 * itself (string ".oo" matches regex ".oo").
Packit Service 0af388
 * kv1 and kv2 are added to the main config file.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_ident_self_matching_re_hwe(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_self_matching_re_hwe(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd__oo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd__oo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_self_matching_re_hwe);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two identical device entries kv1 and kv2, non-trival regex that doesn't
Packit Service 0af388
 * match itself (string "^.oo" doesn't match regex "^.oo").
Packit Service 0af388
 * kv1 is added to the main config file, kv2 to a config_dir file.
Packit Service 0af388
 * This case is more important as you may think, see above.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get props from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void
Packit Service 0af388
test_2_ident_not_self_matching_re_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:baz doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches both */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_bar.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_ident_not_self_matching_re_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_t_oo, prd_bar, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_t_oo, prd_bar, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_ident_not_self_matching_re_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two different non-trivial regexes kv1, kv2. The 1st one matches the 2nd, but
Packit Service 0af388
 * it doesn't match all possible strings matching the second.
Packit Service 0af388
 * ("ba[zy]" matches regex "ba[[rxy]", but "baz" does not).
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: Devices matching both regexes get properties from both, kv2
Packit Service 0af388
 * taking precedence. Devices matching just one regex get properties from
Packit Service 0af388
 * that one regex only.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_matching_res_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:bar matches k1 only */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:bay matches k1 and k2 */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, "bay", USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
Packit Service 0af388
	/* foo:baz matches k2 only. */
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_baz.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_matching_res_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_barx, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bazy, prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_matching_res_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Two different non-trivial regexes which match the same set of strings.
Packit Service 0af388
 * But they don't match each other.
Packit Service 0af388
 * "baz" matches both regex "ba[zy]" and "ba(z|y)"
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: matching devices get properties from both, kv2 taking precedence.
Packit Service 0af388
 */
Packit Service 0af388
static void test_2_nonmatching_res_hwe_dir(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
Packit Service 0af388
	/* foo:bar doesn't match */
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
Packit Service 0af388
	TEST_PROP(pp->getuid, NULL);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), DEFAULT_CHECKER);
Packit Service 0af388
Packit Service 0af388
	pp = mock_path_flags(vnd_foo.value, prd_baz.value, USE_GETUID);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_hds.value);
Packit Service 0af388
	TEST_PROP(pp->getuid, gui_foo.value);
Packit Service 0af388
	TEST_PROP(checker_name(&pp->checker), chk_hp.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_2_nonmatching_res_hwe_dir(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bazy, prio_emc, chk_hp };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bazy1,
Packit Service 0af388
					 prio_hds, gui_foo };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES_W_DIR(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_2_nonmatching_res_hwe_dir);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Simple blacklist test.
Packit Service 0af388
 *
Packit Service 0af388
 * NOTE: test failures in blacklisting tests will manifest as cmocka errors
Packit Service 0af388
 * "Could not get value to mock function XYZ", because pathinfo() takes
Packit Service 0af388
 * different code paths for blacklisted devices.
Packit Service 0af388
 */
Packit Service 0af388
static void test_blacklist(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_bar.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path(vnd_foo.value, prd_baz.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_blacklist(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "blacklist");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_blacklist);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Simple blacklist test with regex and exception
Packit Service 0af388
 */
Packit Service 0af388
static void test_blacklist_regex(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_baz.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path(vnd_foo.value, prd_bam.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_blacklist_regex(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_ba_s };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	hwt = CHECK_STATE(state);
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "blacklist");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	begin_section_all(hwt, "blacklist_exceptions");
Packit Service 0af388
	write_device(hwt->conf_dir_file[0], ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_blacklist_regex);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Simple blacklist test with regex and exception
Packit Service 0af388
 * config file order inverted wrt test_blacklist_regex
Packit Service 0af388
 */
Packit Service 0af388
static int setup_blacklist_regex_inv(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_ba_s };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bar };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "blacklist");
Packit Service 0af388
	write_device(hwt->conf_dir_file[0], ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	begin_section_all(hwt, "blacklist_exceptions");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_blacklist_regex);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Simple blacklist test with regex and exception
Packit Service 0af388
 * config file order inverted wrt test_blacklist_regex
Packit Service 0af388
 */
Packit Service 0af388
static void test_blacklist_regex_matching(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_bar.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_baz.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path(vnd_foo.value, prd_bam.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_blacklist_regex_matching(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_barx };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_bazy };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "blacklist");
Packit Service 0af388
	write_device(hwt->config_file, ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_device(hwt->conf_dir_file[0], ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_blacklist_regex_matching);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Test for blacklisting by WWID
Packit Service 0af388
 *
Packit Service 0af388
 * Note that default_wwid is a substring of default_wwid_1. Because
Packit Service 0af388
 * matching is done by regex, both paths are blacklisted.
Packit Service 0af388
 */
Packit Service 0af388
static void test_blacklist_wwid(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_bar.value, BL_BY_WWID);
Packit Service 0af388
	mock_path_wwid_flags(vnd_foo.value, prd_baz.value, default_wwid_1,
Packit Service 0af388
			     BL_BY_WWID);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_blacklist_wwid(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv[] = { wwid_test };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	write_section(hwt->config_file, "blacklist", ARRAY_SIZE(kv), kv);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_blacklist_wwid);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Test for blacklisting by WWID
Packit Service 0af388
 *
Packit Service 0af388
 * Here the blacklist contains only default_wwid_1. Thus the path
Packit Service 0af388
 * with default_wwid is NOT blacklisted.
Packit Service 0af388
 */
Packit Service 0af388
static void test_blacklist_wwid_1(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	mock_path_wwid_flags(vnd_foo.value, prd_baz.value, default_wwid_1,
Packit Service 0af388
			     BL_BY_WWID);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_blacklist_wwid_1(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv[] = { { _wwid, default_wwid_1 }, };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	write_section(hwt->config_file, "blacklist", ARRAY_SIZE(kv), kv);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_blacklist_wwid_1);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Test for product_blacklist. Two entries blacklisting each other.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: Both are blacklisted.
Packit Service 0af388
 */
Packit Service 0af388
static void test_product_blacklist(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_baz.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_bar.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path(vnd_foo.value, prd_bam.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_product_blacklist(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, bl_baz };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_baz, bl_bar };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_product_blacklist);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Test for product_blacklist. The second regex "matches" the first.
Packit Service 0af388
 * This is a pathological example.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: "foo:bar", "foo:baz" are blacklisted.
Packit Service 0af388
 */
Packit Service 0af388
static void test_product_blacklist_matching(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_bar.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path_flags(vnd_foo.value, prd_baz.value, BL_BY_DEVICE);
Packit Service 0af388
	mock_path(vnd_foo.value, prd_bam.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_product_blacklist_matching(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { vnd_foo, prd_bar, bl_barx };
Packit Service 0af388
	const struct key_value kv2[] = { vnd_foo, prd_baz, bl_bazy };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_TWO_DEVICES(hwt, kv1, kv2);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_product_blacklist_matching);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Basic test for multipath-based configuration.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: properties, including pp->prio, are taken from multipath
Packit Service 0af388
 * section.
Packit Service 0af388
 */
Packit Service 0af388
static void test_multipath_config(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
	struct multipath *mp;
Packit Service 0af388
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	mp = mock_multipath(pp);
Packit Service 0af388
	assert_ptr_not_equal(mp->mpe, NULL);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_rdac.value);
Packit Service 0af388
	assert_int_equal(mp->minio, atoi(minio_99.value));
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, uid_baz.value);
Packit Service 0af388
Packit Service 0af388
	/* test different wwid */
Packit Service 0af388
	pp = mock_path_wwid(vnd_foo.value, prd_bar.value, default_wwid_1);
Packit Service 0af388
	mp = mock_multipath(pp);
Packit Service 0af388
	// assert_ptr_equal(mp->mpe, NULL);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_emc.value);
Packit Service 0af388
	assert_int_equal(mp->minio, DEFAULT_MINIO_RQ);
Packit Service 0af388
	TEST_PROP(pp->uid_attribute, uid_baz.value);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_multipath_config(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
	const struct key_value kvm[] = { wwid_test, prio_rdac, minio_99 };
Packit Service 0af388
	const struct key_value kvp[] = { vnd_foo, prd_bar, prio_emc, uid_baz };
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "devices");
Packit Service 0af388
	write_section(hwt->conf_dir_file[0], "device", ARRAY_SIZE(kvp), kvp);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	begin_section_all(hwt, "multipaths");
Packit Service 0af388
	write_section(hwt->config_file, "multipath", ARRAY_SIZE(kvm), kvm);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_multipath_config);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Basic test for multipath-based configuration. Two sections for the same wwid.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: properties are taken from both multipath sections, later taking
Packit Service 0af388
 * precedence
Packit Service 0af388
 */
Packit Service 0af388
static void test_multipath_config_2(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
	struct multipath *mp;
Packit Service 0af388
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	mp = mock_multipath(pp);
Packit Service 0af388
	assert_ptr_not_equal(mp, NULL);
Packit Service 0af388
	assert_ptr_not_equal(mp->mpe, NULL);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_rdac.value);
Packit Service 0af388
	assert_int_equal(mp->minio, atoi(minio_99.value));
Packit Service 0af388
	assert_int_equal(mp->no_path_retry, atoi(npr_37.value));
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_multipath_config_2(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { wwid_test, prio_rdac, npr_queue };
Packit Service 0af388
	const struct key_value kv2[] = { wwid_test, minio_99, npr_37 };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "multipaths");
Packit Service 0af388
	write_section(hwt->config_file, "multipath", ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_section(hwt->conf_dir_file[1], "multipath", ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_multipath_config_2);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Same as test_multipath_config_2, both entries in the same config file.
Packit Service 0af388
 *
Packit Service 0af388
 * Expected: properties are taken from both multipath sections.
Packit Service 0af388
 */
Packit Service 0af388
static void test_multipath_config_3(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	struct path *pp;
Packit Service 0af388
	struct multipath *mp;
Packit Service 0af388
Packit Service 0af388
	pp = mock_path(vnd_foo.value, prd_bar.value);
Packit Service 0af388
	mp = mock_multipath(pp);
Packit Service 0af388
	assert_ptr_not_equal(mp, NULL);
Packit Service 0af388
	assert_ptr_not_equal(mp->mpe, NULL);
Packit Service 0af388
	TEST_PROP(prio_name(&pp->prio), prio_rdac.value);
Packit Service 0af388
	assert_int_equal(mp->minio, atoi(minio_99.value));
Packit Service 0af388
	assert_int_equal(mp->no_path_retry, atoi(npr_37.value));
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_multipath_config_3(void **state)
Packit Service 0af388
{
Packit Service 0af388
	const struct key_value kv1[] = { wwid_test, prio_rdac, npr_queue };
Packit Service 0af388
	const struct key_value kv2[] = { wwid_test, minio_99, npr_37 };
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	begin_config(hwt);
Packit Service 0af388
	begin_section_all(hwt, "multipaths");
Packit Service 0af388
	write_section(hwt->config_file, "multipath", ARRAY_SIZE(kv1), kv1);
Packit Service 0af388
	write_section(hwt->config_file, "multipath", ARRAY_SIZE(kv2), kv2);
Packit Service 0af388
	end_section_all(hwt);
Packit Service 0af388
	finish_config(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_multipath_config_3);
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Test for device with "hidden" attribute
Packit Service 0af388
 */
Packit Service 0af388
static void test_hidden(const struct hwt_state *hwt)
Packit Service 0af388
{
Packit Service 0af388
	mock_path_flags("NVME", "NoName", DEV_HIDDEN|BL_MASK);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
static int setup_hidden(void **state)
Packit Service 0af388
{
Packit Service 0af388
	struct hwt_state *hwt = CHECK_STATE(state);
Packit Service 0af388
Packit Service 0af388
	WRITE_EMPTY_CONF(hwt);
Packit Service 0af388
	SET_TEST_FUNC(hwt, test_hidden);
Packit Service 0af388
Packit Service 0af388
	return 0;
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
/*
Packit Service 0af388
 * Create wrapper functions around test_driver() to avoid that cmocka
Packit Service 0af388
 * always uses the same test name. That makes it easier to read test results.
Packit Service 0af388
 */
Packit Service 0af388
Packit Service 0af388
#define define_test(x)				\
Packit Service 0af388
	static void run_##x(void **state)	\
Packit Service 0af388
	{					\
Packit Service 0af388
		return test_driver(state);	\
Packit Service 0af388
	}
Packit Service 0af388
Packit Service 0af388
define_test(string_hwe)
Packit Service 0af388
define_test(broken_hwe)
Packit Service 0af388
define_test(broken_hwe_dir)
Packit Service 0af388
define_test(quoted_hwe)
Packit Service 0af388
define_test(internal_nvme)
Packit Service 0af388
define_test(regex_hwe)
Packit Service 0af388
define_test(regex_string_hwe)
Packit Service 0af388
define_test(regex_string_hwe_dir)
Packit Service 0af388
define_test(regex_2_strings_hwe_dir)
Packit Service 0af388
define_test(string_regex_hwe_dir)
Packit Service 0af388
define_test(2_ident_strings_hwe)
Packit Service 0af388
define_test(2_ident_strings_both_dir)
Packit Service 0af388
define_test(2_ident_strings_both_dir_w_prev)
Packit Service 0af388
define_test(2_ident_strings_hwe_dir)
Packit Service 0af388
define_test(3_ident_strings_hwe_dir)
Packit Service 0af388
define_test(2_ident_self_matching_re_hwe_dir)
Packit Service 0af388
define_test(2_ident_self_matching_re_hwe)
Packit Service 0af388
define_test(2_ident_not_self_matching_re_hwe_dir)
Packit Service 0af388
define_test(2_matching_res_hwe_dir)
Packit Service 0af388
define_test(2_nonmatching_res_hwe_dir)
Packit Service 0af388
define_test(blacklist)
Packit Service 0af388
define_test(blacklist_wwid)
Packit Service 0af388
define_test(blacklist_wwid_1)
Packit Service 0af388
define_test(blacklist_regex)
Packit Service 0af388
define_test(blacklist_regex_inv)
Packit Service 0af388
define_test(blacklist_regex_matching)
Packit Service 0af388
define_test(product_blacklist)
Packit Service 0af388
define_test(product_blacklist_matching)
Packit Service 0af388
define_test(multipath_config)
Packit Service 0af388
define_test(multipath_config_2)
Packit Service 0af388
define_test(multipath_config_3)
Packit Service 0af388
define_test(hidden)
Packit Service 0af388
Packit Service 0af388
#define test_entry(x) \
Packit Service 0af388
	cmocka_unit_test_setup(run_##x, setup_##x)
Packit Service 0af388
Packit Service 0af388
static int test_hwtable(void)
Packit Service 0af388
{
Packit Service 0af388
	const struct CMUnitTest tests[] = {
Packit Service 0af388
		cmocka_unit_test(test_sanity_globals),
Packit Service 0af388
		test_entry(internal_nvme),
Packit Service 0af388
		test_entry(string_hwe),
Packit Service 0af388
		test_entry(broken_hwe),
Packit Service 0af388
		test_entry(broken_hwe_dir),
Packit Service 0af388
		test_entry(quoted_hwe),
Packit Service 0af388
		test_entry(regex_hwe),
Packit Service 0af388
		test_entry(regex_string_hwe),
Packit Service 0af388
		test_entry(regex_string_hwe_dir),
Packit Service 0af388
		test_entry(regex_2_strings_hwe_dir),
Packit Service 0af388
		test_entry(string_regex_hwe_dir),
Packit Service 0af388
		test_entry(2_ident_strings_hwe),
Packit Service 0af388
		test_entry(2_ident_strings_both_dir),
Packit Service 0af388
		test_entry(2_ident_strings_both_dir_w_prev),
Packit Service 0af388
		test_entry(2_ident_strings_hwe_dir),
Packit Service 0af388
		test_entry(3_ident_strings_hwe_dir),
Packit Service 0af388
		test_entry(2_ident_self_matching_re_hwe_dir),
Packit Service 0af388
		test_entry(2_ident_self_matching_re_hwe),
Packit Service 0af388
		test_entry(2_ident_not_self_matching_re_hwe_dir),
Packit Service 0af388
		test_entry(2_matching_res_hwe_dir),
Packit Service 0af388
		test_entry(2_nonmatching_res_hwe_dir),
Packit Service 0af388
		test_entry(blacklist),
Packit Service 0af388
		test_entry(blacklist_wwid),
Packit Service 0af388
		test_entry(blacklist_wwid_1),
Packit Service 0af388
		test_entry(blacklist_regex),
Packit Service 0af388
		test_entry(blacklist_regex_inv),
Packit Service 0af388
		test_entry(blacklist_regex_matching),
Packit Service 0af388
		test_entry(product_blacklist),
Packit Service 0af388
		test_entry(product_blacklist_matching),
Packit Service 0af388
		test_entry(multipath_config),
Packit Service 0af388
		test_entry(multipath_config_2),
Packit Service 0af388
		test_entry(multipath_config_3),
Packit Service 0af388
		test_entry(hidden),
Packit Service 0af388
	};
Packit Service 0af388
Packit Service 0af388
	return cmocka_run_group_tests(tests, setup, teardown);
Packit Service 0af388
}
Packit Service 0af388
Packit Service 0af388
int main(void)
Packit Service 0af388
{
Packit Service 0af388
	int ret = 0;
Packit Service 0af388
Packit Service 0af388
	ret += test_hwtable();
Packit Service 0af388
	return ret;
Packit Service 0af388
}