diff --git a/Makefile.inc b/Makefile.inc
index e05f3a91..13587a9f 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -66,6 +66,7 @@ libdir		= $(prefix)/$(LIB)/multipath
 unitdir		= $(prefix)/$(SYSTEMDPATH)/systemd/system
 mpathpersistdir	= $(TOPDIR)/libmpathpersist
 mpathcmddir	= $(TOPDIR)/libmpathcmd
+mpathvaliddir	= $(TOPDIR)/libmpathvalid
 thirdpartydir	= $(TOPDIR)/third-party
 libdmmpdir	= $(TOPDIR)/libdmmp
 nvmedir		= $(TOPDIR)/libmultipath/nvme
diff --git a/tests/Makefile b/tests/Makefile
index 73ff0f5c..73ec0702 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \
 LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka
 
 TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
-	 alias directio valid devt
+	 alias directio valid devt mpathvalid
 
 .SILENT: $(TESTS:%=%.o)
 .PRECIOUS: $(TESTS:%=%-test)
@@ -30,6 +30,7 @@ endif
 ifneq ($(DIO_TEST_DEV),)
 directio-test_FLAGS := -DDIO_TEST_DEV=\"$(DIO_TEST_DEV)\"
 endif
+mpathvalid-test_FLAGS := -I$(mpathvaliddir)
 
 # test-specific linker flags
 # XYZ-test_TESTDEPS: test libraries containing __wrap_xyz functions
@@ -55,6 +56,8 @@ alias-test_LIBDEPS := -lpthread -ldl
 valid-test_OBJDEPS := ../libmultipath/valid.o
 valid-test_LIBDEPS := -ludev -lpthread -ldl
 devt-test_LIBDEPS := -ludev
+mpathvalid-test_LIBDEPS := -ludev -lpthread -ldl
+mpathvalid-test_OBJDEPS := ../libmpathvalid/mpath_valid.o
 ifneq ($(DIO_TEST_DEV),)
 directio-test_LIBDEPS := -laio
 endif
