]>
git.proxmox.com Git - ceph.git/blob - 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
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2014 Cloudwatt <libre.licensing@cloudwatt.com>
8 * Author: Loic Dachary <loic@dachary.org>
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)
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.
22 #include "common/config_proxy.h"
23 #include "common/errno.h"
24 #include "gtest/gtest.h"
25 #include "common/hostname.h"
27 extern std::string
exec(const char* cmd
); // defined in test_hostname.cc
29 class test_config_proxy
: public ConfigProxy
, public ::testing::Test
{
33 : ConfigProxy
{true}, Test()
36 void test_expand_meta() {
37 // successfull meta expansion $run_dir and ${run_dir}
40 std::string before
= " BEFORE ";
41 std::string after
= " AFTER ";
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());
50 std::string before
= " BEFORE ";
51 std::string after
= " AFTER ";
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());
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());
68 // no meta expansion if variables are unknown
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());
77 // recursive variable expansion
79 std::string host
= "localhost";
80 EXPECT_EQ(0, set_val("host", host
.c_str()));
82 std::string mon_host
= "$cluster_network";
83 EXPECT_EQ(0, set_val("mon_host", mon_host
.c_str()));
85 std::string lockdep
= "true";
86 EXPECT_EQ(0, set_val("lockdep", lockdep
.c_str()));
88 std::string cluster_network
= "$public_network $public_network $lockdep $host";
89 EXPECT_EQ(0, set_val("cluster_network", cluster_network
.c_str()));
91 std::string public_network
= "NETWORK";
92 EXPECT_EQ(0, set_val("public_network", public_network
.c_str()));
95 std::string val
= "$mon_host";
96 early_expand_meta(val
, &oss
);
97 EXPECT_EQ(public_network
+ " " +
98 public_network
+ " " +
101 EXPECT_EQ("", oss
.str());
103 // variable expansion loops are non fatal
105 std::string mon_host
= "$cluster_network";
106 EXPECT_EQ(0, set_val("mon_host", mon_host
.c_str()));
108 std::string cluster_network
= "$public_network";
109 EXPECT_EQ(0, set_val("cluster_network", cluster_network
.c_str()));
111 std::string public_network
= "$mon_host";
112 EXPECT_EQ(0, set_val("public_network", public_network
.c_str()));
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"
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());
129 TEST_F(test_config_proxy
, expand_meta
)
134 TEST(md_config_t
, parse_env
)
137 ConfigProxy conf
{false};
138 setenv("POD_MEMORY_REQUEST", "1", 1);
139 conf
.parse_env(CEPH_ENTITY_TYPE_OSD
);
142 ConfigProxy conf
{false};
143 setenv("POD_MEMORY_REQUEST", "0", 1);
144 conf
.parse_env(CEPH_ENTITY_TYPE_OSD
);
147 ConfigProxy conf
{false};
148 setenv("CEPH_KEYRING", "", 1);
149 conf
.parse_env(CEPH_ENTITY_TYPE_OSD
);
153 TEST(md_config_t
, set_val
)
156 ConfigProxy conf
{false};
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
));
167 // set_val should support SI conversion
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"));
175 // set_val should support 1 days 2 hours 4 minutes
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());
190 using namespace std::chrono
;
192 using days_t
= duration
<int, std::ratio
<3600 * 24>>;
196 std::chrono::seconds r
;
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}) },
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}) },
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());
239 std::vector
<std::string
> bad
= {
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
;
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());
261 TEST(Option
, validation
)
263 Option
opt_int("foo", Option::TYPE_INT
, Option::LEVEL_BASIC
);
264 opt_int
.set_min_max(5, 10);
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
));
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
));
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")) {
282 } else if (*value
== std::string("666")) {
289 std::string input
= "666"; // An explicitly forbidden value
290 EXPECT_EQ(-EINVAL
, opt_validator
.pre_validate(&input
, &msg
));
291 EXPECT_EQ(input
, "666");
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");
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");
304 * compile-command: "cd ../.. ;
305 * make unittest_config &&
307 * --max-stackframe=20000000 --tool=memcheck \
308 * ./unittest_config # --gtest_filter=md_config_t.set_val