]>
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
, set_val
)
137 ConfigProxy conf
{false};
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
));
148 // set_val should support SI conversion
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"));
156 // set_val should support 1 days 2 hours 4 minutes
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());
171 using namespace std::chrono
;
173 using days_t
= duration
<int, std::ratio
<3600 * 24>>;
177 std::chrono::seconds r
;
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}) },
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}) },
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());
220 std::vector
<std::string
> bad
= {
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
;
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());
242 TEST(Option
, validation
)
244 Option
opt_int("foo", Option::TYPE_INT
, Option::LEVEL_BASIC
);
245 opt_int
.set_min_max(5, 10);
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
));
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
));
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")) {
263 } else if (*value
== std::string("666")) {
270 std::string input
= "666"; // An explicitly forbidden value
271 EXPECT_EQ(-EINVAL
, opt_validator
.pre_validate(&input
, &msg
));
272 EXPECT_EQ(input
, "666");
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");
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");
285 * compile-command: "cd ../.. ;
286 * make unittest_config &&
288 * --max-stackframe=20000000 --tool=memcheck \
289 * ./unittest_config # --gtest_filter=md_config_t.set_val