From 3f34dc7d5272e7fe61d1efb2712a9defd2ce329c Mon Sep 17 00:00:00 2001 From: Loic Dachary Date: Sun, 5 Jan 2014 15:49:57 +0100 Subject: [PATCH] common: unit tests for config::expand_meta 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 --- src/common/config.h | 2 + src/test/Makefile.am | 5 + src/test/cli/ceph-conf/show-config-value.t | 10 ++ src/test/common/test_config.cc | 187 +++++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 src/test/common/test_config.cc diff --git a/src/common/config.h b/src/common/config.h index a6be703464555..d54642b2a6d48 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -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 { diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 5faf9ac49fd1e..5f440888cb327 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -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) diff --git a/src/test/cli/ceph-conf/show-config-value.t b/src/test/cli/ceph-conf/show-config-value.t index 3d7d319416ce9..f2f82045cee62 100644 --- a/src/test/cli/ceph-conf/show-config-value.t +++ b/src/test/cli/ceph-conf/show-config-value.t @@ -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 index 0000000000000..cffdc763d7117 --- /dev/null +++ b/src/test/common/test_config.cc @@ -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 + * + * Author: Loic Dachary + * + * 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: + */ -- 2.39.5