]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/common/test_config.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / 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_proxy.h"
23 #include "common/errno.h"
24 #include "gtest/gtest.h"
25 #include "common/hostname.h"
26
27 extern std::string exec(const char* cmd); // defined in test_hostname.cc
28
29 class test_config_proxy : public ConfigProxy, public ::testing::Test {
30 public:
31
32 test_config_proxy()
33 : ConfigProxy{true}, Test()
34 {}
35
36 void test_expand_meta() {
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 early_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
53 std::string val(before + "$$1$run_dir$2${run_dir}$3$" + after);
54 early_expand_meta(val, &oss);
55 EXPECT_EQ(before + "$$1/var/run/ceph$2/var/run/ceph$3$" + after, val);
56 EXPECT_EQ("", oss.str());
57 }
58 {
59 ostringstream oss;
60 std::string before = " BEFORE ";
61 std::string after = " AFTER ";
62 std::string val(before + "$host${host}" + after);
63 early_expand_meta(val, &oss);
64 std::string hostname = ceph_get_short_hostname();
65 EXPECT_EQ(before + hostname + hostname + after, val);
66 EXPECT_EQ("", oss.str());
67 }
68 // no meta expansion if variables are unknown
69 {
70 ostringstream oss;
71 std::string expected = "expect $foo and ${bar} to not expand";
72 std::string val = expected;
73 early_expand_meta(val, &oss);
74 EXPECT_EQ(expected, val);
75 EXPECT_EQ("", oss.str());
76 }
77 // recursive variable expansion
78 {
79 std::string host = "localhost";
80 EXPECT_EQ(0, set_val("host", host.c_str()));
81
82 std::string mon_host = "$cluster_network";
83 EXPECT_EQ(0, set_val("mon_host", mon_host.c_str()));
84
85 std::string lockdep = "true";
86 EXPECT_EQ(0, set_val("lockdep", lockdep.c_str()));
87
88 std::string cluster_network = "$public_network $public_network $lockdep $host";
89 EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str()));
90
91 std::string public_network = "NETWORK";
92 EXPECT_EQ(0, set_val("public_network", public_network.c_str()));
93
94 ostringstream oss;
95 std::string val = "$mon_host";
96 early_expand_meta(val, &oss);
97 EXPECT_EQ(public_network + " " +
98 public_network + " " +
99 lockdep + " " +
100 "localhost", val);
101 EXPECT_EQ("", oss.str());
102 }
103 // variable expansion loops are non fatal
104 {
105 std::string mon_host = "$cluster_network";
106 EXPECT_EQ(0, set_val("mon_host", mon_host.c_str()));
107
108 std::string cluster_network = "$public_network";
109 EXPECT_EQ(0, set_val("cluster_network", cluster_network.c_str()));
110
111 std::string public_network = "$mon_host";
112 EXPECT_EQ(0, set_val("public_network", public_network.c_str()));
113
114 ostringstream oss;
115 std::string val = "$mon_host";
116 early_expand_meta(val, &oss);
117 EXPECT_EQ("$mon_host", val);
118 const char *expected_oss =
119 "variable expansion loop at mon_host=$cluster_network\n"
120 "expansion stack:\n"
121 "public_network=$mon_host\n"
122 "cluster_network=$public_network\n"
123 "mon_host=$cluster_network\n";
124 EXPECT_EQ(expected_oss, oss.str());
125 }
126 }
127 };
128
129 TEST_F(test_config_proxy, expand_meta)
130 {
131 test_expand_meta();
132 }
133
134 TEST(md_config_t, set_val)
135 {
136 int buf_size = 1024;
137 ConfigProxy conf{false};
138 {
139 char *run_dir = (char*)malloc(buf_size);
140 EXPECT_EQ(0, conf.get_val("run_dir", &run_dir, buf_size));
141 EXPECT_EQ(0, conf.set_val("admin_socket", "$run_dir"));
142 char *admin_socket = (char*)malloc(buf_size);
143 EXPECT_EQ(0, conf.get_val("admin_socket", &admin_socket, buf_size));
144 EXPECT_EQ(std::string(run_dir), std::string(admin_socket));
145 free(run_dir);
146 free(admin_socket);
147 }
148 // set_val should support SI conversion
149 {
150 auto expected = Option::size_t{512 << 20};
151 EXPECT_EQ(0, conf.set_val("mgr_osd_bytes", "512M", nullptr));
152 EXPECT_EQ(expected, conf.get_val<Option::size_t>("mgr_osd_bytes"));
153 EXPECT_EQ(-EINVAL, conf.set_val("mgr_osd_bytes", "512 bits", nullptr));
154 EXPECT_EQ(expected, conf.get_val<Option::size_t>("mgr_osd_bytes"));
155 }
156 // set_val should support 1 days 2 hours 4 minutes
157 {
158 using namespace std::chrono;
159 const string s{"1 days 2 hours 4 minutes"};
160 using days_t = duration<int, std::ratio<3600 * 24>>;
161 auto expected = (duration_cast<seconds>(days_t{1}) +
162 duration_cast<seconds>(hours{2}) +
163 duration_cast<seconds>(minutes{4}));
164 EXPECT_EQ(0, conf.set_val("mgr_tick_period",
165 "1 days 2 hours 4 minutes", nullptr));
166 EXPECT_EQ(expected.count(), conf.get_val<seconds>("mgr_tick_period").count());
167 EXPECT_EQ(-EINVAL, conf.set_val("mgr_tick_period", "21 centuries", nullptr));
168 EXPECT_EQ(expected.count(), conf.get_val<seconds>("mgr_tick_period").count());
169 }
170
171 using namespace std::chrono;
172
173 using days_t = duration<int, std::ratio<3600 * 24>>;
174
175 struct testcase {
176 std::string s;
177 std::chrono::seconds r;
178 };
179 std::vector<testcase> good = {
180 { "23"s, duration_cast<seconds>(seconds{23}) },
181 { " 23 "s, duration_cast<seconds>(seconds{23}) },
182 { " 23s "s, duration_cast<seconds>(seconds{23}) },
183 { " 23 s "s, duration_cast<seconds>(seconds{23}) },
184 { " 23 sec "s, duration_cast<seconds>(seconds{23}) },
185 { "23 second "s, duration_cast<seconds>(seconds{23}) },
186 { "23 seconds"s, duration_cast<seconds>(seconds{23}) },
187 { "2m5s"s, duration_cast<seconds>(seconds{2*60+5}) },
188 { "2 m 5 s "s, duration_cast<seconds>(seconds{2*60+5}) },
189 { "2 m5"s, duration_cast<seconds>(seconds{2*60+5}) },
190 { "2 min5"s, duration_cast<seconds>(seconds{2*60+5}) },
191 { "2 minutes 5"s, duration_cast<seconds>(seconds{2*60+5}) },
192 { "1w"s, duration_cast<seconds>(seconds{3600*24*7}) },
193 { "1wk"s, duration_cast<seconds>(seconds{3600*24*7}) },
194 { "1week"s, duration_cast<seconds>(seconds{3600*24*7}) },
195 { "1weeks"s, duration_cast<seconds>(seconds{3600*24*7}) },
196 { "1month"s, duration_cast<seconds>(seconds{3600*24*30}) },
197 { "1months"s, duration_cast<seconds>(seconds{3600*24*30}) },
198 { "1mo"s, duration_cast<seconds>(seconds{3600*24*30}) },
199 { "1y"s, duration_cast<seconds>(seconds{3600*24*365}) },
200 { "1yr"s, duration_cast<seconds>(seconds{3600*24*365}) },
201 { "1year"s, duration_cast<seconds>(seconds{3600*24*365}) },
202 { "1years"s, duration_cast<seconds>(seconds{3600*24*365}) },
203 { "1d2h3m4s"s,
204 duration_cast<seconds>(days_t{1}) +
205 duration_cast<seconds>(hours{2}) +
206 duration_cast<seconds>(minutes{3}) +
207 duration_cast<seconds>(seconds{4}) },
208 { "1 days 2 hours 4 minutes"s,
209 duration_cast<seconds>(days_t{1}) +
210 duration_cast<seconds>(hours{2}) +
211 duration_cast<seconds>(minutes{4}) },
212 };
213
214 for (auto& i : good) {
215 cout << "good: " << i.s << " -> " << i.r.count() << std::endl;
216 EXPECT_EQ(0, conf.set_val("mgr_tick_period", i.s, nullptr));
217 EXPECT_EQ(i.r.count(), conf.get_val<seconds>("mgr_tick_period").count());
218 }
219
220 std::vector<std::string> bad = {
221 "12x",
222 "_ 12",
223 "1 2",
224 "21 centuries",
225 "1 y m",
226 };
227 for (auto& i : bad) {
228 std::stringstream err;
229 EXPECT_EQ(-EINVAL, conf.set_val("mgr_tick_period", i, &err));
230 cout << "bad: " << i << " -> " << err.str() << std::endl;
231 }
232
233 for (int i = 0; i < 100; ++i) {
234 std::chrono::seconds j = std::chrono::seconds(rand());
235 string s = exact_timespan_str(j);
236 std::chrono::seconds k = parse_timespan(s);
237 cout << "rt: " << j.count() << " -> " << s << " -> " << k.count() << std::endl;
238 EXPECT_EQ(j.count(), k.count());
239 }
240 }
241
242 TEST(Option, validation)
243 {
244 Option opt_int("foo", Option::TYPE_INT, Option::LEVEL_BASIC);
245 opt_int.set_min_max(5, 10);
246
247 std::string msg;
248 EXPECT_EQ(-EINVAL, opt_int.validate(Option::value_t(int64_t(4)), &msg));
249 EXPECT_EQ(-EINVAL, opt_int.validate(Option::value_t(int64_t(11)), &msg));
250 EXPECT_EQ(0, opt_int.validate(Option::value_t(int64_t(7)), &msg));
251
252 Option opt_enum("foo", Option::TYPE_STR, Option::LEVEL_BASIC);
253 opt_enum.set_enum_allowed({"red", "blue"});
254 EXPECT_EQ(0, opt_enum.validate(Option::value_t(std::string("red")), &msg));
255 EXPECT_EQ(0, opt_enum.validate(Option::value_t(std::string("blue")), &msg));
256 EXPECT_EQ(-EINVAL, opt_enum.validate(Option::value_t(std::string("green")), &msg));
257
258 Option opt_validator("foo", Option::TYPE_INT, Option::LEVEL_BASIC);
259 opt_validator.set_validator([](std::string *value, std::string *error_message){
260 if (*value == std::string("one")) {
261 *value = "1";
262 return 0;
263 } else if (*value == std::string("666")) {
264 return -EINVAL;
265 } else {
266 return 0;
267 }
268 });
269
270 std::string input = "666"; // An explicitly forbidden value
271 EXPECT_EQ(-EINVAL, opt_validator.pre_validate(&input, &msg));
272 EXPECT_EQ(input, "666");
273
274 input = "123"; // A permitted value with no special behaviour
275 EXPECT_EQ(0, opt_validator.pre_validate(&input, &msg));
276 EXPECT_EQ(input, "123");
277
278 input = "one"; // A value that has a magic conversion
279 EXPECT_EQ(0, opt_validator.pre_validate(&input, &msg));
280 EXPECT_EQ(input, "1");
281 }
282
283 /*
284 * Local Variables:
285 * compile-command: "cd ../.. ;
286 * make unittest_config &&
287 * valgrind \
288 * --max-stackframe=20000000 --tool=memcheck \
289 * ./unittest_config # --gtest_filter=md_config_t.set_val
290 * "
291 * End:
292 */