Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / common / test_config.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
7  *
8  * Author: Loic Dachary <loic@dachary.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU Library Public License as published by
12  * the Free Software Foundation; either version 2, or (at your option)
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Library Public License for more details.
19  *
20  *
21  */
22 #include "common/config.h"
23 #include "common/errno.h"
24 #include "gtest/gtest.h"
25
26 extern std::string exec(const char* cmd); // defined in test_hostname.cc
27
28 class test_md_config_t : public md_config_t, public ::testing::Test {
29 public:
30
31   test_md_config_t()
32     : md_config_t(true), Test()
33   {}
34
35   void test_expand_meta() {
36     Mutex::Locker l(lock);
37     // successfull meta expansion $run_dir and ${run_dir}
38     {
39       ostringstream oss;
40       std::string before = " BEFORE ";
41       std::string after = " AFTER ";
42
43       std::string val(before + "$run_dir${run_dir}" + after);
44       EXPECT_TRUE(expand_meta(val, &oss));
45       EXPECT_EQ(before + "/var/run/ceph/var/run/ceph" + after, val);
46       EXPECT_EQ("", oss.str());
47     }
48     {
49       ostringstream oss;
50       std::string before = " BEFORE ";
51       std::string after = " AFTER ";
52       std::string val(before + "$host${host}" + after);
53       EXPECT_TRUE(expand_meta(val, &oss));
54       std::string hostname = exec("hostname -s");
55       EXPECT_EQ(before + hostname + hostname + after, val);
56       EXPECT_EQ("", oss.str());
57     }
58     // no meta expansion if variables are unknown
59     {
60       ostringstream oss;
61       std::string expected = "expect $foo and ${bar} to not expand";
62       std::string val = expected;
63       EXPECT_FALSE(expand_meta(val, &oss));
64       EXPECT_EQ(expected, val);
65       EXPECT_EQ("", oss.str());
66     }
67     // recursive variable expansion
68     {
69       std::string host = "localhost";
70       EXPECT_EQ(0, set_val("host", host.c_str(), false));
71
72       std::string mon_host = "$cluster_network";
73       EXPECT_EQ(0, set_val("mon_host", mon_host.c_str(), false));
74
75       std::string lockdep = "true";
76       EXPECT_EQ(0, set_val("lockdep", lockdep.c_str(), false));
77
78       std::string cluster_network = "$public_network $public_network $lockdep $host";
79       EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str(), false));
80
81       std::string public_network = "NETWORK";
82       EXPECT_EQ(0, set_val("public_network", public_network.c_str(), false));
83
84       ostringstream oss;
85       std::string val = "$mon_host";
86       EXPECT_TRUE(expand_meta(val, &oss));
87       EXPECT_EQ(public_network + " " +
88                 public_network + " " +
89                 lockdep + " " +
90                 "localhost", val);
91       EXPECT_EQ("", oss.str());
92     }
93     // variable expansion loops are non fatal
94     {
95       std::string mon_host = "$cluster_network";
96       EXPECT_EQ(0, set_val("mon_host", mon_host.c_str(), false));
97
98       std::string cluster_network = "$public_network";
99       EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str(), false));
100
101       std::string public_network = "$mon_host";
102       EXPECT_EQ(0, set_val("public_network", public_network.c_str(), false));
103
104       ostringstream oss;
105       std::string val = "$mon_host";
106       EXPECT_TRUE(expand_meta(val, &oss));
107       EXPECT_EQ("$cluster_network", val);
108       const char *expected_oss =
109         "variable expansion loop at mon_host=$cluster_network\n"
110         "expansion stack: \n"
111         "public_network=$mon_host\n"
112         "cluster_network=$public_network\n"
113         "mon_host=$cluster_network\n";
114       EXPECT_EQ(expected_oss, oss.str());
115     }
116   }
117
118   void test_expand_all_meta() {
119     Mutex::Locker l(lock);
120     int before_count = 0, data_dir = 0;
121     for (const auto &i : schema) {
122       const Option &opt = i.second;
123       if (opt.type == Option::TYPE_STR) {
124         const auto &str = boost::get<std::string>(opt.value);
125         if (str.find("$") != string::npos)
126           before_count++;
127         if (str.find("$data_dir") != string::npos)
128           data_dir++;
129       }
130     }
131
132     // if there are no meta variables in the default configuration,
133     // something must be done to check the expected side effect
134     // of expand_all_meta
135     ASSERT_LT(0, before_count);
136     expand_all_meta();
137     int after_count = 0;
138     for (auto& i : values) {
139       const auto &opt = schema.at(i.first);
140       if (opt.type == Option::TYPE_STR) {
141         const std::string &str = boost::get<std::string>(i.second);
142         size_t pos = 0;
143         while ((pos = str.find("$", pos)) != string::npos) {
144           if (str.substr(pos, 8) != "$channel") {
145             std::cout << "unexpected meta-variable found at pos " << pos
146                       << " of '" << str << "'" << std::endl;
147             after_count++;
148           }
149           pos++;
150         }
151       }
152     }
153     ASSERT_EQ(data_dir, after_count);
154   }
155 };
156
157 TEST_F(test_md_config_t, expand_meta)
158 {
159   test_expand_meta();
160 }
161
162 TEST_F(test_md_config_t, expand_all_meta)
163 {
164   test_expand_all_meta();
165 }
166
167 TEST(md_config_t, set_val)
168 {
169   int buf_size = 1024;
170   md_config_t conf;
171   // disable meta variable expansion
172   {
173     char *buf = (char*)malloc(buf_size);
174     std::string expected = "$host";
175     EXPECT_EQ(0, conf.set_val("mon_host", expected.c_str(), false));
176     EXPECT_EQ(0, conf.get_val("mon_host", &buf, buf_size));
177     EXPECT_EQ(expected, buf);
178     free(buf);
179   }
180   // meta variable expansion is enabled by default
181   {
182     char *run_dir = (char*)malloc(buf_size);
183     EXPECT_EQ(0, conf.get_val("run_dir", &run_dir, buf_size));
184     EXPECT_EQ(0, conf.set_val("admin_socket", "$run_dir"));
185     char *admin_socket = (char*)malloc(buf_size);
186     EXPECT_EQ(0, conf.get_val("admin_socket", &admin_socket, buf_size));
187     EXPECT_EQ(std::string(run_dir), std::string(admin_socket));
188     free(run_dir);
189     free(admin_socket);
190   }
191 }
192
193 TEST(Option, validation)
194 {
195   Option opt_int("foo", Option::TYPE_INT, Option::LEVEL_BASIC);
196   opt_int.set_min_max(5, 10);
197
198   std::string msg;
199   EXPECT_EQ(-EINVAL, opt_int.validate(Option::value_t(int64_t(4)), &msg));
200   EXPECT_EQ(-EINVAL, opt_int.validate(Option::value_t(int64_t(11)), &msg));
201   EXPECT_EQ(0, opt_int.validate(Option::value_t(int64_t(7)), &msg));
202
203   Option opt_enum("foo", Option::TYPE_STR, Option::LEVEL_BASIC);
204   opt_enum.set_enum_allowed({"red", "blue"});
205   EXPECT_EQ(0, opt_enum.validate(Option::value_t(std::string("red")), &msg));
206   EXPECT_EQ(0, opt_enum.validate(Option::value_t(std::string("blue")), &msg));
207   EXPECT_EQ(-EINVAL, opt_enum.validate(Option::value_t(std::string("green")), &msg));
208
209   Option opt_validator("foo", Option::TYPE_INT, Option::LEVEL_BASIC);
210   opt_validator.set_validator([](std::string *value, std::string *error_message){
211       if (*value == std::string("one")) {
212         *value = "1";
213         return 0;
214       } else if (*value == std::string("666")) {
215         return -EINVAL;
216       } else {
217         return 0;
218       }
219   });
220
221   std::string input = "666";  // An explicitly forbidden value
222   EXPECT_EQ(-EINVAL, opt_validator.pre_validate(&input, &msg));
223   EXPECT_EQ(input, "666");
224
225   input = "123";  // A permitted value with no special behaviour
226   EXPECT_EQ(0, opt_validator.pre_validate(&input, &msg));
227   EXPECT_EQ(input, "123");
228
229   input = "one";  // A value that has a magic conversion
230   EXPECT_EQ(0, opt_validator.pre_validate(&input, &msg));
231   EXPECT_EQ(input, "1");
232 }
233
234 /*
235  * Local Variables:
236  * compile-command: "cd ../.. ;
237  *   make unittest_config &&
238  *    valgrind \
239  *    --max-stackframe=20000000 --tool=memcheck \
240  *   ./unittest_config # --gtest_filter=md_config_t.set_val
241  * "
242  * End:
243  */