diff --git a/tests/mpathvalid.c b/tests/mpathvalid.c
new file mode 100644
index 00000000..5ffabb9d
--- /dev/null
+++ b/tests/mpathvalid.c
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2020 Benjamin Marzinski, Red Hat
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libudev.h>
+#include <cmocka.h>
+#include "structs.h"
+#include "config.h"
+#include "mpath_valid.h"
+#include "util.h"
+#include "debug.h"
+
+const char *test_dev = "test_name";
+#define TEST_WWID "WWID_123"
+#define CONF_TEMPLATE "mpathvalid-testconf-XXXXXXXX"
+char conf_name[] = CONF_TEMPLATE;
+bool initialized;
+
+#if 0
+static int mode_to_findmp(unsigned int mode)
+{
+	switch (mode) {
+	case MPATH_SMART:
+		return FIND_MULTIPATHS_SMART;
+	case MPATH_GREEDY:
+		return FIND_MULTIPATHS_GREEDY;
+	case MPATH_STRICT:
+		return FIND_MULTIPATHS_STRICT;
+	}
+	fail_msg("invalid mode: %u", mode);
+	return FIND_MULTIPATHS_UNDEF;
+}
+#endif
+
+static unsigned int findmp_to_mode(int findmp)
+{
+	switch (findmp) {
+	case FIND_MULTIPATHS_SMART:
+		return MPATH_SMART;
+	case FIND_MULTIPATHS_GREEDY:
+		return MPATH_GREEDY;
+	case FIND_MULTIPATHS_STRICT:
+	case FIND_MULTIPATHS_OFF:
+	case FIND_MULTIPATHS_ON:
+		return MPATH_STRICT;
+	}
+	fail_msg("invalid find_multipaths value: %d", findmp);
+	return MPATH_DEFAULT;
+}
+
+int __wrap_is_path_valid(const char *name, struct config *conf, struct path *pp,
+			 bool check_multipathd)
+{
+	int r = mock_type(int);
+	int findmp = mock_type(int);
+
+	assert_ptr_equal(name, test_dev);
+	assert_ptr_not_equal(conf, NULL);
+	assert_ptr_not_equal(pp, NULL);
+	assert_true(check_multipathd);
+
+	assert_int_equal(findmp, conf->find_multipaths);	
+	if (r == MPATH_IS_ERROR || r == MPATH_IS_NOT_VALID)
+		return r;
+	
+	strlcpy(pp->wwid, mock_ptr_type(char *), WWID_SIZE);
+	return r;
+}
+
+int __wrap_libmultipath_init(void)
+{
+	int r = mock_type(int);
+
+	assert_false(initialized);
+	if (r != 0)
+		return r;
+	initialized = true;
+	return 0;
+}
+
+void __wrap_libmultipath_exit(void)
+{
+	assert_true(initialized);
+	initialized = false;
+}
+
+int __wrap_dm_prereq(unsigned int *v)
+{
+	assert_ptr_not_equal(v, NULL);
+	return mock_type(int);
+}
+
+int __real_init_config(const char *file);
+
+int __wrap_init_config(const char *file)
+{
+	int r = mock_type(int);
+	struct config *conf;
+
+	assert_ptr_equal(file, DEFAULT_CONFIGFILE);
+	if (r != 0)
+		return r;
+
+	assert_string_not_equal(conf_name, CONF_TEMPLATE);
+	r = __real_init_config(conf_name);
+	conf = get_multipath_config();
+	assert_ptr_not_equal(conf, NULL);
+	assert_int_equal(conf->find_multipaths, mock_type(int));
+	return 0;
+}
+
+static const char * const find_multipaths_optvals[] = {
+        [FIND_MULTIPATHS_OFF] = "off",
+        [FIND_MULTIPATHS_ON] = "on",
+        [FIND_MULTIPATHS_STRICT] = "strict",
+        [FIND_MULTIPATHS_GREEDY] = "greedy",
+        [FIND_MULTIPATHS_SMART] = "smart",
+};
+
+void make_config_file(int findmp)
+{
+	int r, fd;
+	char buf[64];
+
+	assert_true(findmp > FIND_MULTIPATHS_UNDEF &&
+		    findmp < __FIND_MULTIPATHS_LAST);
+
+	r = snprintf(buf, sizeof(buf), "defaults {\nfind_multipaths %s\n}\n",
+		     find_multipaths_optvals[findmp]);
+	assert_true(r > 0 && (long unsigned int)r < sizeof(buf));
+
+	memcpy(conf_name, CONF_TEMPLATE, sizeof(conf_name));
+	fd = mkstemp(conf_name);
+	assert_true(fd >= 0);
+	assert_int_equal(safe_write(fd, buf, r), 0);
+	assert_int_equal(close(fd), 0);
+}
+
+int setup(void **state)
+{
+	initialized = false;
+	udev = udev_new();
+	if (udev == NULL)
+		return -1;
+	return 0;
+}
+
+int teardown(void **state)
+{
+	struct config *conf;
+	conf = get_multipath_config();
+	put_multipath_config(conf);
+	if (conf)
+		uninit_config();
+	if (strcmp(conf_name, CONF_TEMPLATE) != 0)
+		unlink(conf_name);
+	udev_unref(udev);
+	udev = NULL;
+	return 0;
+}
+
+static void check_config(bool valid_config)
+{
+	struct config *conf;
+
+	conf = get_multipath_config();
+	put_multipath_config(conf);
+	if (valid_config)
+		assert_ptr_not_equal(conf, NULL);
+}
+
+/* libmultipath_init fails */
+static void test_mpathvalid_init_bad1(void **state)
+{
+	will_return(__wrap_libmultipath_init, 1);
+	assert_int_equal(mpathvalid_init(MPATH_LOG_PRIO_DEBUG,
+					 MPATH_LOG_STDERR), -1);
+	assert_false(initialized);
+	check_config(false);
+}
+
+/* init_config fails */
+static void test_mpathvalid_init_bad2(void **state)
+{
+	will_return(__wrap_libmultipath_init, 0);
+	will_return(__wrap_init_config, 1);
+	assert_int_equal(mpathvalid_init(MPATH_LOG_PRIO_ERR,
+					 MPATH_LOG_STDERR_TIMESTAMP), -1);
+	assert_false(initialized);
+	check_config(false);
+}
+
+/* dm_prereq fails */
+static void test_mpathvalid_init_bad3(void **state)
+{
+	make_config_file(FIND_MULTIPATHS_STRICT);
+	will_return(__wrap_libmultipath_init, 0);
+	will_return(__wrap_init_config, 0);
+	will_return(__wrap_init_config, FIND_MULTIPATHS_STRICT);
+	will_return(__wrap_dm_prereq, 1);
+	assert_int_equal(mpathvalid_init(MPATH_LOG_STDERR, MPATH_LOG_PRIO_ERR),
+			 -1);
+	assert_false(initialized);
+	check_config(false);
+}
+
+static void check_mpathvalid_init(int findmp, int prio, int log_style)
+{
+	make_config_file(findmp);
+	will_return(__wrap_libmultipath_init, 0);
+	will_return(__wrap_init_config, 0);
+	will_return(__wrap_init_config, findmp);
+	will_return(__wrap_dm_prereq, 0);
+	assert_int_equal(mpathvalid_init(prio, log_style), 0);	
+	assert_true(initialized);
+	check_config(true);
+	assert_int_equal(logsink, log_style);
+	assert_int_equal(libmp_verbosity, prio);
+	assert_int_equal(findmp_to_mode(findmp), mpathvalid_get_mode());
+}
+
+static void check_mpathvalid_exit(void)
+{
+	assert_int_equal(mpathvalid_exit(), 0);
+	assert_false(initialized);
+	check_config(false);
+}
+
+static void test_mpathvalid_init_good1(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR_TIMESTAMP);
+}
+
+static void test_mpathvalid_init_good2(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_STRICT, MPATH_LOG_PRIO_DEBUG,
+			      MPATH_LOG_STDERR);
+}
+
+static void test_mpathvalid_init_good3(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_NOLOG,
+			      MPATH_LOG_SYSLOG);
+}
+
+static void test_mpathvalid_exit(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	check_mpathvalid_exit();
+}
+
+/* fails if config hasn't been set */
+static void test_mpathvalid_get_mode_bad(void **state)
+{
+#if 1
+	assert_int_equal(mpathvalid_get_mode(), MPATH_MODE_ERROR);
+#else
+	assert_int_equal(mpathvalid_get_mode(), 1);
+#endif
+}
+
+/*fails if config hasn't been set */
+static void test_mpathvalid_reload_config_bad1(void **state)
+{
+#if 1
+	will_return(__wrap_init_config, 1);
+#endif
+	assert_int_equal(mpathvalid_reload_config(), -1);
+	check_config(false);
+}
+
+/* init_config fails */
+static void test_mpathvalid_reload_config_bad2(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_init_config, 1);
+	assert_int_equal(mpathvalid_reload_config(), -1);
+	check_config(false);
+	check_mpathvalid_exit();
+}
+
+static void check_mpathvalid_reload_config(int findmp)
+{
+	assert_string_not_equal(conf_name, CONF_TEMPLATE);
+	unlink(conf_name);
+	make_config_file(findmp);
+	will_return(__wrap_init_config, 0);
+	will_return(__wrap_init_config, findmp);
+	assert_int_equal(mpathvalid_reload_config(), 0);
+	check_config(true);
+	assert_int_equal(findmp_to_mode(findmp), mpathvalid_get_mode());
+}
+
+static void test_mpathvalid_reload_config_good(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	check_mpathvalid_reload_config(FIND_MULTIPATHS_ON);
+	check_mpathvalid_reload_config(FIND_MULTIPATHS_GREEDY);
+	check_mpathvalid_reload_config(FIND_MULTIPATHS_SMART);
+	check_mpathvalid_reload_config(FIND_MULTIPATHS_STRICT);
+	check_mpathvalid_exit();
+}
+
+/* NULL name */
+static void test_mpathvalid_is_path_bad1(void **state)
+{
+	assert_int_equal(mpathvalid_is_path(NULL, MPATH_STRICT, NULL, NULL, 0),
+			 MPATH_IS_ERROR);
+}
+
+/* bad mode */
+static void test_mpathvalid_is_path_bad2(void **state)
+{
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_MODE_ERROR, NULL,
+					    NULL, 0), MPATH_IS_ERROR);
+}
+
+/* NULL path_wwids and non-zero nr_paths */
+static void test_mpathvalid_is_path_bad3(void **state)
+{
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_MODE_ERROR, NULL,
+			 		    NULL, 1), MPATH_IS_ERROR);
+}
+
+/*fails if config hasn't been set */
+static void test_mpathvalid_is_path_bad4(void **state)
+{
+#if 0
+	will_return(__wrap_is_path_valid, MPATH_IS_ERROR);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_STRICT);
+#endif
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_STRICT, NULL,
+					    NULL, 0), MPATH_IS_ERROR);
+}
+
+/* is_path_valid fails */
+static void test_mpathvalid_is_path_bad5(void **state)
+{
+	check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_is_path_valid, MPATH_IS_ERROR);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_GREEDY);
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_GREEDY, NULL,
+					    NULL, 0), MPATH_IS_ERROR);
+	check_mpathvalid_exit();
+}
+
+static void test_mpathvalid_is_path_good1(void **state)
+{
+	char *wwid;
+	check_mpathvalid_init(FIND_MULTIPATHS_STRICT, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_is_path_valid, MPATH_IS_NOT_VALID);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_STRICT);
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid,
+			 		    NULL, 0), MPATH_IS_NOT_VALID);
+	assert_ptr_equal(wwid, NULL);
+	check_mpathvalid_exit();
+}
+
+static void test_mpathvalid_is_path_good2(void **state)
+{
+	const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" };
+	char *wwid;
+	check_mpathvalid_init(FIND_MULTIPATHS_ON, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_is_path_valid, MPATH_IS_VALID);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_ON);
+	will_return(__wrap_is_path_valid, TEST_WWID);
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid,
+					    wwids, 4), MPATH_IS_VALID);
+	assert_string_equal(wwid, TEST_WWID);
+}
+
+static void test_mpathvalid_is_path_good3(void **state)
+{
+	const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" };
+	char *wwid;
+	check_mpathvalid_init(FIND_MULTIPATHS_OFF, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_is_path_valid, MPATH_IS_VALID);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART);
+	will_return(__wrap_is_path_valid, TEST_WWID);
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_SMART, &wwid,
+					    wwids, 4), MPATH_IS_VALID);
+	assert_string_equal(wwid, TEST_WWID);
+}
+
+/* mabybe valid with no matching paths */
+static void test_mpathvalid_is_path_good4(void **state)
+{
+	const char *wwids[] = { "WWID_A", "WWID_B", "WWID_C", "WWID_D" };
+	char *wwid;
+	check_mpathvalid_init(FIND_MULTIPATHS_SMART, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_is_path_valid, MPATH_IS_MAYBE_VALID);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART);
+	will_return(__wrap_is_path_valid, TEST_WWID);
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid,
+					    wwids, 4), MPATH_IS_MAYBE_VALID);
+	assert_string_equal(wwid, TEST_WWID);
+}
+
+/* maybe valid with matching paths */
+static void test_mpathvalid_is_path_good5(void **state)
+{
+	const char *wwids[] = { "WWID_A", "WWID_B", TEST_WWID, "WWID_D" };
+	char *wwid;
+	check_mpathvalid_init(FIND_MULTIPATHS_SMART, MPATH_LOG_PRIO_ERR,
+			      MPATH_LOG_STDERR);
+	will_return(__wrap_is_path_valid, MPATH_IS_MAYBE_VALID);
+	will_return(__wrap_is_path_valid, FIND_MULTIPATHS_SMART);
+	will_return(__wrap_is_path_valid, TEST_WWID);
+	assert_int_equal(mpathvalid_is_path(test_dev, MPATH_DEFAULT, &wwid,
+					    wwids, 4), MPATH_IS_VALID);
+	assert_string_equal(wwid, TEST_WWID);
+}
+
+#define setup_test(name) \
+	cmocka_unit_test_setup_teardown(name, setup, teardown)
+
+int test_mpathvalid(void)
+{
+	const struct CMUnitTest tests[] = {
+		setup_test(test_mpathvalid_init_bad1),
+		setup_test(test_mpathvalid_init_bad2),
+		setup_test(test_mpathvalid_init_bad3),
+		setup_test(test_mpathvalid_init_good1),
+		setup_test(test_mpathvalid_init_good2),
+		setup_test(test_mpathvalid_init_good3),
+		setup_test(test_mpathvalid_exit),
+		setup_test(test_mpathvalid_get_mode_bad),
+		setup_test(test_mpathvalid_reload_config_bad1),
+		setup_test(test_mpathvalid_reload_config_bad2),
+		setup_test(test_mpathvalid_reload_config_good),
+		setup_test(test_mpathvalid_is_path_bad1),
+		setup_test(test_mpathvalid_is_path_bad2),
+		setup_test(test_mpathvalid_is_path_bad3),
+		setup_test(test_mpathvalid_is_path_bad4),
+		setup_test(test_mpathvalid_is_path_bad5),
+		setup_test(test_mpathvalid_is_path_good1),
+		setup_test(test_mpathvalid_is_path_good2),
+		setup_test(test_mpathvalid_is_path_good3),
+		setup_test(test_mpathvalid_is_path_good4),
+		setup_test(test_mpathvalid_is_path_good5),
+	};
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+int main(void)
+{
+	int r = 0;
+
+	r += test_mpathvalid();
+	return r;
+}
