kpartx: fix bad dm_devn return
[multipath-tools/.git] / tests / hwtable.c
index 15f364e..42127ad 100644 (file)
@@ -23,6 +23,7 @@
 #include "defaults.h"
 #include "pgpolicies.h"
 #include "test-lib.h"
+#include "print.h"
 
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #define N_CONF_FILES 2
@@ -358,6 +359,16 @@ static void write_device(FILE *ff, int nkv, const struct key_value *kv)
                conf = NULL;                    \
        } while (0)
 
+static void replace_config(const struct hwt_state *hwt,
+                          const char *conf_str)
+{
+       FREE_CONFIG(_conf);
+       reset_configs(hwt);
+       fprintf(hwt->config_file, "%s", conf_str);
+       fflush(hwt->config_file);
+       _conf = LOAD_CONFIG(hwt);
+}
+
 #define TEST_PROP(prop, val) do {                              \
                if (val == NULL)                                \
                        assert_ptr_equal(prop, NULL);           \
@@ -432,8 +443,74 @@ static const struct key_value npr_queue = { _no_path_retry, "queue" };
 /***** BEGIN TESTS SECTION *****/
 
 /*
- * Run the given test case. This will later be extended
- * to run the test several times in a row.
+ * Dump the configuration, subistitute the dumped configuration
+ * for the current one, and verify that the result is identical.
+ */
+static void replicate_config(const struct hwt_state *hwt, bool local)
+{
+       char *cfg1, *cfg2;
+       vector hwtable;
+       struct config *conf;
+
+       condlog(1, "--- %s: replicating %s configuration", __func__,
+               local ? "local" : "full");
+
+       conf = get_multipath_config();
+       if (!local)
+               /* "full" configuration */
+               cfg1 = snprint_config(conf, NULL, NULL, NULL);
+       else {
+               /* "local" configuration */
+               hwtable = get_used_hwes(hwt->vecs->pathvec);
+               cfg1 = snprint_config(conf, NULL, hwtable, hwt->vecs->mpvec);
+       }
+
+       assert_non_null(cfg1);
+       put_multipath_config(conf);
+
+       replace_config(hwt, cfg1);
+
+       /*
+        * The local configuration adds multipath entries, and may move device
+        * entries for local devices to the end of the list. Identical config
+        * strings therefore can't be expected in the "local" case.
+        * That doesn't matter. The important thing is that, with the reloaded
+        * configuration, the test case still passes.
+        */
+       if (local) {
+               free(cfg1);
+               return;
+       }
+
+       conf = get_multipath_config();
+       cfg2 = snprint_config(conf, NULL, NULL, NULL);
+       assert_non_null(cfg2);
+       put_multipath_config(conf);
+
+// #define DBG_CONFIG 1
+#ifdef DBG_CONFIG
+#define DUMP_CFG_STR(x) do {                                           \
+               FILE *tmp = fopen("/tmp/hwtable-" #x ".txt", "w");      \
+               fprintf(tmp, "%s", x);                                  \
+               fclose(tmp);                                            \
+       } while (0)
+
+       DUMP_CFG_STR(cfg1);
+       DUMP_CFG_STR(cfg2);
+#endif
+
+       assert_int_equal(strlen(cfg2), strlen(cfg1));
+       assert_string_equal(cfg2, cfg1);
+       free(cfg1);
+       free(cfg2);
+}
+
+/*
+ * Run hwt->test three times; once with the constructed configuration,
+ * once after re-reading the full dumped configuration, and once with the
+ * dumped local configuration.
+ *
+ * Expected: test passes every time.
  */
 static void test_driver(void **state)
 {
@@ -443,6 +520,14 @@ static void test_driver(void **state)
        _conf = LOAD_CONFIG(hwt);
        hwt->test(hwt);
 
+       replicate_config(hwt, false);
+       reset_vecs(hwt->vecs);
+       hwt->test(hwt);
+
+       replicate_config(hwt, true);
+       reset_vecs(hwt->vecs);
+       hwt->test(hwt);
+
        reset_vecs(hwt->vecs);
        FREE_CONFIG(_conf);
 }
@@ -516,6 +601,7 @@ static int setup_internal_nvme(void **state)
 static void test_quoted_hwe(const struct hwt_state *hwt)
 {
        struct path *pp;
+
        /* foo:"bar" matches */
        pp = mock_path(vnd_foo.value, prd_baq.value);
        TEST_PROP(prio_name(&pp->prio), prio_emc.value);
@@ -565,6 +651,51 @@ static int setup_string_hwe(void **state)
        return 0;
 }
 
