]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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: | |
c07f9fc5 FG |
30 | |
31 | test_md_config_t() | |
32 | : md_config_t(true), Test() | |
33 | {} | |
34 | ||
7c673cae FG |
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 "; | |
c07f9fc5 | 42 | |
7c673cae FG |
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; | |
c07f9fc5 FG |
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) | |
7c673cae | 126 | before_count++; |
c07f9fc5 | 127 | if (str.find("$data_dir") != string::npos) |
7c673cae FG |
128 | data_dir++; |
129 | } | |
130 | } | |
c07f9fc5 | 131 | |
7c673cae FG |
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; | |
c07f9fc5 FG |
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); | |
7c673cae | 142 | size_t pos = 0; |
c07f9fc5 FG |
143 | while ((pos = str.find("$", pos)) != string::npos) { |
144 | if (str.substr(pos, 8) != "$channel") { | |
7c673cae | 145 | std::cout << "unexpected meta-variable found at pos " << pos |
c07f9fc5 | 146 | << " of '" << str << "'" << std::endl; |
7c673cae FG |
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 | ||
c07f9fc5 FG |
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 | ||
7c673cae FG |
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 | */ |