1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
10 #include "options/configurable_test.h"
15 #include <unordered_map>
17 #include "options/configurable_helper.h"
18 #include "options/options_helper.h"
19 #include "options/options_parser.h"
20 #include "rocksdb/configurable.h"
21 #include "test_util/testharness.h"
22 #include "test_util/testutil.h"
25 bool FLAGS_enable_print
= false;
27 #include "util/gflags_compat.h"
28 using GFLAGS_NAMESPACE::ParseCommandLineFlags
;
29 DEFINE_bool(enable_print
, false, "Print options generated to console.");
32 namespace ROCKSDB_NAMESPACE
{
34 class StringLogger
: public Logger
{
37 void Logv(const char* format
, va_list ap
) override
{
39 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
40 string_
.append(buffer
);
42 const std::string
& str() const { return string_
; }
43 void clear() { string_
.clear(); }
48 static std::unordered_map
<std::string
, OptionTypeInfo
> struct_option_info
= {
50 {"struct", OptionTypeInfo::Struct("struct", &simple_option_info
, 0,
51 OptionVerificationType::kNormal
,
52 OptionTypeFlags::kMutable
)},
53 #endif // ROCKSDB_LITE
56 static std::unordered_map
<std::string
, OptionTypeInfo
> imm_struct_option_info
=
59 {"struct", OptionTypeInfo::Struct("struct", &simple_option_info
, 0,
60 OptionVerificationType::kNormal
,
61 OptionTypeFlags::kNone
)},
62 #endif // ROCKSDB_LITE
65 class SimpleConfigurable
: public TestConfigurable
<Configurable
> {
67 static SimpleConfigurable
* Create(
68 const std::string
& name
= "simple",
69 int mode
= TestConfigMode::kDefaultMode
,
70 const std::unordered_map
<std::string
, OptionTypeInfo
>* map
=
71 &simple_option_info
) {
72 return new SimpleConfigurable(name
, mode
, map
);
75 SimpleConfigurable(const std::string
& name
, int mode
,
76 const std::unordered_map
<std::string
, OptionTypeInfo
>*
77 map
= &simple_option_info
)
78 : TestConfigurable(name
, mode
, map
) {
79 if ((mode
& TestConfigMode::kUniqueMode
) != 0) {
80 unique_
.reset(SimpleConfigurable::Create("Unique" + name_
));
81 RegisterOptions(name_
+ "Unique", &unique_
, &unique_option_info
);
83 if ((mode
& TestConfigMode::kSharedMode
) != 0) {
84 shared_
.reset(SimpleConfigurable::Create("Shared" + name_
));
85 RegisterOptions(name_
+ "Shared", &shared_
, &shared_option_info
);
87 if ((mode
& TestConfigMode::kRawPtrMode
) != 0) {
88 pointer_
= SimpleConfigurable::Create("Pointer" + name_
);
89 RegisterOptions(name_
+ "Pointer", &pointer_
, &pointer_option_info
);
93 }; // End class SimpleConfigurable
95 using ConfigTestFactoryFunc
= std::function
<Configurable
*()>;
97 class ConfigurableTest
: public testing::Test
{
99 ConfigurableTest() { config_options_
.invoke_prepare_options
= false; }
101 ConfigOptions config_options_
;
104 TEST_F(ConfigurableTest
, GetOptionsPtrTest
) {
106 std::unique_ptr
<Configurable
> configurable(SimpleConfigurable::Create());
107 ASSERT_NE(configurable
->GetOptions
<TestOptions
>("simple"), nullptr);
108 ASSERT_EQ(configurable
->GetOptions
<TestOptions
>("bad-opt"), nullptr);
111 TEST_F(ConfigurableTest
, ConfigureFromMapTest
) {
112 std::unique_ptr
<Configurable
> configurable(SimpleConfigurable::Create());
113 auto* opts
= configurable
->GetOptions
<TestOptions
>("simple");
114 ASSERT_OK(configurable
->ConfigureFromMap(config_options_
, {}));
115 ASSERT_NE(opts
, nullptr);
117 std::unordered_map
<std::string
, std::string
> options_map
= {
118 {"int", "1"}, {"bool", "true"}, {"string", "string"}};
119 ASSERT_OK(configurable
->ConfigureFromMap(config_options_
, options_map
));
120 ASSERT_EQ(opts
->i
, 1);
121 ASSERT_EQ(opts
->b
, true);
122 ASSERT_EQ(opts
->s
, "string");
126 TEST_F(ConfigurableTest
, ConfigureFromStringTest
) {
127 std::unique_ptr
<Configurable
> configurable(SimpleConfigurable::Create());
128 auto* opts
= configurable
->GetOptions
<TestOptions
>("simple");
129 ASSERT_OK(configurable
->ConfigureFromString(config_options_
, ""));
130 ASSERT_NE(opts
, nullptr);
131 #ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
132 ASSERT_OK(configurable
->ConfigureFromString(config_options_
,
133 "int=1;bool=true;string=s"));
134 ASSERT_EQ(opts
->i
, 1);
135 ASSERT_EQ(opts
->b
, true);
136 ASSERT_EQ(opts
->s
, "s");
140 #ifndef ROCKSDB_LITE // GetOptionsFromMap is not supported in ROCKSDB_LITE
141 TEST_F(ConfigurableTest
, ConfigureIgnoreTest
) {
142 std::unique_ptr
<Configurable
> configurable(SimpleConfigurable::Create());
143 std::unordered_map
<std::string
, std::string
> options_map
= {{"unused", "u"}};
144 ConfigOptions ignore
= config_options_
;
145 ignore
.ignore_unknown_options
= true;
146 ASSERT_NOK(configurable
->ConfigureFromMap(config_options_
, options_map
));
147 ASSERT_OK(configurable
->ConfigureFromMap(ignore
, options_map
));
148 ASSERT_NOK(configurable
->ConfigureFromString(config_options_
, "unused=u"));
149 ASSERT_OK(configurable
->ConfigureFromString(ignore
, "unused=u"));
152 TEST_F(ConfigurableTest
, ConfigureNestedOptionsTest
) {
153 std::unique_ptr
<Configurable
> base
, copy
;
155 std::string mismatch
;
157 base
.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode
));
158 copy
.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode
));
159 ASSERT_OK(base
->ConfigureFromString(config_options_
,
160 "shared={int=10; string=10};"
161 "unique={int=20; string=20};"
162 "pointer={int=30; string=30};"));
163 ASSERT_OK(base
->GetOptionString(config_options_
, &opt_str
));
164 ASSERT_OK(copy
->ConfigureFromString(config_options_
, opt_str
));
165 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
168 TEST_F(ConfigurableTest
, GetOptionsTest
) {
169 std::unique_ptr
<Configurable
> simple
;
172 SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode
));
174 for (auto opt
: {"", "shared.", "unique.", "pointer."}) {
176 std::string expected
= std::to_string(i
);
177 std::string opt_name
= opt
;
179 simple
->ConfigureOption(config_options_
, opt_name
+ "int", expected
));
180 ASSERT_OK(simple
->GetOption(config_options_
, opt_name
+ "int", &value
));
181 ASSERT_EQ(expected
, value
);
182 ASSERT_OK(simple
->ConfigureOption(config_options_
, opt_name
+ "string",
184 ASSERT_OK(simple
->GetOption(config_options_
, opt_name
+ "string", &value
));
185 ASSERT_EQ(expected
, value
);
188 simple
->ConfigureOption(config_options_
, opt_name
+ "bad", expected
));
189 ASSERT_NOK(simple
->GetOption(config_options_
, "bad option", &value
));
190 ASSERT_TRUE(value
.empty());
195 TEST_F(ConfigurableTest
, ConfigureBadOptionsTest
) {
196 std::unique_ptr
<Configurable
> configurable(SimpleConfigurable::Create());
197 auto* opts
= configurable
->GetOptions
<TestOptions
>("simple");
198 ASSERT_NE(opts
, nullptr);
199 ASSERT_OK(configurable
->ConfigureOption(config_options_
, "int", "42"));
200 ASSERT_EQ(opts
->i
, 42);
201 ASSERT_NOK(configurable
->ConfigureOption(config_options_
, "int", "fred"));
202 ASSERT_NOK(configurable
->ConfigureOption(config_options_
, "bool", "fred"));
204 configurable
->ConfigureFromString(config_options_
, "int=33;unused=u"));
205 ASSERT_EQ(opts
->i
, 42);
208 TEST_F(ConfigurableTest
, InvalidOptionTest
) {
209 std::unique_ptr
<Configurable
> configurable(SimpleConfigurable::Create());
210 std::unordered_map
<std::string
, std::string
> options_map
= {
211 {"bad-option", "bad"}};
212 ASSERT_NOK(configurable
->ConfigureFromMap(config_options_
, options_map
));
214 configurable
->ConfigureFromString(config_options_
, "bad-option=bad"));
216 configurable
->ConfigureOption(config_options_
, "bad-option", "bad"));
219 static std::unordered_map
<std::string
, OptionTypeInfo
> validated_option_info
= {
222 {0, OptionType::kBoolean
, OptionVerificationType::kNormal
,
223 OptionTypeFlags::kNone
}},
224 #endif // ROCKSDB_LITE
226 static std::unordered_map
<std::string
, OptionTypeInfo
> prepared_option_info
= {
229 {0, OptionType::kInt
, OptionVerificationType::kNormal
,
230 OptionTypeFlags::kMutable
}},
231 #endif // ROCKSDB_LITE
233 static std::unordered_map
<std::string
, OptionTypeInfo
>
234 dont_prepare_option_info
= {
237 {0, OptionType::kConfigurable
, OptionVerificationType::kNormal
,
238 (OptionTypeFlags::kUnique
| OptionTypeFlags::kDontPrepare
)}},
240 #endif // ROCKSDB_LITE
243 class ValidatedConfigurable
: public SimpleConfigurable
{
245 ValidatedConfigurable(const std::string
& name
, unsigned char mode
,
246 bool dont_prepare
= false)
247 : SimpleConfigurable(name
, TestConfigMode::kDefaultMode
),
250 RegisterOptions("Validated", &validated
, &validated_option_info
);
251 RegisterOptions("Prepared", &prepared
, &prepared_option_info
);
252 if ((mode
& TestConfigMode::kUniqueMode
) != 0) {
253 unique_
.reset(new ValidatedConfigurable(
254 "Unique" + name_
, TestConfigMode::kDefaultMode
, false));
256 RegisterOptions(name_
+ "Unique", &unique_
, &dont_prepare_option_info
);
258 RegisterOptions(name_
+ "Unique", &unique_
, &unique_option_info
);
263 Status
PrepareOptions(const ConfigOptions
& config_options
) override
{
264 if (++prepared
<= 0) {
265 return Status::InvalidArgument("Cannot prepare option");
267 return SimpleConfigurable::PrepareOptions(config_options
);
271 Status
ValidateOptions(const DBOptions
& db_opts
,
272 const ColumnFamilyOptions
& cf_opts
) const override
{
274 return Status::InvalidArgument("Not Validated");
276 return SimpleConfigurable::ValidateOptions(db_opts
, cf_opts
);
285 TEST_F(ConfigurableTest
, ValidateOptionsTest
) {
286 std::unique_ptr
<Configurable
> configurable(
287 new ValidatedConfigurable("validated", TestConfigMode::kDefaultMode
));
288 ColumnFamilyOptions cf_opts
;
291 configurable
->ConfigureOption(config_options_
, "validated", "false"));
292 ASSERT_NOK(configurable
->ValidateOptions(db_opts
, cf_opts
));
294 configurable
->ConfigureOption(config_options_
, "validated", "true"));
295 ASSERT_OK(configurable
->ValidateOptions(db_opts
, cf_opts
));
298 TEST_F(ConfigurableTest
, PrepareOptionsTest
) {
299 std::unique_ptr
<Configurable
> c(
300 new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode
, false));
301 auto cp
= c
->GetOptions
<int>("Prepared");
302 auto u
= c
->GetOptions
<std::unique_ptr
<Configurable
>>("SimpleUnique");
303 auto up
= u
->get()->GetOptions
<int>("Prepared");
304 config_options_
.invoke_prepare_options
= false;
306 ASSERT_NE(cp
, nullptr);
307 ASSERT_NE(up
, nullptr);
310 ASSERT_OK(c
->ConfigureFromMap(config_options_
, {}));
313 config_options_
.invoke_prepare_options
= true;
314 ASSERT_OK(c
->ConfigureFromMap(config_options_
, {}));
317 ASSERT_OK(c
->ConfigureFromString(config_options_
, "prepared=0"));
321 ASSERT_NOK(c
->ConfigureFromString(config_options_
, "prepared=-2"));
324 new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode
, true));
325 cp
= c
->GetOptions
<int>("Prepared");
326 u
= c
->GetOptions
<std::unique_ptr
<Configurable
>>("SimpleUnique");
327 up
= u
->get()->GetOptions
<int>("Prepared");
329 ASSERT_OK(c
->ConfigureFromString(config_options_
, "prepared=0"));
334 TEST_F(ConfigurableTest
, CopyObjectTest
) {
335 class CopyConfigurable
: public Configurable
{
337 CopyConfigurable() : prepared_(0), validated_(0) {}
338 Status
PrepareOptions(const ConfigOptions
& options
) override
{
340 return Configurable::PrepareOptions(options
);
342 Status
ValidateOptions(const DBOptions
& db_opts
,
343 const ColumnFamilyOptions
& cf_opts
) const override
{
345 return Configurable::ValidateOptions(db_opts
, cf_opts
);
348 mutable int validated_
;
352 ConfigOptions config_options
;
355 ASSERT_OK(c1
.PrepareOptions(config_options
));
356 ASSERT_OK(c1
.ValidateOptions(options
, options
));
357 ASSERT_EQ(c1
.prepared_
, 1);
358 ASSERT_EQ(c1
.validated_
, 1);
359 CopyConfigurable c2
= c1
;
360 ASSERT_OK(c1
.PrepareOptions(config_options
));
361 ASSERT_OK(c1
.ValidateOptions(options
, options
));
362 ASSERT_EQ(c2
.prepared_
, 1);
363 ASSERT_EQ(c2
.validated_
, 1);
364 ASSERT_EQ(c1
.prepared_
, 2);
365 ASSERT_EQ(c1
.validated_
, 2);
368 TEST_F(ConfigurableTest
, MutableOptionsTest
) {
369 static std::unordered_map
<std::string
, OptionTypeInfo
> imm_option_info
= {
371 {"imm", OptionTypeInfo::Struct("imm", &simple_option_info
, 0,
372 OptionVerificationType::kNormal
,
373 OptionTypeFlags::kNone
)},
374 #endif // ROCKSDB_LITE
377 class MutableConfigurable
: public SimpleConfigurable
{
379 MutableConfigurable()
380 : SimpleConfigurable("mutable", TestConfigMode::kDefaultMode
|
381 TestConfigMode::kUniqueMode
|
382 TestConfigMode::kSharedMode
) {
383 RegisterOptions("struct", &options_
, &struct_option_info
);
384 RegisterOptions("imm", &options_
, &imm_option_info
);
387 MutableConfigurable mc
;
388 ConfigOptions options
= config_options_
;
390 ASSERT_OK(mc
.ConfigureOption(options
, "bool", "true"));
391 ASSERT_OK(mc
.ConfigureOption(options
, "int", "42"));
392 auto* opts
= mc
.GetOptions
<TestOptions
>("mutable");
393 ASSERT_NE(opts
, nullptr);
394 ASSERT_EQ(opts
->i
, 42);
395 ASSERT_EQ(opts
->b
, true);
396 ASSERT_OK(mc
.ConfigureOption(options
, "struct", "{bool=false;}"));
397 ASSERT_OK(mc
.ConfigureOption(options
, "imm", "{int=55;}"));
399 options
.mutable_options_only
= true;
401 // Now only mutable options should be settable.
402 ASSERT_NOK(mc
.ConfigureOption(options
, "bool", "true"));
403 ASSERT_OK(mc
.ConfigureOption(options
, "int", "24"));
404 ASSERT_EQ(opts
->i
, 24);
405 ASSERT_EQ(opts
->b
, false);
406 ASSERT_NOK(mc
.ConfigureFromString(options
, "bool=false;int=33;"));
407 ASSERT_EQ(opts
->i
, 24);
408 ASSERT_EQ(opts
->b
, false);
410 // Setting options through an immutable struct fails
411 ASSERT_NOK(mc
.ConfigureOption(options
, "imm", "{int=55;}"));
412 ASSERT_NOK(mc
.ConfigureOption(options
, "imm.int", "55"));
413 ASSERT_EQ(opts
->i
, 24);
414 ASSERT_EQ(opts
->b
, false);
416 // Setting options through an mutable struct succeeds
417 ASSERT_OK(mc
.ConfigureOption(options
, "struct", "{int=44;}"));
418 ASSERT_EQ(opts
->i
, 44);
419 ASSERT_OK(mc
.ConfigureOption(options
, "struct.int", "55"));
420 ASSERT_EQ(opts
->i
, 55);
422 // Setting nested immutable configurable options fail
423 ASSERT_NOK(mc
.ConfigureOption(options
, "shared", "{bool=true;}"));
424 ASSERT_NOK(mc
.ConfigureOption(options
, "shared.bool", "true"));
426 // Setting nested mutable configurable options succeeds
427 ASSERT_OK(mc
.ConfigureOption(options
, "unique", "{bool=true}"));
428 ASSERT_OK(mc
.ConfigureOption(options
, "unique.bool", "true"));
431 TEST_F(ConfigurableTest
, DeprecatedOptionsTest
) {
432 static std::unordered_map
<std::string
, OptionTypeInfo
>
433 deprecated_option_info
= {
435 {offsetof(struct TestOptions
, b
), OptionType::kBoolean
,
436 OptionVerificationType::kDeprecated
, OptionTypeFlags::kNone
}}};
437 std::unique_ptr
<Configurable
> orig
;
438 orig
.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode
,
439 &deprecated_option_info
));
440 auto* opts
= orig
->GetOptions
<TestOptions
>("simple");
441 ASSERT_NE(opts
, nullptr);
443 ASSERT_OK(orig
->ConfigureOption(config_options_
, "deprecated", "false"));
444 ASSERT_TRUE(opts
->d
);
445 ASSERT_OK(orig
->ConfigureFromString(config_options_
, "deprecated=false"));
446 ASSERT_TRUE(opts
->d
);
449 TEST_F(ConfigurableTest
, AliasOptionsTest
) {
450 static std::unordered_map
<std::string
, OptionTypeInfo
> alias_option_info
= {
452 {offsetof(struct TestOptions
, b
), OptionType::kBoolean
,
453 OptionVerificationType::kNormal
, OptionTypeFlags::kNone
}},
455 {offsetof(struct TestOptions
, b
), OptionType::kBoolean
,
456 OptionVerificationType::kAlias
, OptionTypeFlags::kNone
, 0}}};
457 std::unique_ptr
<Configurable
> orig
;
458 orig
.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode
,
459 &alias_option_info
));
460 auto* opts
= orig
->GetOptions
<TestOptions
>("simple");
461 ASSERT_NE(opts
, nullptr);
462 ASSERT_OK(orig
->ConfigureOption(config_options_
, "bool", "false"));
463 ASSERT_FALSE(opts
->b
);
464 ASSERT_OK(orig
->ConfigureOption(config_options_
, "alias", "true"));
465 ASSERT_TRUE(opts
->b
);
466 std::string opts_str
;
467 ASSERT_OK(orig
->GetOptionString(config_options_
, &opts_str
));
468 ASSERT_EQ(opts_str
.find("alias"), std::string::npos
);
470 ASSERT_OK(orig
->ConfigureOption(config_options_
, "bool", "false"));
471 ASSERT_FALSE(opts
->b
);
472 ASSERT_OK(orig
->GetOption(config_options_
, "alias", &opts_str
));
473 ASSERT_EQ(opts_str
, "false");
476 TEST_F(ConfigurableTest
, NestedUniqueConfigTest
) {
477 std::unique_ptr
<Configurable
> simple
;
479 SimpleConfigurable::Create("Outer", TestConfigMode::kAllOptMode
));
480 const auto outer
= simple
->GetOptions
<TestOptions
>("Outer");
482 simple
->GetOptions
<std::unique_ptr
<Configurable
>>("OuterUnique");
483 ASSERT_NE(outer
, nullptr);
484 ASSERT_NE(unique
, nullptr);
486 simple
->ConfigureFromString(config_options_
, "int=24;string=outer"));
487 ASSERT_OK(simple
->ConfigureFromString(config_options_
,
488 "unique={int=42;string=nested}"));
489 const auto inner
= unique
->get()->GetOptions
<TestOptions
>("UniqueOuter");
490 ASSERT_NE(inner
, nullptr);
491 ASSERT_EQ(outer
->i
, 24);
492 ASSERT_EQ(outer
->s
, "outer");
493 ASSERT_EQ(inner
->i
, 42);
494 ASSERT_EQ(inner
->s
, "nested");
497 TEST_F(ConfigurableTest
, NestedSharedConfigTest
) {
498 std::unique_ptr
<Configurable
> simple
;
499 simple
.reset(SimpleConfigurable::Create(
500 "Outer", TestConfigMode::kDefaultMode
| TestConfigMode::kSharedMode
));
502 simple
->ConfigureFromString(config_options_
, "int=24;string=outer"));
503 ASSERT_OK(simple
->ConfigureFromString(config_options_
,
504 "shared={int=42;string=nested}"));
505 const auto outer
= simple
->GetOptions
<TestOptions
>("Outer");
507 simple
->GetOptions
<std::shared_ptr
<Configurable
>>("OuterShared");
508 ASSERT_NE(outer
, nullptr);
509 ASSERT_NE(shared
, nullptr);
510 const auto inner
= shared
->get()->GetOptions
<TestOptions
>("SharedOuter");
511 ASSERT_NE(inner
, nullptr);
512 ASSERT_EQ(outer
->i
, 24);
513 ASSERT_EQ(outer
->s
, "outer");
514 ASSERT_EQ(inner
->i
, 42);
515 ASSERT_EQ(inner
->s
, "nested");
518 TEST_F(ConfigurableTest
, NestedRawConfigTest
) {
519 std::unique_ptr
<Configurable
> simple
;
520 simple
.reset(SimpleConfigurable::Create(
521 "Outer", TestConfigMode::kDefaultMode
| TestConfigMode::kRawPtrMode
));
523 simple
->ConfigureFromString(config_options_
, "int=24;string=outer"));
524 ASSERT_OK(simple
->ConfigureFromString(config_options_
,
525 "pointer={int=42;string=nested}"));
526 const auto outer
= simple
->GetOptions
<TestOptions
>("Outer");
527 const auto pointer
= simple
->GetOptions
<Configurable
*>("OuterPointer");
528 ASSERT_NE(outer
, nullptr);
529 ASSERT_NE(pointer
, nullptr);
530 const auto inner
= (*pointer
)->GetOptions
<TestOptions
>("PointerOuter");
531 ASSERT_NE(inner
, nullptr);
532 ASSERT_EQ(outer
->i
, 24);
533 ASSERT_EQ(outer
->s
, "outer");
534 ASSERT_EQ(inner
->i
, 42);
535 ASSERT_EQ(inner
->s
, "nested");
538 TEST_F(ConfigurableTest
, MatchesTest
) {
539 std::string mismatch
;
540 std::unique_ptr
<Configurable
> base
, copy
;
541 base
.reset(SimpleConfigurable::Create(
542 "simple", TestConfigMode::kDefaultMode
| TestConfigMode::kNestedMode
));
543 copy
.reset(SimpleConfigurable::Create(
544 "simple", TestConfigMode::kDefaultMode
| TestConfigMode::kNestedMode
));
545 ASSERT_OK(base
->ConfigureFromString(
547 "int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}"));
548 ASSERT_OK(copy
->ConfigureFromString(
550 "int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}"));
551 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
552 ASSERT_OK(base
->ConfigureOption(config_options_
, "shared", "int=44"));
553 ASSERT_FALSE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
554 ASSERT_EQ(mismatch
, "shared.int");
555 std::string c1value
, c2value
;
556 ASSERT_OK(base
->GetOption(config_options_
, mismatch
, &c1value
));
557 ASSERT_OK(copy
->GetOption(config_options_
, mismatch
, &c2value
));
558 ASSERT_NE(c1value
, c2value
);
561 static Configurable
* SimpleStructFactory() {
562 return SimpleConfigurable::Create(
563 "simple-struct", TestConfigMode::kDefaultMode
, &struct_option_info
);
566 TEST_F(ConfigurableTest
, ConfigureStructTest
) {
567 std::unique_ptr
<Configurable
> base(SimpleStructFactory());
568 std::unique_ptr
<Configurable
> copy(SimpleStructFactory());
569 std::string opt_str
, value
;
570 std::string mismatch
;
571 std::unordered_set
<std::string
> names
;
574 base
->ConfigureFromString(config_options_
, "struct={int=10; string=10}"));
575 ASSERT_OK(base
->GetOptionString(config_options_
, &opt_str
));
576 ASSERT_OK(copy
->ConfigureFromString(config_options_
, opt_str
));
577 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
578 ASSERT_OK(base
->GetOptionNames(config_options_
, &names
));
579 ASSERT_EQ(names
.size(), 1);
580 ASSERT_EQ(*(names
.begin()), "struct");
582 base
->ConfigureFromString(config_options_
, "struct={int=20; string=20}"));
583 ASSERT_OK(base
->GetOption(config_options_
, "struct", &value
));
584 ASSERT_OK(copy
->ConfigureOption(config_options_
, "struct", value
));
585 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
587 ASSERT_NOK(base
->ConfigureFromString(config_options_
,
588 "struct={int=10; string=10; bad=11}"));
589 ASSERT_OK(base
->ConfigureOption(config_options_
, "struct.int", "42"));
590 ASSERT_NOK(base
->ConfigureOption(config_options_
, "struct.bad", "42"));
591 ASSERT_NOK(base
->GetOption(config_options_
, "struct.bad", &value
));
592 ASSERT_OK(base
->GetOption(config_options_
, "struct.int", &value
));
593 ASSERT_EQ(value
, "42");
596 TEST_F(ConfigurableTest
, ConfigurableEnumTest
) {
597 std::unique_ptr
<Configurable
> base
, copy
;
598 base
.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode
));
599 copy
.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode
));
601 std::string opts_str
;
602 std::string mismatch
;
604 ASSERT_OK(base
->ConfigureFromString(config_options_
, "enum=B"));
605 ASSERT_FALSE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
606 ASSERT_OK(base
->GetOptionString(config_options_
, &opts_str
));
607 ASSERT_OK(copy
->ConfigureFromString(config_options_
, opts_str
));
608 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
609 ASSERT_NOK(base
->ConfigureOption(config_options_
, "enum", "bad"));
610 ASSERT_NOK(base
->ConfigureOption(config_options_
, "unknown", "bad"));
614 static std::unordered_map
<std::string
, OptionTypeInfo
> noserialize_option_info
=
617 {offsetof(struct TestOptions
, i
), OptionType::kInt
,
618 OptionVerificationType::kNormal
, OptionTypeFlags::kDontSerialize
}},
621 TEST_F(ConfigurableTest
, TestNoSerialize
) {
622 std::unique_ptr
<Configurable
> base
;
623 base
.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode
,
624 &noserialize_option_info
));
625 std::string opts_str
, value
;
626 ASSERT_OK(base
->ConfigureFromString(config_options_
, "int=10"));
627 ASSERT_OK(base
->GetOptionString(config_options_
, &opts_str
));
628 ASSERT_EQ(opts_str
, "");
629 ASSERT_NOK(base
->GetOption(config_options_
, "int", &value
));
632 TEST_F(ConfigurableTest
, TestNoCompare
) {
633 std::unordered_map
<std::string
, OptionTypeInfo
> nocomp_option_info
= {
635 {offsetof(struct TestOptions
, i
), OptionType::kInt
,
636 OptionVerificationType::kNormal
, OptionTypeFlags::kCompareNever
}},
638 std::unordered_map
<std::string
, OptionTypeInfo
> normal_option_info
= {
640 {offsetof(struct TestOptions
, i
), OptionType::kInt
,
641 OptionVerificationType::kNormal
, OptionTypeFlags::kNone
}},
644 std::unique_ptr
<Configurable
> base
, copy
;
645 base
.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode
,
646 &nocomp_option_info
));
647 copy
.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode
,
648 &normal_option_info
));
649 ASSERT_OK(base
->ConfigureFromString(config_options_
, "int=10"));
650 ASSERT_OK(copy
->ConfigureFromString(config_options_
, "int=20"));
651 std::string bvalue
, cvalue
, mismatch
;
652 ASSERT_OK(base
->GetOption(config_options_
, "int", &bvalue
));
653 ASSERT_OK(copy
->GetOption(config_options_
, "int", &cvalue
));
654 ASSERT_EQ(bvalue
, "10");
655 ASSERT_EQ(cvalue
, "20");
656 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
657 ASSERT_FALSE(copy
->AreEquivalent(config_options_
, base
.get(), &mismatch
));
660 TEST_F(ConfigurableTest
, NullOptionMapTest
) {
661 std::unique_ptr
<Configurable
> base
;
662 std::unordered_set
<std::string
> names
;
666 SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode
, nullptr));
667 ASSERT_NOK(base
->ConfigureFromString(config_options_
, "int=10"));
668 ASSERT_NOK(base
->ConfigureFromString(config_options_
, "int=20"));
669 ASSERT_NOK(base
->ConfigureOption(config_options_
, "int", "20"));
670 ASSERT_NOK(base
->GetOption(config_options_
, "int", &str
));
671 ASSERT_NE(base
->GetOptions
<TestOptions
>("c"), nullptr);
672 ASSERT_OK(base
->GetOptionNames(config_options_
, &names
));
673 ASSERT_EQ(names
.size(), 0UL);
674 ASSERT_OK(base
->PrepareOptions(config_options_
));
675 ASSERT_OK(base
->ValidateOptions(DBOptions(), ColumnFamilyOptions()));
676 std::unique_ptr
<Configurable
> copy
;
678 SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode
, nullptr));
679 ASSERT_OK(base
->GetOptionString(config_options_
, &str
));
680 ASSERT_OK(copy
->ConfigureFromString(config_options_
, str
));
681 ASSERT_TRUE(base
->AreEquivalent(config_options_
, copy
.get(), &str
));
685 static std::unordered_map
<std::string
, ConfigTestFactoryFunc
> TestFactories
= {
686 {"Simple", []() { return SimpleConfigurable::Create("simple"); }},
687 {"Struct", []() { return SimpleStructFactory(); }},
690 return SimpleConfigurable::Create(
691 "simple", TestConfigMode::kSimpleMode
| TestConfigMode::kUniqueMode
);
695 return SimpleConfigurable::Create(
696 "simple", TestConfigMode::kSimpleMode
| TestConfigMode::kSharedMode
);
700 return SimpleConfigurable::Create(
701 "simple", TestConfigMode::kSimpleMode
| TestConfigMode::kNestedMode
);
705 return SimpleConfigurable::Create("simple",
706 TestConfigMode::kMutableMode
|
707 TestConfigMode::kSimpleMode
|
708 TestConfigMode::kNestedMode
);
712 Configurable
* simple
= SimpleConfigurable::Create(
714 TestConfigMode::kUniqueMode
| TestConfigMode::kDefaultMode
);
716 simple
->GetOptions
<std::unique_ptr
<Configurable
>>("SimpleUnique");
717 unique
->reset(SimpleConfigurable::Create(
719 TestConfigMode::kUniqueMode
| TestConfigMode::kDefaultMode
));
720 unique
= unique
->get()->GetOptions
<std::unique_ptr
<Configurable
>>(
723 SimpleConfigurable::Create("Child", TestConfigMode::kDefaultMode
));
728 auto config
= DBOptionsAsConfigurable(DBOptions());
729 return config
.release();
733 auto config
= CFOptionsAsConfigurable(ColumnFamilyOptions());
734 return config
.release();
736 {"BlockBased", []() { return NewBlockBasedTableFactory(); }},
739 class ConfigurableParamTest
: public ConfigurableTest
,
740 virtual public ::testing::WithParamInterface
<
741 std::pair
<std::string
, std::string
>> {
743 ConfigurableParamTest() {
744 type_
= GetParam().first
;
745 configuration_
= GetParam().second
;
746 assert(TestFactories
.find(type_
) != TestFactories
.end());
747 object_
.reset(CreateConfigurable());
750 Configurable
* CreateConfigurable() {
751 const auto& iter
= TestFactories
.find(type_
);
752 return (iter
->second
)();
755 void TestConfigureOptions(const ConfigOptions
& opts
);
757 std::string configuration_
;
758 std::unique_ptr
<Configurable
> object_
;
761 void ConfigurableParamTest::TestConfigureOptions(
762 const ConfigOptions
& config_options
) {
763 std::unique_ptr
<Configurable
> base
, copy
;
764 std::unordered_set
<std::string
> names
;
765 std::string opt_str
, mismatch
;
767 base
.reset(CreateConfigurable());
768 copy
.reset(CreateConfigurable());
770 ASSERT_OK(base
->ConfigureFromString(config_options
, configuration_
));
771 ASSERT_OK(base
->GetOptionString(config_options
, &opt_str
));
772 ASSERT_OK(copy
->ConfigureFromString(config_options
, opt_str
));
773 ASSERT_OK(copy
->GetOptionString(config_options
, &opt_str
));
774 ASSERT_TRUE(base
->AreEquivalent(config_options
, copy
.get(), &mismatch
));
776 copy
.reset(CreateConfigurable());
777 ASSERT_OK(base
->GetOptionNames(config_options
, &names
));
778 std::unordered_map
<std::string
, std::string
> unused
;
779 bool found_one
= false;
780 for (auto name
: names
) {
782 Status s
= base
->GetOption(config_options
, name
, &value
);
784 s
= copy
->ConfigureOption(config_options
, name
, value
);
785 if (s
.ok() || s
.IsNotSupported()) {
788 unused
[name
] = value
;
791 ASSERT_TRUE(s
.IsNotSupported());
794 ASSERT_TRUE(found_one
|| names
.empty());
795 while (found_one
&& !unused
.empty()) {
797 for (auto iter
= unused
.begin(); iter
!= unused
.end();) {
798 if (copy
->ConfigureOption(config_options
, iter
->first
, iter
->second
)
801 iter
= unused
.erase(iter
);
807 ASSERT_EQ(0, unused
.size());
808 ASSERT_TRUE(base
->AreEquivalent(config_options
, copy
.get(), &mismatch
));
811 TEST_P(ConfigurableParamTest
, GetDefaultOptionsTest
) {
812 TestConfigureOptions(config_options_
);
815 TEST_P(ConfigurableParamTest
, ConfigureFromPropsTest
) {
816 std::string opt_str
, mismatch
;
817 std::unordered_set
<std::string
> names
;
818 std::unique_ptr
<Configurable
> copy(CreateConfigurable());
820 ASSERT_OK(object_
->ConfigureFromString(config_options_
, configuration_
));
821 config_options_
.delimiter
= "\n";
822 ASSERT_OK(object_
->GetOptionString(config_options_
, &opt_str
));
823 std::istringstream
iss(opt_str
);
824 std::unordered_map
<std::string
, std::string
> copy_map
;
826 for (int line_num
= 0; std::getline(iss
, line
); line_num
++) {
830 RocksDBOptionsParser::ParseStatement(&name
, &value
, line
, line_num
));
831 copy_map
[name
] = value
;
833 ASSERT_OK(copy
->ConfigureFromMap(config_options_
, copy_map
));
834 ASSERT_TRUE(object_
->AreEquivalent(config_options_
, copy
.get(), &mismatch
));
837 INSTANTIATE_TEST_CASE_P(
838 ParamTest
, ConfigurableParamTest
,
840 std::pair
<std::string
, std::string
>("Simple",
841 "int=42;bool=true;string=s"),
842 std::pair
<std::string
, std::string
>(
843 "Mutable", "int=42;unique={int=33;string=unique}"),
844 std::pair
<std::string
, std::string
>(
845 "Struct", "struct={int=33;bool=true;string=s;}"),
846 std::pair
<std::string
, std::string
>("Shared",
847 "int=33;bool=true;string=outer;"
848 "shared={int=42;string=shared}"),
849 std::pair
<std::string
, std::string
>("Unique",
850 "int=33;bool=true;string=outer;"
851 "unique={int=42;string=unique}"),
852 std::pair
<std::string
, std::string
>("Nested",
853 "int=11;bool=true;string=outer;"
854 "pointer={int=22;string=pointer};"
855 "unique={int=33;string=unique};"
856 "shared={int=44;string=shared}"),
857 std::pair
<std::string
, std::string
>("ThreeDeep",
858 "int=11;bool=true;string=outer;"
859 "unique={int=22;string=inner;"
860 "unique={int=33;string=unique}};"),
861 std::pair
<std::string
, std::string
>("DBOptions",
862 "max_background_jobs=100;"
863 "max_open_files=200;"),
864 std::pair
<std::string
, std::string
>("CFOptions",
865 "table_factory=BlockBasedTable;"
866 "disable_auto_compactions=true;"),
867 std::pair
<std::string
, std::string
>("BlockBased",
869 "no_block_cache=true;")));
870 #endif // ROCKSDB_LITE
873 } // namespace ROCKSDB_NAMESPACE
874 int main(int argc
, char** argv
) {
875 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
876 ::testing::InitGoogleTest(&argc
, argv
);
878 ParseCommandLineFlags(&argc
, &argv
, true);
880 return RUN_ALL_TESTS();