+/*
+ * Device section with a broken entry (no product)
+ * It should be ignored.
+ */
+static void test_broken_hwe(const struct hwt_state *hwt)
+{
+       struct path *pp;
+
+       /* foo:bar doesn't match, as hwentry is ignored */
+       pp = mock_path(vnd_foo.value, prd_bar.value);
+       TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
+
+       /* boo:bar doesn't match */
+       pp = mock_path(vnd_boo.value, prd_bar.value);
+       TEST_PROP(prio_name(&pp->prio), DEFAULT_PRIO);
+}
+
+static int setup_broken_hwe(void **state)
+{
+       struct hwt_state *hwt = CHECK_STATE(state);
+       const struct key_value kv[] = { vnd_foo, prio_emc };
+
+       WRITE_ONE_DEVICE(hwt, kv);
+       SET_TEST_FUNC(hwt, test_broken_hwe);
+       return 0;
+}
+
+/*
+ * Like test_broken_hwe, but in config_dir file.
+ */
+static int setup_broken_hwe_dir(void **state)
+{
+       struct hwt_state *hwt = CHECK_STATE(state);
+       const struct key_value kv[] = { vnd_foo, prio_emc };
+
+       begin_config(hwt);
+       begin_section_all(hwt, "devices");
+       write_device(hwt->conf_dir_file[0], ARRAY_SIZE(kv), kv);
+       end_section_all(hwt);
+       finish_config(hwt);
+       hwt->test = test_broken_hwe;
+       hwt->test_name = "test_broken_hwe_dir";
+       return 0;
+}
+
 /*
  * Device section with a single regex entry ("^.foo:(bar|baz|ba\.)$")
  */
@@ -1399,13 +1530,7 @@ static int setup_product_blacklist(void **state)
 static void test_product_blacklist_matching(const struct hwt_state *hwt)
 {
        mock_path_flags(vnd_foo.value, prd_bar.value, BL_BY_DEVICE);
-#if BROKEN == 1
-       condlog(1, "%s: WARNING: broken blacklist test on line %d",
-               __func__, __LINE__ + 1);
-       mock_path(vnd_foo.value, prd_baz.value);
-#else
-       mock_path_blacklisted(vnd_foo.value, prd_baz.value);
-#endif
+       mock_path_flags(vnd_foo.value, prd_baz.value, BL_BY_DEVICE);
        mock_path(vnd_foo.value, prd_bam.value);
 }
 
@@ -1470,8 +1595,6 @@ static int setup_multipath_config(void **state)
  *
  * Expected: properties are taken from both multipath sections, later taking
  * precedence
- *
- * Current: gets properties from first entry only.
  */
 static void test_multipath_config_2(const struct hwt_state *hwt)
 {
@@ -1483,15 +1606,8 @@ static void test_multipath_config_2(const struct hwt_state *hwt)
        assert_ptr_not_equal(mp, NULL);
        assert_ptr_not_equal(mp->mpe, NULL);
        TEST_PROP(prio_name(&pp->prio), prio_rdac.value);
-#if BROKEN
-       condlog(1, "%s: WARNING: broken test on %d", __func__, __LINE__ + 1);
-       assert_int_equal(mp->minio, DEFAULT_MINIO_RQ);
-       condlog(1, "%s: WARNING: broken test on %d", __func__, __LINE__ + 1);
-       assert_int_equal(mp->no_path_retry, NO_PATH_RETRY_QUEUE);
-#else
        assert_int_equal(mp->minio, atoi(minio_99.value));
        assert_int_equal(mp->no_path_retry, atoi(npr_37.value));
-#endif
 }
 
 static int setup_multipath_config_2(void **state)
@@ -1525,15 +1641,8 @@ static void test_multipath_config_3(const struct hwt_state *hwt)
        assert_ptr_not_equal(mp, NULL);
        assert_ptr_not_equal(mp->mpe, NULL);
        TEST_PROP(prio_name(&pp->prio), prio_rdac.value);
-#if BROKEN
-       condlog(1, "%s: WARNING: broken test on %d", __func__, __LINE__ + 1);
-       assert_int_equal(mp->minio, DEFAULT_MINIO_RQ);
-       condlog(1, "%s: WARNING: broken test on %d", __func__, __LINE__ + 1);
-       assert_int_equal(mp->no_path_retry, NO_PATH_RETRY_QUEUE);
-#else
        assert_int_equal(mp->minio, atoi(minio_99.value));
        assert_int_equal(mp->no_path_retry, atoi(npr_37.value));
-#endif
 }
 
 static int setup_multipath_config_3(void **state)
@@ -1564,6 +1673,8 @@ static int setup_multipath_config_3(void **state)
        }
 
 define_test(string_hwe)
+define_test(broken_hwe)
+define_test(broken_hwe_dir)
 define_test(quoted_hwe)
 define_test(internal_nvme)
 define_test(regex_hwe)
@@ -1602,6 +1713,8 @@ static int test_hwtable(void)
                cmocka_unit_test(test_sanity_globals),
                test_entry(internal_nvme),
                test_entry(string_hwe),
+               test_entry(broken_hwe),
+               test_entry(broken_hwe_dir),
                test_entry(quoted_hwe),
                test_entry(regex_hwe),
                test_entry(regex_string_hwe),