]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/confutils.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) 2011 New Dream Network
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
14 #include "common/ConfUtils.h"
15 #include "common/config.h"
16 #include "common/errno.h"
17 #include "gtest/gtest.h"
18 #include "include/buffer.h"
26 #include <sys/types.h>
27 #include "include/memory.h"
29 using ceph::bufferlist
;
31 using std::ostringstream
;
33 #define MAX_FILES_TO_DELETE 1000UL
35 static size_t config_idx
= 0;
36 static size_t unlink_idx
= 0;
37 static char *to_unlink
[MAX_FILES_TO_DELETE
];
39 static std::string
get_temp_dir()
41 static std::string temp_dir
;
43 if (temp_dir
.empty()) {
44 const char *tmpdir
= getenv("TMPDIR");
49 oss
<< tmpdir
<< "/confutils_test_dir." << rand() << "." << getpid();
51 int res
= mkdir(oss
.str().c_str(), 01777);
53 cerr
<< "failed to create temp directory '" << temp_dir
<< "'" << std::endl
;
61 static void unlink_all(void)
63 for (size_t i
= 0; i
< unlink_idx
; ++i
) {
66 for (size_t i
= 0; i
< unlink_idx
; ++i
) {
69 rmdir(get_temp_dir().c_str());
72 static int create_tempfile(const std::string
&fname
, const char *text
)
74 FILE *fp
= fopen(fname
.c_str(), "w");
77 cerr
<< "Failed to write file '" << fname
<< "' to temp directory '"
78 << get_temp_dir() << "'. " << cpp_strerror(err
) << std::endl
;
81 ceph::shared_ptr
<FILE> fpp(fp
, fclose
);
82 if (unlink_idx
>= MAX_FILES_TO_DELETE
)
84 if (unlink_idx
== 0) {
85 memset(to_unlink
, 0, sizeof(to_unlink
));
88 to_unlink
[unlink_idx
++] = strdup(fname
.c_str());
89 size_t strlen_text
= strlen(text
);
90 size_t res
= fwrite(text
, 1, strlen_text
, fp
);
91 if (res
!= strlen_text
) {
93 cerr
<< "fwrite error while writing to " << fname
94 << ": " << cpp_strerror(err
) << std::endl
;
100 static std::string
next_tempfile(const char *text
)
103 std::string
temp_dir(get_temp_dir());
104 if (temp_dir
.empty())
106 oss
<< temp_dir
<< "/test_config." << config_idx
++ << ".config";
107 int ret
= create_tempfile(oss
.str(), text
);
113 const char * const trivial_conf_1
= "";
115 const char * const trivial_conf_2
= "log dir = foobar";
117 const char * const trivial_conf_3
= "log dir = barfoo\n";
119 const char * const trivial_conf_4
= "log dir = \"barbaz\"\n";
121 const char * const simple_conf_1
= "\
122 ; here's a comment\n\
124 keyring = .my_ceph_keyring\n\
128 log per instance = true\n\
129 log sym history = 100\n\
130 profiling logger = true\n\
131 profiling logger dir = wowsers\n\
133 pid file = out/$name.pid\n\
135 mds debug frag = true\n\
137 pid file = out/$name.pid\n\
138 osd scrub load threshold = 5.0\n\
142 osd data = dev/osd0\n\
143 osd journal size = 100\n\
149 // we can add whitespace at odd locations and it will get stripped out.
150 const char * const simple_conf_2
= "\
152 log dir = special_mds_a\n\
154 log sym history = 100\n\
155 log dir = out # after a comment, anything # can ### happen ;;; right?\n\
156 log per instance = true\n\
157 profiling logger = true\n\
158 profiling logger dir = log\n\
162 keyring = osd_keyring ; osd's keyring\n\
166 # I like pound signs as comment markers.\n\
167 ; Do you like pound signs as comment markers?\n\
168 keyring = shenanigans ; The keyring of a leprechaun\n\
170 # Let's just have a line with a lot of whitespace and nothing else.\n\
175 // test line-combining
176 const char * const conf3
= "\
178 log file = /quite/a/long/path\\\n\
183 [mon] #nothing here \n\
186 const char * const escaping_conf_1
= "\
188 log file = the \"scare quotes\"\n\
192 keyring = \"nested \\\"quotes\\\"\"\n\
195 const char * const escaping_conf_2
= "\
197 log file = floppy disk\n\
199 keyring = \"backslash\\\\\"\n\
202 // illegal because it contains an invalid utf8 sequence.
203 const char illegal_conf1
[] = "\
206 pid file = invalid-utf-\xe2\x28\xa1\n\
208 keyring = osd_keyring ; osd's keyring\n\
211 // illegal because it contains a malformed section header.
212 const char illegal_conf2
[] = "\
216 keyring = osd_keyring ; osd's keyring\n\
219 // illegal because it contains a line that doesn't parse
220 const char illegal_conf3
[] = "\
224 keyring = osd_keyring ; osd's keyring\n\
227 // illegal because it has unterminated quotes
228 const char illegal_conf4
[] = "\
230 keyring = \"unterminated quoted string\n\
232 keyring = osd_keyring ; osd's keyring\n\
235 // illegal because it has a backslash at the very end
236 const char illegal_conf5
[] = "\
238 keyring = something awful\\\\\n\
241 // unicode config file
242 const char unicode_config_1
[] = "\
244 log file = \x66\xd1\x86\xd1\x9d\xd3\xad\xd3\xae \n\
245 pid file = foo-bar\n\
249 const char override_config_1
[] = "\
251 log file = global_log\n\
253 log file = mds_log\n\
255 log file = osd_log\n\
257 log file = osd0_log\n\
260 const char dup_key_config_1
[] = "\
266 TEST(ConfUtils
, Whitespace
) {
267 std::string
test0("");
268 ConfFile::trim_whitespace(test0
, false);
269 ASSERT_EQ(test0
, "");
271 std::string
test0a("");
272 ConfFile::trim_whitespace(test0a
, true);
273 ASSERT_EQ(test0a
, "");
275 std::string
test0b(" ");
276 ConfFile::trim_whitespace(test0b
, false);
277 ASSERT_EQ(test0b
, "");
279 std::string
test0c(" ");
280 ConfFile::trim_whitespace(test0c
, true);
281 ASSERT_EQ(test0c
, "");
283 std::string
test1(" abc ");
284 ConfFile::trim_whitespace(test1
, false);
285 ASSERT_EQ(test1
, "abc");
287 std::string
test2(" abc d ");
288 ConfFile::trim_whitespace(test2
, true);
289 ASSERT_EQ(test2
, "abc d");
291 std::string
test3(" abc d ");
292 ConfFile::trim_whitespace(test3
, false);
293 ASSERT_EQ(test3
, "abc d");
295 std::string
test4("abcd");
296 ConfFile::trim_whitespace(test4
, false);
297 ASSERT_EQ(test4
, "abcd");
299 std::string
test5("abcd");
300 ConfFile::trim_whitespace(test5
, true);
301 ASSERT_EQ(test5
, "abcd");
304 TEST(ConfUtils
, ParseFiles0
) {
305 std::deque
<std::string
> err
;
307 std::ostringstream warn
;
309 std::string
trivial_conf_1_f(next_tempfile(trivial_conf_1
));
311 ASSERT_EQ(cf1
.parse_file(trivial_conf_1_f
.c_str(), &err
, &warn
), 0);
312 ASSERT_EQ(err
.size(), 0U);
314 std::string
trivial_conf_2_f(next_tempfile(trivial_conf_2
));
316 ASSERT_EQ(cf2
.parse_file(trivial_conf_2_f
.c_str(), &err
, &warn
), 0);
317 ASSERT_EQ(err
.size(), 1U);
320 bl3
.append(trivial_conf_3
, strlen(trivial_conf_3
));
322 ASSERT_EQ(cf3
.parse_bufferlist(&bl3
, &err
, &warn
), 0);
323 ASSERT_EQ(err
.size(), 0U);
324 ASSERT_EQ(cf3
.read("global", "log dir", val
), 0);
325 ASSERT_EQ(val
, "barfoo");
327 std::string
trivial_conf_4_f(next_tempfile(trivial_conf_4
));
329 ASSERT_EQ(cf4
.parse_file(trivial_conf_4_f
.c_str(), &err
, &warn
), 0);
330 ASSERT_EQ(err
.size(), 0U);
331 ASSERT_EQ(cf4
.read("global", "log dir", val
), 0);
332 ASSERT_EQ(val
, "barbaz");
335 TEST(ConfUtils
, ParseFiles1
) {
336 std::deque
<std::string
> err
;
337 std::ostringstream warn
;
338 std::string
simple_conf_1_f(next_tempfile(simple_conf_1
));
340 ASSERT_EQ(cf1
.parse_file(simple_conf_1_f
.c_str(), &err
, &warn
), 0);
341 ASSERT_EQ(err
.size(), 0U);
343 std::string
simple_conf_2_f(next_tempfile(simple_conf_1
));
345 ASSERT_EQ(cf2
.parse_file(simple_conf_2_f
.c_str(), &err
, &warn
), 0);
346 ASSERT_EQ(err
.size(), 0U);
349 bl3
.append(simple_conf_1
, strlen(simple_conf_1
));
351 ASSERT_EQ(cf3
.parse_bufferlist(&bl3
, &err
, &warn
), 0);
352 ASSERT_EQ(err
.size(), 0U);
355 bl4
.append(simple_conf_2
, strlen(simple_conf_2
));
357 ASSERT_EQ(cf4
.parse_bufferlist(&bl4
, &err
, &warn
), 0);
358 ASSERT_EQ(err
.size(), 0U);
361 TEST(ConfUtils
, ReadFiles1
) {
362 std::deque
<std::string
> err
;
363 std::ostringstream warn
;
364 std::string
simple_conf_1_f(next_tempfile(simple_conf_1
));
366 ASSERT_EQ(cf1
.parse_file(simple_conf_1_f
.c_str(), &err
, &warn
), 0);
367 ASSERT_EQ(err
.size(), 0U);
370 ASSERT_EQ(cf1
.read("global", "keyring", val
), 0);
371 ASSERT_EQ(val
, ".my_ceph_keyring");
373 ASSERT_EQ(cf1
.read("mds", "profiling logger dir", val
), 0);
374 ASSERT_EQ(val
, "wowsers");
376 ASSERT_EQ(cf1
.read("mds", "something that does not exist", val
), -ENOENT
);
378 // exists in mds section, but not in global
379 ASSERT_EQ(cf1
.read("global", "profiling logger dir", val
), -ENOENT
);
382 bl2
.append(simple_conf_2
, strlen(simple_conf_2
));
384 ASSERT_EQ(cf2
.parse_bufferlist(&bl2
, &err
, &warn
), 0);
385 ASSERT_EQ(err
.size(), 0U);
386 ASSERT_EQ(cf2
.read("osd0", "keyring", val
), 0);
387 ASSERT_EQ(val
, "osd_keyring");
389 ASSERT_EQ(cf2
.read("mds", "pid file", val
), 0);
390 ASSERT_EQ(val
, "foo2");
391 ASSERT_EQ(cf2
.read("nonesuch", "keyring", val
), -ENOENT
);
394 TEST(ConfUtils
, ReadFiles2
) {
395 std::deque
<std::string
> err
;
396 std::ostringstream warn
;
397 std::string
conf3_f(next_tempfile(conf3
));
400 ASSERT_EQ(cf1
.parse_file(conf3_f
.c_str(), &err
, &warn
), 0);
401 ASSERT_EQ(err
.size(), 0U);
402 ASSERT_EQ(cf1
.read("global", "log file", val
), 0);
403 ASSERT_EQ(val
, "/quite/a/long/path/for/a/log/file");
404 ASSERT_EQ(cf1
.read("global", "pid file", val
), 0);
405 ASSERT_EQ(val
, "spork");
407 std::string
unicode_config_1f(next_tempfile(unicode_config_1
));
409 ASSERT_EQ(cf2
.parse_file(unicode_config_1f
.c_str(), &err
, &warn
), 0);
410 ASSERT_EQ(err
.size(), 0U);
411 ASSERT_EQ(cf2
.read("global", "log file", val
), 0);
412 ASSERT_EQ(val
, "\x66\xd1\x86\xd1\x9d\xd3\xad\xd3\xae");
415 TEST(ConfUtils
, IllegalFiles
) {
416 std::deque
<std::string
> err
;
417 std::ostringstream warn
;
418 std::string
illegal_conf1_f(next_tempfile(illegal_conf1
));
420 ASSERT_EQ(cf1
.parse_file(illegal_conf1_f
.c_str(), &err
, &warn
), 0);
421 ASSERT_EQ(err
.size(), 1U);
424 bl2
.append(illegal_conf2
, strlen(illegal_conf2
));
426 ASSERT_EQ(cf2
.parse_bufferlist(&bl2
, &err
, &warn
), 0);
427 ASSERT_EQ(err
.size(), 1U);
429 std::string
illegal_conf3_f(next_tempfile(illegal_conf3
));
431 ASSERT_EQ(cf3
.parse_file(illegal_conf3_f
.c_str(), &err
, &warn
), 0);
432 ASSERT_EQ(err
.size(), 1U);
434 std::string
illegal_conf4_f(next_tempfile(illegal_conf4
));
436 ASSERT_EQ(cf4
.parse_file(illegal_conf4_f
.c_str(), &err
, &warn
), 0);
437 ASSERT_EQ(err
.size(), 1U);
439 std::string
illegal_conf5_f(next_tempfile(illegal_conf5
));
441 ASSERT_EQ(cf5
.parse_file(illegal_conf5_f
.c_str(), &err
, &warn
), 0);
442 ASSERT_EQ(err
.size(), 1U);
445 TEST(ConfUtils
, EscapingFiles
) {
446 std::deque
<std::string
> err
;
447 std::ostringstream warn
;
448 std::string
escaping_conf_1_f(next_tempfile(escaping_conf_1
));
451 ASSERT_EQ(cf1
.parse_file(escaping_conf_1_f
.c_str(), &err
, &warn
), 0);
452 ASSERT_EQ(err
.size(), 0U);
454 ASSERT_EQ(cf1
.read("global", "log file", val
), 0);
455 ASSERT_EQ(val
, "the \"scare quotes\"");
456 ASSERT_EQ(cf1
.read("global", "pid file", val
), 0);
457 ASSERT_EQ(val
, "a pid file");
458 ASSERT_EQ(cf1
.read("mon", "keyring", val
), 0);
459 ASSERT_EQ(val
, "nested \"quotes\"");
461 std::string
escaping_conf_2_f(next_tempfile(escaping_conf_2
));
463 ASSERT_EQ(cf2
.parse_file(escaping_conf_2_f
.c_str(), &err
, &warn
), 0);
464 ASSERT_EQ(err
.size(), 0U);
466 ASSERT_EQ(cf2
.read("apple ][", "log file", val
), 0);
467 ASSERT_EQ(val
, "floppy disk");
468 ASSERT_EQ(cf2
.read("mon", "keyring", val
), 0);
469 ASSERT_EQ(val
, "backslash\\");
472 TEST(ConfUtils
, Overrides
) {
474 std::ostringstream warn
;
475 std::string
override_conf_1_f(next_tempfile(override_config_1
));
477 conf
.name
.set(CEPH_ENTITY_TYPE_MON
, "0");
478 conf
.parse_config_files(override_conf_1_f
.c_str(), &warn
, 0);
479 ASSERT_EQ(conf
.parse_errors
.size(), 0U);
480 ASSERT_EQ(conf
.log_file
, "global_log");
482 conf
.name
.set(CEPH_ENTITY_TYPE_MDS
, "a");
483 conf
.parse_config_files(override_conf_1_f
.c_str(), &warn
, 0);
484 ASSERT_EQ(conf
.parse_errors
.size(), 0U);
485 ASSERT_EQ(conf
.log_file
, "mds_log");
487 conf
.name
.set(CEPH_ENTITY_TYPE_OSD
, "0");
488 conf
.parse_config_files(override_conf_1_f
.c_str(), &warn
, 0);
489 ASSERT_EQ(conf
.parse_errors
.size(), 0U);
490 ASSERT_EQ(conf
.log_file
, "osd0_log");
493 TEST(ConfUtils
, DupKey
) {
495 std::ostringstream warn
;
496 std::string
dup_key_config_f(next_tempfile(dup_key_config_1
));
498 conf
.name
.set(CEPH_ENTITY_TYPE_MDS
, "a");
499 conf
.parse_config_files(dup_key_config_f
.c_str(), &warn
, 0);
500 ASSERT_EQ(conf
.parse_errors
.size(), 0U);
501 ASSERT_EQ(conf
.log_file
, string("3"));