]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/common/test_config.cc
import ceph nautilus 14.2.2
[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, parse_env)
135 {
136 {
137 ConfigProxy conf{false};
138 setenv("POD_MEMORY_REQUEST", "1", 1);
139 conf.parse_env(CEPH_ENTITY_TYPE_OSD);
140 }
141 {
142 ConfigProxy conf{false};
143 setenv("POD_MEMORY_REQUEST", "0", 1);
144 conf.parse_env(CEPH_ENTITY_TYPE_OSD);
145 }
146 {
147 ConfigProxy conf{false};
148 setenv("CEPH_KEYRING", "", 1);
149 conf.parse_env(CEPH_ENTITY_TYPE_OSD);
150 }
151 }
152
153 TEST(md_config_t, set_val)
154 {
155 int buf_size = 1024;
156 ConfigProxy conf{false};
157 {
158 char *run_dir = (char*)malloc(buf_size);
159 EXPECT_EQ(0, conf.get_val("run_dir", &run_dir, buf_size));
160 EXPECT_EQ(0, conf.set_val("admin_socket", "$run_dir"));
161 char *admin_socket = (char*)malloc(buf_size);
162 EXPECT_EQ(0, conf.get_val("admin_socket", &admin_socket, buf_size));
163 EXPECT_EQ(std::string(run_dir), std::string(admin_socket));
164 free(run_dir);
165 free(admin_socket);
166 }
167 // set_val should support SI conversion
168 {
169 auto expected = Option::size_t{512 << 20};
170 EXPECT_EQ(0, conf.set_val("mgr_osd_bytes", "512M", nullptr));
171 EXPECT_EQ(expected, conf.get_val<Option::size_t>("mgr_osd_bytes"));
172 EXPECT_EQ(-EINVAL, conf.set_val("mgr_osd_bytes", "512 bits", nullptr));
173 EXPECT_EQ(expected, conf.get_val<Option::size_t>("mgr_osd_bytes"));
174 }
175 // set_val should support 1 days 2 hours 4 minutes
176 {
177 using namespace std::chrono;
178 const string s{"1 days 2 hours 4 minutes"};
179 using days_t = duration<int, std::ratio<3600 * 24>>;
180 auto expected = (duration_cast<seconds>(days_t{1}) +
181 duration_cast<seconds>(hours{2}) +
182 duration_cast<seconds>(minutes{4}));
183 EXPECT_EQ(0, conf.set_val("mgr_tick_period",
184 "1 days 2 hours 4 minutes", nullptr));
185 EXPECT_EQ(expected.count(), conf.get_val<seconds>("mgr_tick_period").count());
186 EXPECT_EQ(-EINVAL, conf.set_val("mgr_tick_period", "21 centuries", nullptr));
187 EXPECT_EQ(expected.count(), conf.get_val<seconds>("mgr_tick_period").count());
188 }
189
190 using namespace std::chrono;
191
192 using days_t = duration<int, std::ratio<3600 * 24>>;
193
194 struct testcase {
195 std::string s;
196 std::chrono::seconds r;
197 };
198 std::vector<testcase> good = {
199 { "23"s, duration_cast<seconds>(seconds{23}) },
200 { " 23 "s, duration_cast<seconds>(seconds{23}) },
201 { " 23s "s, duration_cast<seconds>(seconds{23}) },
202 { " 23 s "s, duration_cast<seconds>(seconds{23}) },
203 { " 23 sec "s, duration_cast<seconds>(seconds{23}) },
204 { "23 second "s, duration_cast<seconds>(seconds{23}) },
205 { "23 seconds"s, duration_cast<seconds>(seconds{23}) },
206 { "2m5s"s, duration_cast<seconds>(seconds{2*60+5}) },
207 { "2 m 5 s "s, duration_cast<seconds>(seconds{2*60+5}) },
208 { "2 m5"s, duration_cast<seconds>(seconds{2*60+5}) },
209 { "2 min5"s, duration_cast<seconds>(seconds{2*60+5}) },
210 { "2 minutes 5"s, duration_cast<seconds>(seconds{2*60+5}) },
211 { "1w"s, duration_cast<seconds>(seconds{3600*24*7}) },
212 { "1wk"s, duration_cast<seconds>(seconds{3600*24*7}) },
213 { "1week"s, duration_cast<seconds>(seconds{3600*24*7}) },
214 { "1weeks"s, duration_cast<seconds>(seconds{3600*24*7}) },
215 { "1month"s, duration_cast<seconds>(seconds{3600*24*30}) },
216 { "1months"s, duration_cast<seconds>(seconds{3600*24*30}) },
217 { "1mo"s, duration_cast<seconds>(seconds{3600*24*30}) },
218 { "1y"s, duration_cast<seconds>(seconds{3600*24*365}) },
219 { "1yr"s, duration_cast<seconds>(seconds{3600*24*365}) },
220 { "1year"s, duration_cast<seconds>(seconds{3600*24*365}) },
221 { "1years"s, duration_cast<seconds>(seconds{3600*24*365}) },
222 { "1d2h3m4s"s,
223 duration_cast<seconds>(days_t{1}) +
224 duration_cast<seconds>(hours{2}) +
225 duration_cast<seconds>(minutes{3}) +
226 duration_cast<seconds>(seconds{4}) },
227 { "1 days 2 hours 4 minutes"s,
228 duration_cast<seconds>(days_t{1}) +
229 duration_cast<seconds>(hours{2}) +
230 duration_cast<seconds>(minutes{4}) },
231 };
232
233 for (auto& i : good) {
234 cout << "good: " << i.s << " -> " << i.r.count() << std::endl;
235 EXPECT_EQ(0, conf.set_val("mgr_tick_period", i.s, nullptr));
236 EXPECT_EQ(i.r.count(), conf.get_val<seconds>("mgr_tick_period").count());
237 }
238
239 std::vector<std::string> bad = {
240 "12x",
241 "_ 12",
242 "1 2",
243 "21 centuries",
244 "1 y m",
245 };
246 for (auto& i : bad) {
247 std::stringstream err;
248 EXPECT_EQ(-EINVAL, conf.set_val("mgr_tick_period", i, &err));
249 cout << "bad: " << i << " -> " << err.str() << std::endl;
250 }
251
252 for (int i = 0; i < 100; ++i) {
253 std::chrono::seconds j = std::chrono::seconds(rand());
254 string s = exact_timespan_str(j);
255 std::chrono::seconds k = parse_timespan(s);
256 cout << "rt: " << j.count() << " -> " << s << " -> " << k.count() << std::endl;
257 EXPECT_EQ(j.count(), k.count());
258 }
259 }
260
261 TEST(Option, validation)
262 {
263 Option opt_int("foo", Option::TYPE_INT, Option::LEVEL_BASIC);
264 opt_int.set_min_max(5, 10);
265
266 std::string msg;
267 EXPECT_EQ(-EINVAL, opt_int.validate(Option::value_t(int64_t(4)), &msg));
268 EXPECT_EQ(-EINVAL, opt_int.validate(Option::value_t(int64_t(11)), &msg));
269 EXPECT_EQ(0, opt_int.validate(Option::value_t(int64_t(7)), &msg));
270
271 Option opt_enum("foo", Option::TYPE_STR, Option::LEVEL_BASIC);
272 opt_enum.set_enum_allowed({"red", "blue"});
273 EXPECT_EQ(0, opt_enum.validate(Option::value_t(std::string("red")), &msg));
274 EXPECT_EQ(0, opt_enum.validate(Option::value_t(std::string("blue")), &msg));
275 EXPECT_EQ(-EINVAL, opt_enum.validate(Option::value_t(std::string("green")), &msg));
276
277 Option opt_validator("foo", Option::TYPE_INT, Option::LEVEL_BASIC);
278 opt_validator.set_validator([](std::string *value, std::string *error_message){
279 if (*value == std::string("one")) {
280 *value = "1";
281 return 0;
282 } else if (*value == std::string("666")) {
283 return -EINVAL;
284 } else {
285 return 0;
286 }
287 });
288
289 std::string input = "666"; // An explicitly forbidden value
290 EXPECT_EQ(-EINVAL, opt_validator.pre_validate(&input, &msg));
291 EXPECT_EQ(input, "666");
292
293 input = "123"; // A permitted value with no special behaviour
294 EXPECT_EQ(0, opt_validator.pre_validate(&input, &msg));
295 EXPECT_EQ(input, "123");
296
297 input = "one"; // A value that has a magic conversion
298 EXPECT_EQ(0, opt_validator.pre_validate(&input, &msg));
299 EXPECT_EQ(input, "1");
300 }
301
302 /*
303 * Local Variables:
304 * compile-command: "cd ../.. ;
305 * make unittest_config &&
306 * valgrind \
307 * --max-stackframe=20000000 --tool=memcheck \
308 * ./unittest_config # --gtest_filter=md_config_t.set_val
309 * "
310 * End:
311 */