]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: unit tests for config::expand_meta 1046/head
authorLoic Dachary <loic@dachary.org>
Sun, 5 Jan 2014 14:49:57 +0000 (15:49 +0100)
committerLoic Dachary <loic@dachary.org>
Sun, 5 Jan 2014 15:11:43 +0000 (16:11 +0100)
Part of the config.cc tests are in test/confutils.cc but they do not
cover meta variable expansion. Create unittest_config for config.{h,cc}
specific tests.

The test_md_config_t is made a friend of md_config_t to allow testing
private and protected methods.

test/cli/ceph-conf/show-config-value.t is used to check that the human
readable message message shows as expected when there is an expansion
loop.

Signed-off-by: Loic Dachary <loic@dachary.org>
src/common/config.h
src/test/Makefile.am
src/test/cli/ceph-conf/show-config-value.t
src/test/common/test_config.cc [new file with mode: 0644]

index a6be70346455533a7fd0335c3f51107dbaab9898..d54642b2a6d48a39b56b0e5a122d4a1e32887df6 100644 (file)
@@ -237,6 +237,8 @@ public:
    * It is best if this lock comes first in the lock hierarchy. We will
    * hold this lock when calling configuration observers.  */
   mutable Mutex lock;
+
+  friend class test_md_config_t;
 };
 
 typedef enum {
index 5faf9ac49fd1e83c2d738a928091634dbc3ed755..5f440888cb3275347574f5f60644920a4e0587e3 100644 (file)
@@ -535,6 +535,11 @@ unittest_confutils_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
 unittest_confutils_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 check_PROGRAMS += unittest_confutils
 
+unittest_config_SOURCES = test/common/test_config.cc
+unittest_config_LDADD = $(UNITTEST_LDADD) $(CEPH_GLOBAL)
+unittest_config_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+check_PROGRAMS += unittest_config
+
 unittest_heartbeatmap_SOURCES = test/heartbeat_map.cc
 unittest_heartbeatmap_LDADD = $(LIBCOMMON) $(UNITTEST_LDADD) $(CEPH_GLOBAL)
 unittest_heartbeatmap_CXXFLAGS = $(UNITTEST_CXXFLAGS)
index 3d7d319416ce9219233cd973e2304c90a4fc378f..f2f82045cee62c37f4045048027a949888312937 100644 (file)
@@ -8,3 +8,13 @@
   $ ceph-conf -n osd.0 --show-config-value INVALID -c /dev/null
   failed to get config option 'INVALID': option not found
   [1]
+  $ echo '[global]' > $TESTDIR/ceph.conf
+  $ echo 'mon_host=$public_network' >> $TESTDIR/ceph.conf
+  $ echo 'public_network=$mon_host' >> $TESTDIR/ceph.conf
+  $ ceph-conf --show-config-value mon_host -c $TESTDIR/ceph.conf
+  variable expansion loop at public_network=$mon_host
+  expansion stack: 
+  mon_host=$public_network
+  public_network=$mon_host
+  $mon_host
+  $ rm $TESTDIR/ceph.conf
diff --git a/src/test/common/test_config.cc b/src/test/common/test_config.cc
new file mode 100644 (file)
index 0000000..cffdc76
--- /dev/null
@@ -0,0 +1,187 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library Public License for more details.
+ *
+ *
+ */
+#include "common/config.h"
+#include "common/errno.h"
+#include "gtest/gtest.h"
+
+#define _STR(x) #x
+#define STRINGIFY(x) _STR(x)
+
+static struct config_option config_optionsp[] = {
+#define OPTION(name, type, def_val) \
+       { STRINGIFY(name), type, offsetof(struct md_config_t, name) },
+#define SUBSYS(name, log, gather)
+#define DEFAULT_SUBSYS(log, gather)
+#include "common/config_opts.h"
+#undef OPTION
+#undef SUBSYS
+#undef DEFAULT_SUBSYS
+};
+
+static const int NUM_CONFIG_OPTIONS = sizeof(config_optionsp) / sizeof(config_option);
+
+class test_md_config_t : public md_config_t, public ::testing::Test {
+public:
+  void test_expand_meta() {
+    Mutex::Locker l(lock);
+    // successfull meta expansion $run_dir and ${run_dir}
+    {
+      ostringstream oss;
+      std::string before = " BEFORE ";
+      std::string after = " AFTER ";
+      std::string val(before + "$run_dir${run_dir}" + after);
+      EXPECT_TRUE(expand_meta(val, &oss));
+      EXPECT_EQ(before + "/var/run/ceph/var/run/ceph" + after, val);
+      EXPECT_EQ("", oss.str());
+    }
+    // no meta expansion if variables are unknown
+    {
+      ostringstream oss;
+      std::string expected = "expect $foo and ${bar} to not expand";
+      std::string val = expected;
+      EXPECT_FALSE(expand_meta(val, &oss));
+      EXPECT_EQ(expected, val);
+      EXPECT_EQ("", oss.str());
+    }
+    // recursive variable expansion
+    {
+      std::string mon_host = "$cluster_network";
+      EXPECT_EQ(0, set_val("mon_host", mon_host.c_str(), false));
+
+      std::string lockdep = "true";
+      EXPECT_EQ(0, set_val("lockdep", lockdep.c_str(), false));
+
+      std::string cluster_network = "$public_network $public_network $lockdep $host";
+      EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str(), false));
+
+      std::string public_network = "NETWORK";
+      EXPECT_EQ(0, set_val("public_network", public_network.c_str(), false));
+
+      ostringstream oss;
+      std::string val = "$mon_host";
+      EXPECT_TRUE(expand_meta(val, &oss));
+      EXPECT_EQ(public_network + " " +
+                public_network + " " +
+                lockdep + " " +
+                "localhost", val);
+      EXPECT_EQ("", oss.str());
+    }
+    // variable expansion loops are non fatal
+    {
+      std::string mon_host = "$cluster_network";
+      EXPECT_EQ(0, set_val("mon_host", mon_host.c_str(), false));
+
+      std::string cluster_network = "$public_network";
+      EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str(), false));
+
+      std::string public_network = "$mon_host";
+      EXPECT_EQ(0, set_val("public_network", public_network.c_str(), false));
+
+      ostringstream oss;
+      std::string val = "$mon_host";
+      EXPECT_TRUE(expand_meta(val, &oss));
+      EXPECT_EQ("$cluster_network", val);
+      const char *expected_oss =
+        "variable expansion loop at mon_host=$cluster_network\n"
+        "expansion stack: \n"
+        "public_network=$mon_host\n"
+        "cluster_network=$public_network\n"
+        "mon_host=$cluster_network\n";
+      EXPECT_EQ(expected_oss, oss.str());
+    }
+  }
+
+  void test_expand_all_meta() {
+    Mutex::Locker l(lock);
+    int before_count = 0;
+    for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) {
+      config_option *opt = config_optionsp + i;
+      if (opt->type == OPT_STR) {
+        std::string *str = (std::string *)opt->conf_ptr(this);
+        if (str->find("$") != string::npos)
+          before_count++;
+      }
+    }
+    // if there are no meta variables in the default configuration,
+    // something must be done to check the expected side effect
+    // of expand_all_meta
+    ASSERT_LT(0, before_count);
+    expand_all_meta();
+    int after_count = 0;
+    for (int i = 0; i < NUM_CONFIG_OPTIONS; i++) {
+      config_option *opt = config_optionsp + i;
+      if (opt->type == OPT_STR) {
+        std::string *str = (std::string *)opt->conf_ptr(this);
+        if (str->find("$") != string::npos)
+          after_count++;
+      }
+    }
+    ASSERT_EQ(0, after_count);
+  }
+};
+
+TEST_F(test_md_config_t, expand_meta)
+{
+  test_expand_meta();
+}
+
+TEST_F(test_md_config_t, expand_all_meta)
+{
+  test_expand_all_meta();
+}
+
+TEST(md_config_t, set_val)
+{
+  int buf_size = 1024;
+  md_config_t conf;
+  // disable meta variable expansion
+  {
+    char *buf = (char*)malloc(buf_size);
+    std::string expected = "$host";
+    EXPECT_EQ(0, conf.set_val("mon_host", expected.c_str(), false));
+    EXPECT_EQ(0, conf.get_val("mon_host", &buf, buf_size));
+    EXPECT_EQ(expected, buf);
+    free(buf);
+  }
+  // meta variable expansion is enabled by default
+  {
+    char *run_dir = (char*)malloc(buf_size);
+    EXPECT_EQ(0, conf.get_val("run_dir", &run_dir, buf_size));
+    EXPECT_EQ(0, conf.set_val("admin_socket", "$run_dir"));
+    char *admin_socket = (char*)malloc(buf_size);
+    EXPECT_EQ(0, conf.get_val("admin_socket", &admin_socket, buf_size));
+    EXPECT_EQ(std::string(run_dir), std::string(admin_socket));
+    free(run_dir);
+    free(admin_socket);
+  }
+}
+
+/*
+ * Local Variables:
+ * compile-command: "cd ../.. ;
+ *   make unittest_config &&
+ *    valgrind \
+ *    --max-stackframe=20000000 --tool=memcheck \
+ *   ./unittest_config # --gtest_filter=md_config_t.set_val
+ * "
+ * End:
+ */