Packages
rocksdb
3.0.0
3.1.2
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Current section
Files
Jump to
Current section
Files
deps/rocksdb/options/configurable_test.cc
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include "options/configurable_test.h"
#include <cctype>
#include <cinttypes>
#include <cstring>
#include <unordered_map>
#include "options/configurable_helper.h"
#include "options/options_helper.h"
#include "options/options_parser.h"
#include "rocksdb/configurable.h"
#include "test_util/testharness.h"
#include "test_util/testutil.h"
#ifndef GFLAGS
bool FLAGS_enable_print = false;
#else
#include "util/gflags_compat.h"
using GFLAGS_NAMESPACE::ParseCommandLineFlags;
DEFINE_bool(enable_print, false, "Print options generated to console.");
#endif // GFLAGS
namespace ROCKSDB_NAMESPACE::test {
class StringLogger : public Logger {
public:
using Logger::Logv;
void Logv(const char* format, va_list ap) override {
char buffer[1000];
vsnprintf(buffer, sizeof(buffer), format, ap);
string_.append(buffer);
}
const std::string& str() const { return string_; }
void clear() { string_.clear(); }
private:
std::string string_;
};
static std::unordered_map<std::string, OptionTypeInfo> struct_option_info = {
{"struct", OptionTypeInfo::Struct("struct", &simple_option_info, 0,
OptionVerificationType::kNormal,
OptionTypeFlags::kMutable)},
};
static std::unordered_map<std::string, OptionTypeInfo> imm_struct_option_info =
{
{"struct", OptionTypeInfo::Struct("struct", &simple_option_info, 0,
OptionVerificationType::kNormal,
OptionTypeFlags::kNone)},
};
class SimpleConfigurable : public TestConfigurable<Configurable> {
public:
static SimpleConfigurable* Create(
const std::string& name = "simple",
int mode = TestConfigMode::kDefaultMode,
const std::unordered_map<std::string, OptionTypeInfo>* map =
&simple_option_info) {
return new SimpleConfigurable(name, mode, map);
}
SimpleConfigurable(const std::string& name, int mode,
const std::unordered_map<std::string, OptionTypeInfo>*
map = &simple_option_info)
: TestConfigurable(name, mode, map) {
if ((mode & TestConfigMode::kUniqueMode) != 0) {
unique_.reset(SimpleConfigurable::Create("Unique" + name_));
RegisterOptions(name_ + "Unique", &unique_, &unique_option_info);
}
if ((mode & TestConfigMode::kSharedMode) != 0) {
shared_.reset(SimpleConfigurable::Create("Shared" + name_));
RegisterOptions(name_ + "Shared", &shared_, &shared_option_info);
}
if ((mode & TestConfigMode::kRawPtrMode) != 0) {
pointer_ = SimpleConfigurable::Create("Pointer" + name_);
RegisterOptions(name_ + "Pointer", &pointer_, &pointer_option_info);
}
}
}; // End class SimpleConfigurable
using ConfigTestFactoryFunc = std::function<Configurable*()>;
class ConfigurableTest : public testing::Test {
public:
ConfigurableTest() { config_options_.invoke_prepare_options = false; }
ConfigOptions config_options_;
};
TEST_F(ConfigurableTest, GetOptionsPtrTest) {
std::string opt_str;
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
ASSERT_NE(configurable->GetOptions<TestOptions>("simple"), nullptr);
ASSERT_EQ(configurable->GetOptions<TestOptions>("bad-opt"), nullptr);
}
TEST_F(ConfigurableTest, ConfigureFromMapTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
auto* opts = configurable->GetOptions<TestOptions>("simple");
ASSERT_OK(configurable->ConfigureFromMap(config_options_, {}));
ASSERT_NE(opts, nullptr);
std::unordered_map<std::string, std::string> options_map = {
{"int", "1"}, {"bool", "true"}, {"string", "string"}};
ASSERT_OK(configurable->ConfigureFromMap(config_options_, options_map));
ASSERT_EQ(opts->i, 1);
ASSERT_EQ(opts->b, true);
ASSERT_EQ(opts->s, "string");
}
TEST_F(ConfigurableTest, ConfigureFromStringTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
auto* opts = configurable->GetOptions<TestOptions>("simple");
ASSERT_OK(configurable->ConfigureFromString(config_options_, ""));
ASSERT_NE(opts, nullptr);
ASSERT_OK(configurable->ConfigureFromString(config_options_,
"int=1;bool=true;string=s"));
ASSERT_EQ(opts->i, 1);
ASSERT_EQ(opts->b, true);
ASSERT_EQ(opts->s, "s");
}
TEST_F(ConfigurableTest, ConfigureIgnoreTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
std::unordered_map<std::string, std::string> options_map = {{"unused", "u"}};
ConfigOptions ignore = config_options_;
ignore.ignore_unknown_options = true;
ASSERT_NOK(configurable->ConfigureFromMap(config_options_, options_map));
ASSERT_OK(configurable->ConfigureFromMap(ignore, options_map));
ASSERT_NOK(configurable->ConfigureFromString(config_options_, "unused=u"));
ASSERT_OK(configurable->ConfigureFromString(ignore, "unused=u"));
}
TEST_F(ConfigurableTest, ConfigureNestedOptionsTest) {
std::unique_ptr<Configurable> base, copy;
std::string opt_str;
std::string mismatch;
base.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
copy.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
ASSERT_OK(base->ConfigureFromString(config_options_,
"shared={int=10; string=10};"
"unique={int=20; string=20};"
"pointer={int=30; string=30};"));
ASSERT_OK(base->GetOptionString(config_options_, &opt_str));
ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
}
TEST_F(ConfigurableTest, GetOptionsTest) {
std::unique_ptr<Configurable> simple;
simple.reset(
SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
int i = 11;
for (auto opt : {"", "shared.", "unique.", "pointer."}) {
std::string value;
std::string expected = std::to_string(i);
std::string opt_name = opt;
ASSERT_OK(
simple->ConfigureOption(config_options_, opt_name + "int", expected));
ASSERT_OK(simple->GetOption(config_options_, opt_name + "int", &value));
ASSERT_EQ(expected, value);
ASSERT_OK(simple->ConfigureOption(config_options_, opt_name + "string",
expected));
ASSERT_OK(simple->GetOption(config_options_, opt_name + "string", &value));
ASSERT_EQ(expected, value);
ASSERT_NOK(
simple->ConfigureOption(config_options_, opt_name + "bad", expected));
ASSERT_NOK(simple->GetOption(config_options_, "bad option", &value));
ASSERT_TRUE(value.empty());
i += 11;
}
}
TEST_F(ConfigurableTest, ConfigureBadOptionsTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
auto* opts = configurable->GetOptions<TestOptions>("simple");
ASSERT_NE(opts, nullptr);
ASSERT_OK(configurable->ConfigureOption(config_options_, "int", "42"));
ASSERT_EQ(opts->i, 42);
ASSERT_NOK(configurable->ConfigureOption(config_options_, "int", "fred"));
ASSERT_NOK(configurable->ConfigureOption(config_options_, "bool", "fred"));
ASSERT_NOK(
configurable->ConfigureFromString(config_options_, "int=33;unused=u"));
ASSERT_EQ(opts->i, 42);
}
TEST_F(ConfigurableTest, InvalidOptionTest) {
std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
std::unordered_map<std::string, std::string> options_map = {
{"bad-option", "bad"}};
ASSERT_NOK(configurable->ConfigureFromMap(config_options_, options_map));
ASSERT_NOK(
configurable->ConfigureFromString(config_options_, "bad-option=bad"));
ASSERT_NOK(
configurable->ConfigureOption(config_options_, "bad-option", "bad"));
}
static std::unordered_map<std::string, OptionTypeInfo> validated_option_info = {
{"validated",
{0, OptionType::kBoolean, OptionVerificationType::kNormal,
OptionTypeFlags::kNone}},
};
static std::unordered_map<std::string, OptionTypeInfo> prepared_option_info = {
{"prepared",
{0, OptionType::kInt, OptionVerificationType::kNormal,
OptionTypeFlags::kMutable}},
};
static std::unordered_map<std::string, OptionTypeInfo>
dont_prepare_option_info = {
{"unique",
{0, OptionType::kConfigurable, OptionVerificationType::kNormal,
(OptionTypeFlags::kUnique | OptionTypeFlags::kDontPrepare)}},
};
class ValidatedConfigurable : public SimpleConfigurable {
public:
ValidatedConfigurable(const std::string& name, unsigned char mode,
bool dont_prepare = false)
: SimpleConfigurable(name, TestConfigMode::kDefaultMode),
validated(false),
prepared(0) {
RegisterOptions("Validated", &validated, &validated_option_info);
RegisterOptions("Prepared", &prepared, &prepared_option_info);
if ((mode & TestConfigMode::kUniqueMode) != 0) {
unique_.reset(new ValidatedConfigurable(
"Unique" + name_, TestConfigMode::kDefaultMode, false));
if (dont_prepare) {
RegisterOptions(name_ + "Unique", &unique_, &dont_prepare_option_info);
} else {
RegisterOptions(name_ + "Unique", &unique_, &unique_option_info);
}
}
}
Status PrepareOptions(const ConfigOptions& config_options) override {
if (++prepared <= 0) {
return Status::InvalidArgument("Cannot prepare option");
} else {
return SimpleConfigurable::PrepareOptions(config_options);
}
}
Status ValidateOptions(const DBOptions& db_opts,
const ColumnFamilyOptions& cf_opts) const override {
if (!validated) {
return Status::InvalidArgument("Not Validated");
} else {
return SimpleConfigurable::ValidateOptions(db_opts, cf_opts);
}
}
private:
bool validated;
int prepared;
};
TEST_F(ConfigurableTest, ValidateOptionsTest) {
std::unique_ptr<Configurable> configurable(
new ValidatedConfigurable("validated", TestConfigMode::kDefaultMode));
ColumnFamilyOptions cf_opts;
DBOptions db_opts;
ASSERT_OK(
configurable->ConfigureOption(config_options_, "validated", "false"));
ASSERT_NOK(configurable->ValidateOptions(db_opts, cf_opts));
ASSERT_OK(
configurable->ConfigureOption(config_options_, "validated", "true"));
ASSERT_OK(configurable->ValidateOptions(db_opts, cf_opts));
}
TEST_F(ConfigurableTest, PrepareOptionsTest) {
std::unique_ptr<Configurable> c(
new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode, false));
auto cp = c->GetOptions<int>("Prepared");
auto u = c->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique");
auto up = u->get()->GetOptions<int>("Prepared");
config_options_.invoke_prepare_options = false;
ASSERT_NE(cp, nullptr);
ASSERT_NE(up, nullptr);
ASSERT_EQ(*cp, 0);
ASSERT_EQ(*up, 0);
ASSERT_OK(c->ConfigureFromMap(config_options_, {}));
ASSERT_EQ(*cp, 0);
ASSERT_EQ(*up, 0);
config_options_.invoke_prepare_options = true;
ASSERT_OK(c->ConfigureFromMap(config_options_, {}));
ASSERT_EQ(*cp, 1);
ASSERT_EQ(*up, 1);
ASSERT_OK(c->ConfigureFromString(config_options_, "prepared=0"));
ASSERT_EQ(*up, 2);
ASSERT_EQ(*cp, 1);
ASSERT_NOK(c->ConfigureFromString(config_options_, "prepared=-2"));
c.reset(
new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode, true));
cp = c->GetOptions<int>("Prepared");
u = c->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique");
up = u->get()->GetOptions<int>("Prepared");
ASSERT_OK(c->ConfigureFromString(config_options_, "prepared=0"));
ASSERT_EQ(*cp, 1);
ASSERT_EQ(*up, 0);
}
TEST_F(ConfigurableTest, CopyObjectTest) {
class CopyConfigurable : public Configurable {
public:
CopyConfigurable() : prepared_(0), validated_(0) {}
Status PrepareOptions(const ConfigOptions& options) override {
prepared_++;
return Configurable::PrepareOptions(options);
}
Status ValidateOptions(const DBOptions& db_opts,
const ColumnFamilyOptions& cf_opts) const override {
validated_++;
return Configurable::ValidateOptions(db_opts, cf_opts);
}
int prepared_;
mutable int validated_;
};
CopyConfigurable c1;
ConfigOptions config_options;
Options options;
ASSERT_OK(c1.PrepareOptions(config_options));
ASSERT_OK(c1.ValidateOptions(options, options));
ASSERT_EQ(c1.prepared_, 1);
ASSERT_EQ(c1.validated_, 1);
CopyConfigurable c2 = c1;
ASSERT_OK(c1.PrepareOptions(config_options));
ASSERT_OK(c1.ValidateOptions(options, options));
ASSERT_EQ(c2.prepared_, 1);
ASSERT_EQ(c2.validated_, 1);
ASSERT_EQ(c1.prepared_, 2);
ASSERT_EQ(c1.validated_, 2);
}
TEST_F(ConfigurableTest, MutableOptionsTest) {
static std::unordered_map<std::string, OptionTypeInfo> imm_option_info = {
{"imm", OptionTypeInfo::Struct("imm", &simple_option_info, 0,
OptionVerificationType::kNormal,
OptionTypeFlags::kNone)},
};
class MutableConfigurable : public SimpleConfigurable {
public:
MutableConfigurable()
: SimpleConfigurable("mutable", TestConfigMode::kDefaultMode |
TestConfigMode::kUniqueMode |
TestConfigMode::kSharedMode) {
RegisterOptions("struct", &options_, &struct_option_info);
RegisterOptions("imm", &options_, &imm_option_info);
}
};
MutableConfigurable mc;
ConfigOptions options = config_options_;
ASSERT_OK(mc.ConfigureOption(options, "bool", "true"));
ASSERT_OK(mc.ConfigureOption(options, "int", "42"));
auto* opts = mc.GetOptions<TestOptions>("mutable");
ASSERT_NE(opts, nullptr);
ASSERT_EQ(opts->i, 42);
ASSERT_EQ(opts->b, true);
ASSERT_OK(mc.ConfigureOption(options, "struct", "{bool=false;}"));
ASSERT_OK(mc.ConfigureOption(options, "imm", "{int=55;}"));
options.mutable_options_only = true;
// Now only mutable options should be settable.
ASSERT_NOK(mc.ConfigureOption(options, "bool", "true"));
ASSERT_OK(mc.ConfigureOption(options, "int", "24"));
ASSERT_EQ(opts->i, 24);
ASSERT_EQ(opts->b, false);
ASSERT_NOK(mc.ConfigureFromString(options, "bool=false;int=33;"));
ASSERT_EQ(opts->i, 24);
ASSERT_EQ(opts->b, false);
// Setting options through an immutable struct fails
ASSERT_NOK(mc.ConfigureOption(options, "imm", "{int=55;}"));
ASSERT_NOK(mc.ConfigureOption(options, "imm.int", "55"));
ASSERT_EQ(opts->i, 24);
ASSERT_EQ(opts->b, false);
// Setting options through an mutable struct succeeds
ASSERT_OK(mc.ConfigureOption(options, "struct", "{int=44;}"));
ASSERT_EQ(opts->i, 44);
ASSERT_OK(mc.ConfigureOption(options, "struct.int", "55"));
ASSERT_EQ(opts->i, 55);
// Setting nested immutable configurable options fail
ASSERT_NOK(mc.ConfigureOption(options, "shared", "{bool=true;}"));
ASSERT_NOK(mc.ConfigureOption(options, "shared.bool", "true"));
// Setting nested mutable configurable options succeeds
ASSERT_OK(mc.ConfigureOption(options, "unique", "{bool=true}"));
ASSERT_OK(mc.ConfigureOption(options, "unique.bool", "true"));
}
TEST_F(ConfigurableTest, DeprecatedOptionsTest) {
static std::unordered_map<std::string, OptionTypeInfo>
deprecated_option_info = {
{"deprecated",
{offsetof(struct TestOptions, b), OptionType::kBoolean,
OptionVerificationType::kDeprecated, OptionTypeFlags::kNone}}};
std::unique_ptr<Configurable> orig;
orig.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode,
&deprecated_option_info));
auto* opts = orig->GetOptions<TestOptions>("simple");
ASSERT_NE(opts, nullptr);
opts->d = true;
ASSERT_OK(orig->ConfigureOption(config_options_, "deprecated", "false"));
ASSERT_TRUE(opts->d);
ASSERT_OK(orig->ConfigureFromString(config_options_, "deprecated=false"));
ASSERT_TRUE(opts->d);
}
TEST_F(ConfigurableTest, AliasOptionsTest) {
static std::unordered_map<std::string, OptionTypeInfo> alias_option_info = {
{"bool",
{offsetof(struct TestOptions, b), OptionType::kBoolean,
OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
{"alias",
{offsetof(struct TestOptions, b), OptionType::kBoolean,
OptionVerificationType::kAlias, OptionTypeFlags::kNone, nullptr}}};
std::unique_ptr<Configurable> orig;
orig.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode,
&alias_option_info));
auto* opts = orig->GetOptions<TestOptions>("simple");
ASSERT_NE(opts, nullptr);
ASSERT_OK(orig->ConfigureOption(config_options_, "bool", "false"));
ASSERT_FALSE(opts->b);
ASSERT_OK(orig->ConfigureOption(config_options_, "alias", "true"));
ASSERT_TRUE(opts->b);
std::string opts_str;
ASSERT_OK(orig->GetOptionString(config_options_, &opts_str));
ASSERT_EQ(opts_str.find("alias"), std::string::npos);
ASSERT_OK(orig->ConfigureOption(config_options_, "bool", "false"));
ASSERT_FALSE(opts->b);
ASSERT_OK(orig->GetOption(config_options_, "alias", &opts_str));
ASSERT_EQ(opts_str, "false");
}
TEST_F(ConfigurableTest, NestedUniqueConfigTest) {
std::unique_ptr<Configurable> simple;
simple.reset(
SimpleConfigurable::Create("Outer", TestConfigMode::kAllOptMode));
const auto outer = simple->GetOptions<TestOptions>("Outer");
const auto unique =
simple->GetOptions<std::unique_ptr<Configurable>>("OuterUnique");
ASSERT_NE(outer, nullptr);
ASSERT_NE(unique, nullptr);
ASSERT_OK(
simple->ConfigureFromString(config_options_, "int=24;string=outer"));
ASSERT_OK(simple->ConfigureFromString(config_options_,
"unique={int=42;string=nested}"));
const auto inner = unique->get()->GetOptions<TestOptions>("UniqueOuter");
ASSERT_NE(inner, nullptr);
ASSERT_EQ(outer->i, 24);
ASSERT_EQ(outer->s, "outer");
ASSERT_EQ(inner->i, 42);
ASSERT_EQ(inner->s, "nested");
}
TEST_F(ConfigurableTest, NestedSharedConfigTest) {
std::unique_ptr<Configurable> simple;
simple.reset(SimpleConfigurable::Create(
"Outer", TestConfigMode::kDefaultMode | TestConfigMode::kSharedMode));
ASSERT_OK(
simple->ConfigureFromString(config_options_, "int=24;string=outer"));
ASSERT_OK(simple->ConfigureFromString(config_options_,
"shared={int=42;string=nested}"));
const auto outer = simple->GetOptions<TestOptions>("Outer");
const auto shared =
simple->GetOptions<std::shared_ptr<Configurable>>("OuterShared");
ASSERT_NE(outer, nullptr);
ASSERT_NE(shared, nullptr);
const auto inner = shared->get()->GetOptions<TestOptions>("SharedOuter");
ASSERT_NE(inner, nullptr);
ASSERT_EQ(outer->i, 24);
ASSERT_EQ(outer->s, "outer");
ASSERT_EQ(inner->i, 42);
ASSERT_EQ(inner->s, "nested");
}
TEST_F(ConfigurableTest, NestedRawConfigTest) {
std::unique_ptr<Configurable> simple;
simple.reset(SimpleConfigurable::Create(
"Outer", TestConfigMode::kDefaultMode | TestConfigMode::kRawPtrMode));
ASSERT_OK(
simple->ConfigureFromString(config_options_, "int=24;string=outer"));
ASSERT_OK(simple->ConfigureFromString(config_options_,
"pointer={int=42;string=nested}"));
const auto outer = simple->GetOptions<TestOptions>("Outer");
const auto pointer = simple->GetOptions<Configurable*>("OuterPointer");
ASSERT_NE(outer, nullptr);
ASSERT_NE(pointer, nullptr);
const auto inner = (*pointer)->GetOptions<TestOptions>("PointerOuter");
ASSERT_NE(inner, nullptr);
ASSERT_EQ(outer->i, 24);
ASSERT_EQ(outer->s, "outer");
ASSERT_EQ(inner->i, 42);
ASSERT_EQ(inner->s, "nested");
}
TEST_F(ConfigurableTest, MatchesTest) {
std::string mismatch;
std::unique_ptr<Configurable> base, copy;
base.reset(SimpleConfigurable::Create(
"simple", TestConfigMode::kDefaultMode | TestConfigMode::kNestedMode));
copy.reset(SimpleConfigurable::Create(
"simple", TestConfigMode::kDefaultMode | TestConfigMode::kNestedMode));
ASSERT_OK(base->ConfigureFromString(
config_options_,
"int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}"));
ASSERT_OK(copy->ConfigureFromString(
config_options_,
"int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}"));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_OK(base->ConfigureOption(config_options_, "shared", "int=44"));
ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_EQ(mismatch, "shared.int");
std::string c1value, c2value;
ASSERT_OK(base->GetOption(config_options_, mismatch, &c1value));
ASSERT_OK(copy->GetOption(config_options_, mismatch, &c2value));
ASSERT_NE(c1value, c2value);
}
static Configurable* SimpleStructFactory() {
return SimpleConfigurable::Create(
"simple-struct", TestConfigMode::kDefaultMode, &struct_option_info);
}
TEST_F(ConfigurableTest, ConfigureStructTest) {
std::unique_ptr<Configurable> base(SimpleStructFactory());
std::unique_ptr<Configurable> copy(SimpleStructFactory());
std::string opt_str, value;
std::string mismatch;
std::unordered_set<std::string> names;
ASSERT_OK(
base->ConfigureFromString(config_options_, "struct={int=10; string=10}"));
ASSERT_OK(base->GetOptionString(config_options_, &opt_str));
ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_OK(base->GetOptionNames(config_options_, &names));
ASSERT_EQ(names.size(), 1);
ASSERT_EQ(*(names.begin()), "struct");
ASSERT_OK(
base->ConfigureFromString(config_options_, "struct={int=20; string=20}"));
ASSERT_OK(base->GetOption(config_options_, "struct", &value));
ASSERT_OK(copy->ConfigureOption(config_options_, "struct", value));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_NOK(base->ConfigureFromString(config_options_,
"struct={int=10; string=10; bad=11}"));
ASSERT_OK(base->ConfigureOption(config_options_, "struct.int", "42"));
ASSERT_NOK(base->ConfigureOption(config_options_, "struct.bad", "42"));
ASSERT_NOK(base->GetOption(config_options_, "struct.bad", &value));
ASSERT_OK(base->GetOption(config_options_, "struct.int", &value));
ASSERT_EQ(value, "42");
}
TEST_F(ConfigurableTest, ConfigurableEnumTest) {
std::unique_ptr<Configurable> base, copy;
base.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode));
copy.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode));
std::string opts_str;
std::string mismatch;
ASSERT_OK(base->ConfigureFromString(config_options_, "enum=B"));
ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_OK(base->GetOptionString(config_options_, &opts_str));
ASSERT_OK(copy->ConfigureFromString(config_options_, opts_str));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_NOK(base->ConfigureOption(config_options_, "enum", "bad"));
ASSERT_NOK(base->ConfigureOption(config_options_, "unknown", "bad"));
}
static std::unordered_map<std::string, OptionTypeInfo> noserialize_option_info =
{
{"int",
{offsetof(struct TestOptions, i), OptionType::kInt,
OptionVerificationType::kNormal, OptionTypeFlags::kDontSerialize}},
};
TEST_F(ConfigurableTest, TestNoSerialize) {
std::unique_ptr<Configurable> base;
base.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode,
&noserialize_option_info));
std::string opts_str, value;
ASSERT_OK(base->ConfigureFromString(config_options_, "int=10"));
ASSERT_OK(base->GetOptionString(config_options_, &opts_str));
ASSERT_EQ(opts_str, "");
ASSERT_NOK(base->GetOption(config_options_, "int", &value));
}
TEST_F(ConfigurableTest, TestNoCompare) {
std::unordered_map<std::string, OptionTypeInfo> nocomp_option_info = {
{"int",
{offsetof(struct TestOptions, i), OptionType::kInt,
OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}},
};
std::unordered_map<std::string, OptionTypeInfo> normal_option_info = {
{"int",
{offsetof(struct TestOptions, i), OptionType::kInt,
OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
};
std::unique_ptr<Configurable> base, copy;
base.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode,
&nocomp_option_info));
copy.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode,
&normal_option_info));
ASSERT_OK(base->ConfigureFromString(config_options_, "int=10"));
ASSERT_OK(copy->ConfigureFromString(config_options_, "int=20"));
std::string bvalue, cvalue, mismatch;
ASSERT_OK(base->GetOption(config_options_, "int", &bvalue));
ASSERT_OK(copy->GetOption(config_options_, "int", &cvalue));
ASSERT_EQ(bvalue, "10");
ASSERT_EQ(cvalue, "20");
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
ASSERT_FALSE(copy->AreEquivalent(config_options_, base.get(), &mismatch));
}
TEST_F(ConfigurableTest, NullOptionMapTest) {
std::unique_ptr<Configurable> base;
std::unordered_set<std::string> names;
std::string str;
base.reset(
SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, nullptr));
ASSERT_NOK(base->ConfigureFromString(config_options_, "int=10"));
ASSERT_NOK(base->ConfigureFromString(config_options_, "int=20"));
ASSERT_NOK(base->ConfigureOption(config_options_, "int", "20"));
ASSERT_NOK(base->GetOption(config_options_, "int", &str));
ASSERT_NE(base->GetOptions<TestOptions>("c"), nullptr);
ASSERT_OK(base->GetOptionNames(config_options_, &names));
ASSERT_EQ(names.size(), 0UL);
ASSERT_OK(base->PrepareOptions(config_options_));
ASSERT_OK(base->ValidateOptions(DBOptions(), ColumnFamilyOptions()));
std::unique_ptr<Configurable> copy;
copy.reset(
SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, nullptr));
ASSERT_OK(base->GetOptionString(config_options_, &str));
ASSERT_OK(copy->ConfigureFromString(config_options_, str));
ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &str));
}
static std::unordered_map<std::string, ConfigTestFactoryFunc> TestFactories = {
{"Simple", []() { return SimpleConfigurable::Create("simple"); }},
{"Struct", []() { return SimpleStructFactory(); }},
{"Unique",
[]() {
return SimpleConfigurable::Create(
"simple", TestConfigMode::kSimpleMode | TestConfigMode::kUniqueMode);
}},
{"Shared",
[]() {
return SimpleConfigurable::Create(
"simple", TestConfigMode::kSimpleMode | TestConfigMode::kSharedMode);
}},
{"Nested",
[]() {
return SimpleConfigurable::Create(
"simple", TestConfigMode::kSimpleMode | TestConfigMode::kNestedMode);
}},
{"Mutable",
[]() {
return SimpleConfigurable::Create("simple",
TestConfigMode::kMutableMode |
TestConfigMode::kSimpleMode |
TestConfigMode::kNestedMode);
}},
{"ThreeDeep",
[]() {
Configurable* simple = SimpleConfigurable::Create(
"Simple",
TestConfigMode::kUniqueMode | TestConfigMode::kDefaultMode);
auto* unique =
simple->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique");
unique->reset(SimpleConfigurable::Create(
"Child",
TestConfigMode::kUniqueMode | TestConfigMode::kDefaultMode));
unique = unique->get()->GetOptions<std::unique_ptr<Configurable>>(
"ChildUnique");
unique->reset(
SimpleConfigurable::Create("Child", TestConfigMode::kDefaultMode));
return simple;
}},
{"DBOptions",
[]() {
auto config = DBOptionsAsConfigurable(DBOptions());
return config.release();
}},
{"CFOptions",
[]() {
auto config = CFOptionsAsConfigurable(ColumnFamilyOptions());
return config.release();
}},
{"BlockBased", []() { return NewBlockBasedTableFactory(); }},
};
class ConfigurableParamTest : public ConfigurableTest,
virtual public ::testing::WithParamInterface<
std::pair<std::string, std::string>> {
public:
ConfigurableParamTest() {
type_ = GetParam().first;
configuration_ = GetParam().second;
assert(TestFactories.find(type_) != TestFactories.end());
object_.reset(CreateConfigurable());
}
Configurable* CreateConfigurable() {
const auto& iter = TestFactories.find(type_);
return (iter->second)();
}
void TestConfigureOptions(const ConfigOptions& opts);
std::string type_;
std::string configuration_;
std::unique_ptr<Configurable> object_;
};
void ConfigurableParamTest::TestConfigureOptions(
const ConfigOptions& config_options) {
std::unique_ptr<Configurable> base, copy;
std::unordered_set<std::string> names;
std::string opt_str, mismatch;
base.reset(CreateConfigurable());
copy.reset(CreateConfigurable());
ASSERT_OK(base->ConfigureFromString(config_options, configuration_));
ASSERT_OK(base->GetOptionString(config_options, &opt_str));
ASSERT_OK(copy->ConfigureFromString(config_options, opt_str));
ASSERT_OK(copy->GetOptionString(config_options, &opt_str));
ASSERT_TRUE(base->AreEquivalent(config_options, copy.get(), &mismatch));
copy.reset(CreateConfigurable());
ASSERT_OK(base->GetOptionNames(config_options, &names));
std::unordered_map<std::string, std::string> unused;
bool found_one = false;
for (const auto& name : names) {
std::string value;
Status s = base->GetOption(config_options, name, &value);
if (s.ok()) {
s = copy->ConfigureOption(config_options, name, value);
if (s.ok() || s.IsNotSupported()) {
found_one = true;
} else {
unused[name] = value;
}
} else {
ASSERT_TRUE(s.IsNotSupported());
}
}
ASSERT_TRUE(found_one || names.empty());
while (found_one && !unused.empty()) {
found_one = false;
for (auto iter = unused.begin(); iter != unused.end();) {
if (copy->ConfigureOption(config_options, iter->first, iter->second)
.ok()) {
found_one = true;
iter = unused.erase(iter);
} else {
++iter;
}
}
}
ASSERT_EQ(0, unused.size());
ASSERT_TRUE(base->AreEquivalent(config_options, copy.get(), &mismatch));
}
TEST_P(ConfigurableParamTest, GetDefaultOptionsTest) {
TestConfigureOptions(config_options_);
}
TEST_P(ConfigurableParamTest, ConfigureFromPropsTest) {
std::string opt_str, mismatch;
std::unordered_set<std::string> names;
std::unique_ptr<Configurable> copy(CreateConfigurable());
ASSERT_OK(object_->ConfigureFromString(config_options_, configuration_));
config_options_.delimiter = "\n";
ASSERT_OK(object_->GetOptionString(config_options_, &opt_str));
std::istringstream iss(opt_str);
std::unordered_map<std::string, std::string> copy_map;
std::string line;
for (int line_num = 0; std::getline(iss, line); line_num++) {
std::string name;
std::string value;
ASSERT_OK(
RocksDBOptionsParser::ParseStatement(&name, &value, line, line_num));
copy_map[name] = value;
}
ASSERT_OK(copy->ConfigureFromMap(config_options_, copy_map));
ASSERT_TRUE(object_->AreEquivalent(config_options_, copy.get(), &mismatch));
}
INSTANTIATE_TEST_CASE_P(
ParamTest, ConfigurableParamTest,
testing::Values(
std::pair<std::string, std::string>("Simple",
"int=42;bool=true;string=s"),
std::pair<std::string, std::string>(
"Mutable", "int=42;unique={int=33;string=unique}"),
std::pair<std::string, std::string>(
"Struct", "struct={int=33;bool=true;string=s;}"),
std::pair<std::string, std::string>("Shared",
"int=33;bool=true;string=outer;"
"shared={int=42;string=shared}"),
std::pair<std::string, std::string>("Unique",
"int=33;bool=true;string=outer;"
"unique={int=42;string=unique}"),
std::pair<std::string, std::string>("Nested",
"int=11;bool=true;string=outer;"
"pointer={int=22;string=pointer};"
"unique={int=33;string=unique};"
"shared={int=44;string=shared}"),
std::pair<std::string, std::string>("ThreeDeep",
"int=11;bool=true;string=outer;"
"unique={int=22;string=inner;"
"unique={int=33;string=unique}};"),
std::pair<std::string, std::string>("DBOptions",
"max_background_jobs=100;"
"max_open_files=200;"),
std::pair<std::string, std::string>("CFOptions",
"table_factory=BlockBasedTable;"
"disable_auto_compactions=true;"),
std::pair<std::string, std::string>("BlockBased",
"block_size=1024;"
"no_block_cache=true;")));
} // namespace ROCKSDB_NAMESPACE::test
int main(int argc, char** argv) {
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
::testing::InitGoogleTest(&argc, argv);
#ifdef GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif // GFLAGS
return RUN_ALL_TESTS();
}