configurable_test.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  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).
  5. //
  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.
  9. #include "options/configurable_test.h"
  10. #include <cctype>
  11. #include <cinttypes>
  12. #include <cstring>
  13. #include <unordered_map>
  14. #include "options/configurable_helper.h"
  15. #include "options/options_helper.h"
  16. #include "options/options_parser.h"
  17. #include "rocksdb/configurable.h"
  18. #include "test_util/testharness.h"
  19. #include "test_util/testutil.h"
  20. #ifndef GFLAGS
  21. bool FLAGS_enable_print = false;
  22. #else
  23. #include "util/gflags_compat.h"
  24. using GFLAGS_NAMESPACE::ParseCommandLineFlags;
  25. DEFINE_bool(enable_print, false, "Print options generated to console.");
  26. #endif // GFLAGS
  27. namespace ROCKSDB_NAMESPACE::test {
  28. class StringLogger : public Logger {
  29. public:
  30. using Logger::Logv;
  31. void Logv(const char* format, va_list ap) override {
  32. char buffer[1000];
  33. vsnprintf(buffer, sizeof(buffer), format, ap);
  34. string_.append(buffer);
  35. }
  36. const std::string& str() const { return string_; }
  37. void clear() { string_.clear(); }
  38. private:
  39. std::string string_;
  40. };
  41. static std::unordered_map<std::string, OptionTypeInfo> struct_option_info = {
  42. {"struct", OptionTypeInfo::Struct("struct", &simple_option_info, 0,
  43. OptionVerificationType::kNormal,
  44. OptionTypeFlags::kMutable)},
  45. };
  46. static std::unordered_map<std::string, OptionTypeInfo> imm_struct_option_info =
  47. {
  48. {"struct", OptionTypeInfo::Struct("struct", &simple_option_info, 0,
  49. OptionVerificationType::kNormal,
  50. OptionTypeFlags::kNone)},
  51. };
  52. class SimpleConfigurable : public TestConfigurable<Configurable> {
  53. public:
  54. static SimpleConfigurable* Create(
  55. const std::string& name = "simple",
  56. int mode = TestConfigMode::kDefaultMode,
  57. const std::unordered_map<std::string, OptionTypeInfo>* map =
  58. &simple_option_info) {
  59. return new SimpleConfigurable(name, mode, map);
  60. }
  61. SimpleConfigurable(const std::string& name, int mode,
  62. const std::unordered_map<std::string, OptionTypeInfo>*
  63. map = &simple_option_info)
  64. : TestConfigurable(name, mode, map) {
  65. if ((mode & TestConfigMode::kUniqueMode) != 0) {
  66. unique_.reset(SimpleConfigurable::Create("Unique" + name_));
  67. RegisterOptions(name_ + "Unique", &unique_, &unique_option_info);
  68. }
  69. if ((mode & TestConfigMode::kSharedMode) != 0) {
  70. shared_.reset(SimpleConfigurable::Create("Shared" + name_));
  71. RegisterOptions(name_ + "Shared", &shared_, &shared_option_info);
  72. }
  73. if ((mode & TestConfigMode::kRawPtrMode) != 0) {
  74. pointer_ = SimpleConfigurable::Create("Pointer" + name_);
  75. RegisterOptions(name_ + "Pointer", &pointer_, &pointer_option_info);
  76. }
  77. }
  78. }; // End class SimpleConfigurable
  79. using ConfigTestFactoryFunc = std::function<Configurable*()>;
  80. class ConfigurableTest : public testing::Test {
  81. public:
  82. ConfigurableTest() { config_options_.invoke_prepare_options = false; }
  83. ConfigOptions config_options_;
  84. };
  85. TEST_F(ConfigurableTest, GetOptionsPtrTest) {
  86. std::string opt_str;
  87. std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
  88. ASSERT_NE(configurable->GetOptions<TestOptions>("simple"), nullptr);
  89. ASSERT_EQ(configurable->GetOptions<TestOptions>("bad-opt"), nullptr);
  90. }
  91. TEST_F(ConfigurableTest, ConfigureFromMapTest) {
  92. std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
  93. auto* opts = configurable->GetOptions<TestOptions>("simple");
  94. ASSERT_OK(configurable->ConfigureFromMap(config_options_, {}));
  95. ASSERT_NE(opts, nullptr);
  96. std::unordered_map<std::string, std::string> options_map = {
  97. {"int", "1"}, {"bool", "true"}, {"string", "string"}};
  98. ASSERT_OK(configurable->ConfigureFromMap(config_options_, options_map));
  99. ASSERT_EQ(opts->i, 1);
  100. ASSERT_EQ(opts->b, true);
  101. ASSERT_EQ(opts->s, "string");
  102. }
  103. TEST_F(ConfigurableTest, ConfigureFromStringTest) {
  104. std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
  105. auto* opts = configurable->GetOptions<TestOptions>("simple");
  106. ASSERT_OK(configurable->ConfigureFromString(config_options_, ""));
  107. ASSERT_NE(opts, nullptr);
  108. ASSERT_OK(configurable->ConfigureFromString(config_options_,
  109. "int=1;bool=true;string=s"));
  110. ASSERT_EQ(opts->i, 1);
  111. ASSERT_EQ(opts->b, true);
  112. ASSERT_EQ(opts->s, "s");
  113. }
  114. TEST_F(ConfigurableTest, ConfigureIgnoreTest) {
  115. std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
  116. std::unordered_map<std::string, std::string> options_map = {{"unused", "u"}};
  117. ConfigOptions ignore = config_options_;
  118. ignore.ignore_unknown_options = true;
  119. ASSERT_NOK(configurable->ConfigureFromMap(config_options_, options_map));
  120. ASSERT_OK(configurable->ConfigureFromMap(ignore, options_map));
  121. ASSERT_NOK(configurable->ConfigureFromString(config_options_, "unused=u"));
  122. ASSERT_OK(configurable->ConfigureFromString(ignore, "unused=u"));
  123. }
  124. TEST_F(ConfigurableTest, ConfigureNestedOptionsTest) {
  125. std::unique_ptr<Configurable> base, copy;
  126. std::string opt_str;
  127. std::string mismatch;
  128. base.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
  129. copy.reset(SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
  130. ASSERT_OK(base->ConfigureFromString(config_options_,
  131. "shared={int=10; string=10};"
  132. "unique={int=20; string=20};"
  133. "pointer={int=30; string=30};"));
  134. ASSERT_OK(base->GetOptionString(config_options_, &opt_str));
  135. ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
  136. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  137. }
  138. TEST_F(ConfigurableTest, GetOptionsTest) {
  139. std::unique_ptr<Configurable> simple;
  140. simple.reset(
  141. SimpleConfigurable::Create("simple", TestConfigMode::kAllOptMode));
  142. int i = 11;
  143. for (auto opt : {"", "shared.", "unique.", "pointer."}) {
  144. std::string value;
  145. std::string expected = std::to_string(i);
  146. std::string opt_name = opt;
  147. ASSERT_OK(
  148. simple->ConfigureOption(config_options_, opt_name + "int", expected));
  149. ASSERT_OK(simple->GetOption(config_options_, opt_name + "int", &value));
  150. ASSERT_EQ(expected, value);
  151. ASSERT_OK(simple->ConfigureOption(config_options_, opt_name + "string",
  152. expected));
  153. ASSERT_OK(simple->GetOption(config_options_, opt_name + "string", &value));
  154. ASSERT_EQ(expected, value);
  155. ASSERT_NOK(
  156. simple->ConfigureOption(config_options_, opt_name + "bad", expected));
  157. ASSERT_NOK(simple->GetOption(config_options_, "bad option", &value));
  158. ASSERT_TRUE(value.empty());
  159. i += 11;
  160. }
  161. }
  162. TEST_F(ConfigurableTest, ConfigureBadOptionsTest) {
  163. std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
  164. auto* opts = configurable->GetOptions<TestOptions>("simple");
  165. ASSERT_NE(opts, nullptr);
  166. ASSERT_OK(configurable->ConfigureOption(config_options_, "int", "42"));
  167. ASSERT_EQ(opts->i, 42);
  168. ASSERT_NOK(configurable->ConfigureOption(config_options_, "int", "fred"));
  169. ASSERT_NOK(configurable->ConfigureOption(config_options_, "bool", "fred"));
  170. ASSERT_NOK(
  171. configurable->ConfigureFromString(config_options_, "int=33;unused=u"));
  172. ASSERT_EQ(opts->i, 42);
  173. }
  174. TEST_F(ConfigurableTest, InvalidOptionTest) {
  175. std::unique_ptr<Configurable> configurable(SimpleConfigurable::Create());
  176. std::unordered_map<std::string, std::string> options_map = {
  177. {"bad-option", "bad"}};
  178. ASSERT_NOK(configurable->ConfigureFromMap(config_options_, options_map));
  179. ASSERT_NOK(
  180. configurable->ConfigureFromString(config_options_, "bad-option=bad"));
  181. ASSERT_NOK(
  182. configurable->ConfigureOption(config_options_, "bad-option", "bad"));
  183. }
  184. static std::unordered_map<std::string, OptionTypeInfo> validated_option_info = {
  185. {"validated",
  186. {0, OptionType::kBoolean, OptionVerificationType::kNormal,
  187. OptionTypeFlags::kNone}},
  188. };
  189. static std::unordered_map<std::string, OptionTypeInfo> prepared_option_info = {
  190. {"prepared",
  191. {0, OptionType::kInt, OptionVerificationType::kNormal,
  192. OptionTypeFlags::kMutable}},
  193. };
  194. static std::unordered_map<std::string, OptionTypeInfo>
  195. dont_prepare_option_info = {
  196. {"unique",
  197. {0, OptionType::kConfigurable, OptionVerificationType::kNormal,
  198. (OptionTypeFlags::kUnique | OptionTypeFlags::kDontPrepare)}},
  199. };
  200. class ValidatedConfigurable : public SimpleConfigurable {
  201. public:
  202. ValidatedConfigurable(const std::string& name, unsigned char mode,
  203. bool dont_prepare = false)
  204. : SimpleConfigurable(name, TestConfigMode::kDefaultMode),
  205. validated(false),
  206. prepared(0) {
  207. RegisterOptions("Validated", &validated, &validated_option_info);
  208. RegisterOptions("Prepared", &prepared, &prepared_option_info);
  209. if ((mode & TestConfigMode::kUniqueMode) != 0) {
  210. unique_.reset(new ValidatedConfigurable(
  211. "Unique" + name_, TestConfigMode::kDefaultMode, false));
  212. if (dont_prepare) {
  213. RegisterOptions(name_ + "Unique", &unique_, &dont_prepare_option_info);
  214. } else {
  215. RegisterOptions(name_ + "Unique", &unique_, &unique_option_info);
  216. }
  217. }
  218. }
  219. Status PrepareOptions(const ConfigOptions& config_options) override {
  220. if (++prepared <= 0) {
  221. return Status::InvalidArgument("Cannot prepare option");
  222. } else {
  223. return SimpleConfigurable::PrepareOptions(config_options);
  224. }
  225. }
  226. Status ValidateOptions(const DBOptions& db_opts,
  227. const ColumnFamilyOptions& cf_opts) const override {
  228. if (!validated) {
  229. return Status::InvalidArgument("Not Validated");
  230. } else {
  231. return SimpleConfigurable::ValidateOptions(db_opts, cf_opts);
  232. }
  233. }
  234. private:
  235. bool validated;
  236. int prepared;
  237. };
  238. TEST_F(ConfigurableTest, ValidateOptionsTest) {
  239. std::unique_ptr<Configurable> configurable(
  240. new ValidatedConfigurable("validated", TestConfigMode::kDefaultMode));
  241. ColumnFamilyOptions cf_opts;
  242. DBOptions db_opts;
  243. ASSERT_OK(
  244. configurable->ConfigureOption(config_options_, "validated", "false"));
  245. ASSERT_NOK(configurable->ValidateOptions(db_opts, cf_opts));
  246. ASSERT_OK(
  247. configurable->ConfigureOption(config_options_, "validated", "true"));
  248. ASSERT_OK(configurable->ValidateOptions(db_opts, cf_opts));
  249. }
  250. TEST_F(ConfigurableTest, PrepareOptionsTest) {
  251. std::unique_ptr<Configurable> c(
  252. new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode, false));
  253. auto cp = c->GetOptions<int>("Prepared");
  254. auto u = c->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique");
  255. auto up = u->get()->GetOptions<int>("Prepared");
  256. config_options_.invoke_prepare_options = false;
  257. ASSERT_NE(cp, nullptr);
  258. ASSERT_NE(up, nullptr);
  259. ASSERT_EQ(*cp, 0);
  260. ASSERT_EQ(*up, 0);
  261. ASSERT_OK(c->ConfigureFromMap(config_options_, {}));
  262. ASSERT_EQ(*cp, 0);
  263. ASSERT_EQ(*up, 0);
  264. config_options_.invoke_prepare_options = true;
  265. ASSERT_OK(c->ConfigureFromMap(config_options_, {}));
  266. ASSERT_EQ(*cp, 1);
  267. ASSERT_EQ(*up, 1);
  268. ASSERT_OK(c->ConfigureFromString(config_options_, "prepared=0"));
  269. ASSERT_EQ(*up, 2);
  270. ASSERT_EQ(*cp, 1);
  271. ASSERT_NOK(c->ConfigureFromString(config_options_, "prepared=-2"));
  272. c.reset(
  273. new ValidatedConfigurable("Simple", TestConfigMode::kUniqueMode, true));
  274. cp = c->GetOptions<int>("Prepared");
  275. u = c->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique");
  276. up = u->get()->GetOptions<int>("Prepared");
  277. ASSERT_OK(c->ConfigureFromString(config_options_, "prepared=0"));
  278. ASSERT_EQ(*cp, 1);
  279. ASSERT_EQ(*up, 0);
  280. }
  281. TEST_F(ConfigurableTest, CopyObjectTest) {
  282. class CopyConfigurable : public Configurable {
  283. public:
  284. CopyConfigurable() : prepared_(0), validated_(0) {}
  285. Status PrepareOptions(const ConfigOptions& options) override {
  286. prepared_++;
  287. return Configurable::PrepareOptions(options);
  288. }
  289. Status ValidateOptions(const DBOptions& db_opts,
  290. const ColumnFamilyOptions& cf_opts) const override {
  291. validated_++;
  292. return Configurable::ValidateOptions(db_opts, cf_opts);
  293. }
  294. int prepared_;
  295. mutable int validated_;
  296. };
  297. CopyConfigurable c1;
  298. ConfigOptions config_options;
  299. Options options;
  300. ASSERT_OK(c1.PrepareOptions(config_options));
  301. ASSERT_OK(c1.ValidateOptions(options, options));
  302. ASSERT_EQ(c1.prepared_, 1);
  303. ASSERT_EQ(c1.validated_, 1);
  304. CopyConfigurable c2 = c1;
  305. ASSERT_OK(c1.PrepareOptions(config_options));
  306. ASSERT_OK(c1.ValidateOptions(options, options));
  307. ASSERT_EQ(c2.prepared_, 1);
  308. ASSERT_EQ(c2.validated_, 1);
  309. ASSERT_EQ(c1.prepared_, 2);
  310. ASSERT_EQ(c1.validated_, 2);
  311. }
  312. TEST_F(ConfigurableTest, MutableOptionsTest) {
  313. static std::unordered_map<std::string, OptionTypeInfo> imm_option_info = {
  314. {"imm", OptionTypeInfo::Struct("imm", &simple_option_info, 0,
  315. OptionVerificationType::kNormal,
  316. OptionTypeFlags::kNone)},
  317. };
  318. class MutableConfigurable : public SimpleConfigurable {
  319. public:
  320. MutableConfigurable()
  321. : SimpleConfigurable("mutable", TestConfigMode::kDefaultMode |
  322. TestConfigMode::kUniqueMode |
  323. TestConfigMode::kSharedMode) {
  324. RegisterOptions("struct", &options_, &struct_option_info);
  325. RegisterOptions("imm", &options_, &imm_option_info);
  326. }
  327. };
  328. MutableConfigurable mc;
  329. ConfigOptions options = config_options_;
  330. ASSERT_OK(mc.ConfigureOption(options, "bool", "true"));
  331. ASSERT_OK(mc.ConfigureOption(options, "int", "42"));
  332. auto* opts = mc.GetOptions<TestOptions>("mutable");
  333. ASSERT_NE(opts, nullptr);
  334. ASSERT_EQ(opts->i, 42);
  335. ASSERT_EQ(opts->b, true);
  336. ASSERT_OK(mc.ConfigureOption(options, "struct", "{bool=false;}"));
  337. ASSERT_OK(mc.ConfigureOption(options, "imm", "{int=55;}"));
  338. options.mutable_options_only = true;
  339. // Now only mutable options should be settable.
  340. ASSERT_NOK(mc.ConfigureOption(options, "bool", "true"));
  341. ASSERT_OK(mc.ConfigureOption(options, "int", "24"));
  342. ASSERT_EQ(opts->i, 24);
  343. ASSERT_EQ(opts->b, false);
  344. ASSERT_NOK(mc.ConfigureFromString(options, "bool=false;int=33;"));
  345. ASSERT_EQ(opts->i, 24);
  346. ASSERT_EQ(opts->b, false);
  347. // Setting options through an immutable struct fails
  348. ASSERT_NOK(mc.ConfigureOption(options, "imm", "{int=55;}"));
  349. ASSERT_NOK(mc.ConfigureOption(options, "imm.int", "55"));
  350. ASSERT_EQ(opts->i, 24);
  351. ASSERT_EQ(opts->b, false);
  352. // Setting options through an mutable struct succeeds
  353. ASSERT_OK(mc.ConfigureOption(options, "struct", "{int=44;}"));
  354. ASSERT_EQ(opts->i, 44);
  355. ASSERT_OK(mc.ConfigureOption(options, "struct.int", "55"));
  356. ASSERT_EQ(opts->i, 55);
  357. // Setting nested immutable configurable options fail
  358. ASSERT_NOK(mc.ConfigureOption(options, "shared", "{bool=true;}"));
  359. ASSERT_NOK(mc.ConfigureOption(options, "shared.bool", "true"));
  360. // Setting nested mutable configurable options succeeds
  361. ASSERT_OK(mc.ConfigureOption(options, "unique", "{bool=true}"));
  362. ASSERT_OK(mc.ConfigureOption(options, "unique.bool", "true"));
  363. }
  364. TEST_F(ConfigurableTest, DeprecatedOptionsTest) {
  365. static std::unordered_map<std::string, OptionTypeInfo>
  366. deprecated_option_info = {
  367. {"deprecated",
  368. {offsetof(struct TestOptions, b), OptionType::kBoolean,
  369. OptionVerificationType::kDeprecated, OptionTypeFlags::kNone}}};
  370. std::unique_ptr<Configurable> orig;
  371. orig.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode,
  372. &deprecated_option_info));
  373. auto* opts = orig->GetOptions<TestOptions>("simple");
  374. ASSERT_NE(opts, nullptr);
  375. opts->d = true;
  376. ASSERT_OK(orig->ConfigureOption(config_options_, "deprecated", "false"));
  377. ASSERT_TRUE(opts->d);
  378. ASSERT_OK(orig->ConfigureFromString(config_options_, "deprecated=false"));
  379. ASSERT_TRUE(opts->d);
  380. }
  381. TEST_F(ConfigurableTest, AliasOptionsTest) {
  382. static std::unordered_map<std::string, OptionTypeInfo> alias_option_info = {
  383. {"bool",
  384. {offsetof(struct TestOptions, b), OptionType::kBoolean,
  385. OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
  386. {"alias",
  387. {offsetof(struct TestOptions, b), OptionType::kBoolean,
  388. OptionVerificationType::kAlias, OptionTypeFlags::kNone, nullptr}}};
  389. std::unique_ptr<Configurable> orig;
  390. orig.reset(SimpleConfigurable::Create("simple", TestConfigMode::kDefaultMode,
  391. &alias_option_info));
  392. auto* opts = orig->GetOptions<TestOptions>("simple");
  393. ASSERT_NE(opts, nullptr);
  394. ASSERT_OK(orig->ConfigureOption(config_options_, "bool", "false"));
  395. ASSERT_FALSE(opts->b);
  396. ASSERT_OK(orig->ConfigureOption(config_options_, "alias", "true"));
  397. ASSERT_TRUE(opts->b);
  398. std::string opts_str;
  399. ASSERT_OK(orig->GetOptionString(config_options_, &opts_str));
  400. ASSERT_EQ(opts_str.find("alias"), std::string::npos);
  401. ASSERT_OK(orig->ConfigureOption(config_options_, "bool", "false"));
  402. ASSERT_FALSE(opts->b);
  403. ASSERT_OK(orig->GetOption(config_options_, "alias", &opts_str));
  404. ASSERT_EQ(opts_str, "false");
  405. }
  406. TEST_F(ConfigurableTest, NestedUniqueConfigTest) {
  407. std::unique_ptr<Configurable> simple;
  408. simple.reset(
  409. SimpleConfigurable::Create("Outer", TestConfigMode::kAllOptMode));
  410. const auto outer = simple->GetOptions<TestOptions>("Outer");
  411. const auto unique =
  412. simple->GetOptions<std::unique_ptr<Configurable>>("OuterUnique");
  413. ASSERT_NE(outer, nullptr);
  414. ASSERT_NE(unique, nullptr);
  415. ASSERT_OK(
  416. simple->ConfigureFromString(config_options_, "int=24;string=outer"));
  417. ASSERT_OK(simple->ConfigureFromString(config_options_,
  418. "unique={int=42;string=nested}"));
  419. const auto inner = unique->get()->GetOptions<TestOptions>("UniqueOuter");
  420. ASSERT_NE(inner, nullptr);
  421. ASSERT_EQ(outer->i, 24);
  422. ASSERT_EQ(outer->s, "outer");
  423. ASSERT_EQ(inner->i, 42);
  424. ASSERT_EQ(inner->s, "nested");
  425. }
  426. TEST_F(ConfigurableTest, NestedSharedConfigTest) {
  427. std::unique_ptr<Configurable> simple;
  428. simple.reset(SimpleConfigurable::Create(
  429. "Outer", TestConfigMode::kDefaultMode | TestConfigMode::kSharedMode));
  430. ASSERT_OK(
  431. simple->ConfigureFromString(config_options_, "int=24;string=outer"));
  432. ASSERT_OK(simple->ConfigureFromString(config_options_,
  433. "shared={int=42;string=nested}"));
  434. const auto outer = simple->GetOptions<TestOptions>("Outer");
  435. const auto shared =
  436. simple->GetOptions<std::shared_ptr<Configurable>>("OuterShared");
  437. ASSERT_NE(outer, nullptr);
  438. ASSERT_NE(shared, nullptr);
  439. const auto inner = shared->get()->GetOptions<TestOptions>("SharedOuter");
  440. ASSERT_NE(inner, nullptr);
  441. ASSERT_EQ(outer->i, 24);
  442. ASSERT_EQ(outer->s, "outer");
  443. ASSERT_EQ(inner->i, 42);
  444. ASSERT_EQ(inner->s, "nested");
  445. }
  446. TEST_F(ConfigurableTest, NestedRawConfigTest) {
  447. std::unique_ptr<Configurable> simple;
  448. simple.reset(SimpleConfigurable::Create(
  449. "Outer", TestConfigMode::kDefaultMode | TestConfigMode::kRawPtrMode));
  450. ASSERT_OK(
  451. simple->ConfigureFromString(config_options_, "int=24;string=outer"));
  452. ASSERT_OK(simple->ConfigureFromString(config_options_,
  453. "pointer={int=42;string=nested}"));
  454. const auto outer = simple->GetOptions<TestOptions>("Outer");
  455. const auto pointer = simple->GetOptions<Configurable*>("OuterPointer");
  456. ASSERT_NE(outer, nullptr);
  457. ASSERT_NE(pointer, nullptr);
  458. const auto inner = (*pointer)->GetOptions<TestOptions>("PointerOuter");
  459. ASSERT_NE(inner, nullptr);
  460. ASSERT_EQ(outer->i, 24);
  461. ASSERT_EQ(outer->s, "outer");
  462. ASSERT_EQ(inner->i, 42);
  463. ASSERT_EQ(inner->s, "nested");
  464. }
  465. TEST_F(ConfigurableTest, MatchesTest) {
  466. std::string mismatch;
  467. std::unique_ptr<Configurable> base, copy;
  468. base.reset(SimpleConfigurable::Create(
  469. "simple", TestConfigMode::kDefaultMode | TestConfigMode::kNestedMode));
  470. copy.reset(SimpleConfigurable::Create(
  471. "simple", TestConfigMode::kDefaultMode | TestConfigMode::kNestedMode));
  472. ASSERT_OK(base->ConfigureFromString(
  473. config_options_,
  474. "int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}"));
  475. ASSERT_OK(copy->ConfigureFromString(
  476. config_options_,
  477. "int=11;string=outer;unique={int=22;string=u};shared={int=33;string=s}"));
  478. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  479. ASSERT_OK(base->ConfigureOption(config_options_, "shared", "int=44"));
  480. ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  481. ASSERT_EQ(mismatch, "shared.int");
  482. std::string c1value, c2value;
  483. ASSERT_OK(base->GetOption(config_options_, mismatch, &c1value));
  484. ASSERT_OK(copy->GetOption(config_options_, mismatch, &c2value));
  485. ASSERT_NE(c1value, c2value);
  486. }
  487. static Configurable* SimpleStructFactory() {
  488. return SimpleConfigurable::Create(
  489. "simple-struct", TestConfigMode::kDefaultMode, &struct_option_info);
  490. }
  491. TEST_F(ConfigurableTest, ConfigureStructTest) {
  492. std::unique_ptr<Configurable> base(SimpleStructFactory());
  493. std::unique_ptr<Configurable> copy(SimpleStructFactory());
  494. std::string opt_str, value;
  495. std::string mismatch;
  496. std::unordered_set<std::string> names;
  497. ASSERT_OK(
  498. base->ConfigureFromString(config_options_, "struct={int=10; string=10}"));
  499. ASSERT_OK(base->GetOptionString(config_options_, &opt_str));
  500. ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
  501. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  502. ASSERT_OK(base->GetOptionNames(config_options_, &names));
  503. ASSERT_EQ(names.size(), 1);
  504. ASSERT_EQ(*(names.begin()), "struct");
  505. ASSERT_OK(
  506. base->ConfigureFromString(config_options_, "struct={int=20; string=20}"));
  507. ASSERT_OK(base->GetOption(config_options_, "struct", &value));
  508. ASSERT_OK(copy->ConfigureOption(config_options_, "struct", value));
  509. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  510. ASSERT_NOK(base->ConfigureFromString(config_options_,
  511. "struct={int=10; string=10; bad=11}"));
  512. ASSERT_OK(base->ConfigureOption(config_options_, "struct.int", "42"));
  513. ASSERT_NOK(base->ConfigureOption(config_options_, "struct.bad", "42"));
  514. ASSERT_NOK(base->GetOption(config_options_, "struct.bad", &value));
  515. ASSERT_OK(base->GetOption(config_options_, "struct.int", &value));
  516. ASSERT_EQ(value, "42");
  517. }
  518. TEST_F(ConfigurableTest, ConfigurableEnumTest) {
  519. std::unique_ptr<Configurable> base, copy;
  520. base.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode));
  521. copy.reset(SimpleConfigurable::Create("e", TestConfigMode::kEnumMode));
  522. std::string opts_str;
  523. std::string mismatch;
  524. ASSERT_OK(base->ConfigureFromString(config_options_, "enum=B"));
  525. ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  526. ASSERT_OK(base->GetOptionString(config_options_, &opts_str));
  527. ASSERT_OK(copy->ConfigureFromString(config_options_, opts_str));
  528. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  529. ASSERT_NOK(base->ConfigureOption(config_options_, "enum", "bad"));
  530. ASSERT_NOK(base->ConfigureOption(config_options_, "unknown", "bad"));
  531. }
  532. static std::unordered_map<std::string, OptionTypeInfo> noserialize_option_info =
  533. {
  534. {"int",
  535. {offsetof(struct TestOptions, i), OptionType::kInt,
  536. OptionVerificationType::kNormal, OptionTypeFlags::kDontSerialize}},
  537. };
  538. TEST_F(ConfigurableTest, TestNoSerialize) {
  539. std::unique_ptr<Configurable> base;
  540. base.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode,
  541. &noserialize_option_info));
  542. std::string opts_str, value;
  543. ASSERT_OK(base->ConfigureFromString(config_options_, "int=10"));
  544. ASSERT_OK(base->GetOptionString(config_options_, &opts_str));
  545. ASSERT_EQ(opts_str, "");
  546. ASSERT_NOK(base->GetOption(config_options_, "int", &value));
  547. }
  548. TEST_F(ConfigurableTest, TestNoCompare) {
  549. std::unordered_map<std::string, OptionTypeInfo> nocomp_option_info = {
  550. {"int",
  551. {offsetof(struct TestOptions, i), OptionType::kInt,
  552. OptionVerificationType::kNormal, OptionTypeFlags::kCompareNever}},
  553. };
  554. std::unordered_map<std::string, OptionTypeInfo> normal_option_info = {
  555. {"int",
  556. {offsetof(struct TestOptions, i), OptionType::kInt,
  557. OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
  558. };
  559. std::unique_ptr<Configurable> base, copy;
  560. base.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode,
  561. &nocomp_option_info));
  562. copy.reset(SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode,
  563. &normal_option_info));
  564. ASSERT_OK(base->ConfigureFromString(config_options_, "int=10"));
  565. ASSERT_OK(copy->ConfigureFromString(config_options_, "int=20"));
  566. std::string bvalue, cvalue, mismatch;
  567. ASSERT_OK(base->GetOption(config_options_, "int", &bvalue));
  568. ASSERT_OK(copy->GetOption(config_options_, "int", &cvalue));
  569. ASSERT_EQ(bvalue, "10");
  570. ASSERT_EQ(cvalue, "20");
  571. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
  572. ASSERT_FALSE(copy->AreEquivalent(config_options_, base.get(), &mismatch));
  573. }
  574. TEST_F(ConfigurableTest, NullOptionMapTest) {
  575. std::unique_ptr<Configurable> base;
  576. std::unordered_set<std::string> names;
  577. std::string str;
  578. base.reset(
  579. SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, nullptr));
  580. ASSERT_NOK(base->ConfigureFromString(config_options_, "int=10"));
  581. ASSERT_NOK(base->ConfigureFromString(config_options_, "int=20"));
  582. ASSERT_NOK(base->ConfigureOption(config_options_, "int", "20"));
  583. ASSERT_NOK(base->GetOption(config_options_, "int", &str));
  584. ASSERT_NE(base->GetOptions<TestOptions>("c"), nullptr);
  585. ASSERT_OK(base->GetOptionNames(config_options_, &names));
  586. ASSERT_EQ(names.size(), 0UL);
  587. ASSERT_OK(base->PrepareOptions(config_options_));
  588. ASSERT_OK(base->ValidateOptions(DBOptions(), ColumnFamilyOptions()));
  589. std::unique_ptr<Configurable> copy;
  590. copy.reset(
  591. SimpleConfigurable::Create("c", TestConfigMode::kDefaultMode, nullptr));
  592. ASSERT_OK(base->GetOptionString(config_options_, &str));
  593. ASSERT_OK(copy->ConfigureFromString(config_options_, str));
  594. ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &str));
  595. }
  596. static std::unordered_map<std::string, ConfigTestFactoryFunc> TestFactories = {
  597. {"Simple", []() { return SimpleConfigurable::Create("simple"); }},
  598. {"Struct", []() { return SimpleStructFactory(); }},
  599. {"Unique",
  600. []() {
  601. return SimpleConfigurable::Create(
  602. "simple", TestConfigMode::kSimpleMode | TestConfigMode::kUniqueMode);
  603. }},
  604. {"Shared",
  605. []() {
  606. return SimpleConfigurable::Create(
  607. "simple", TestConfigMode::kSimpleMode | TestConfigMode::kSharedMode);
  608. }},
  609. {"Nested",
  610. []() {
  611. return SimpleConfigurable::Create(
  612. "simple", TestConfigMode::kSimpleMode | TestConfigMode::kNestedMode);
  613. }},
  614. {"Mutable",
  615. []() {
  616. return SimpleConfigurable::Create("simple",
  617. TestConfigMode::kMutableMode |
  618. TestConfigMode::kSimpleMode |
  619. TestConfigMode::kNestedMode);
  620. }},
  621. {"ThreeDeep",
  622. []() {
  623. Configurable* simple = SimpleConfigurable::Create(
  624. "Simple",
  625. TestConfigMode::kUniqueMode | TestConfigMode::kDefaultMode);
  626. auto* unique =
  627. simple->GetOptions<std::unique_ptr<Configurable>>("SimpleUnique");
  628. unique->reset(SimpleConfigurable::Create(
  629. "Child",
  630. TestConfigMode::kUniqueMode | TestConfigMode::kDefaultMode));
  631. unique = unique->get()->GetOptions<std::unique_ptr<Configurable>>(
  632. "ChildUnique");
  633. unique->reset(
  634. SimpleConfigurable::Create("Child", TestConfigMode::kDefaultMode));
  635. return simple;
  636. }},
  637. {"DBOptions",
  638. []() {
  639. auto config = DBOptionsAsConfigurable(DBOptions());
  640. return config.release();
  641. }},
  642. {"CFOptions",
  643. []() {
  644. auto config = CFOptionsAsConfigurable(ColumnFamilyOptions());
  645. return config.release();
  646. }},
  647. {"BlockBased", []() { return NewBlockBasedTableFactory(); }},
  648. };
  649. class ConfigurableParamTest : public ConfigurableTest,
  650. virtual public ::testing::WithParamInterface<
  651. std::pair<std::string, std::string>> {
  652. public:
  653. ConfigurableParamTest() {
  654. type_ = GetParam().first;
  655. configuration_ = GetParam().second;
  656. assert(TestFactories.find(type_) != TestFactories.end());
  657. object_.reset(CreateConfigurable());
  658. }
  659. Configurable* CreateConfigurable() {
  660. const auto& iter = TestFactories.find(type_);
  661. return (iter->second)();
  662. }
  663. void TestConfigureOptions(const ConfigOptions& opts);
  664. std::string type_;
  665. std::string configuration_;
  666. std::unique_ptr<Configurable> object_;
  667. };
  668. void ConfigurableParamTest::TestConfigureOptions(
  669. const ConfigOptions& config_options) {
  670. std::unique_ptr<Configurable> base, copy;
  671. std::unordered_set<std::string> names;
  672. std::string opt_str, mismatch;
  673. base.reset(CreateConfigurable());
  674. copy.reset(CreateConfigurable());
  675. ASSERT_OK(base->ConfigureFromString(config_options, configuration_));
  676. ASSERT_OK(base->GetOptionString(config_options, &opt_str));
  677. ASSERT_OK(copy->ConfigureFromString(config_options, opt_str));
  678. ASSERT_OK(copy->GetOptionString(config_options, &opt_str));
  679. ASSERT_TRUE(base->AreEquivalent(config_options, copy.get(), &mismatch));
  680. copy.reset(CreateConfigurable());
  681. ASSERT_OK(base->GetOptionNames(config_options, &names));
  682. std::unordered_map<std::string, std::string> unused;
  683. bool found_one = false;
  684. for (const auto& name : names) {
  685. std::string value;
  686. Status s = base->GetOption(config_options, name, &value);
  687. if (s.ok()) {
  688. s = copy->ConfigureOption(config_options, name, value);
  689. if (s.ok() || s.IsNotSupported()) {
  690. found_one = true;
  691. } else {
  692. unused[name] = value;
  693. }
  694. } else {
  695. ASSERT_TRUE(s.IsNotSupported());
  696. }
  697. }
  698. ASSERT_TRUE(found_one || names.empty());
  699. while (found_one && !unused.empty()) {
  700. found_one = false;
  701. for (auto iter = unused.begin(); iter != unused.end();) {
  702. if (copy->ConfigureOption(config_options, iter->first, iter->second)
  703. .ok()) {
  704. found_one = true;
  705. iter = unused.erase(iter);
  706. } else {
  707. ++iter;
  708. }
  709. }
  710. }
  711. ASSERT_EQ(0, unused.size());
  712. ASSERT_TRUE(base->AreEquivalent(config_options, copy.get(), &mismatch));
  713. }
  714. TEST_P(ConfigurableParamTest, GetDefaultOptionsTest) {
  715. TestConfigureOptions(config_options_);
  716. }
  717. TEST_P(ConfigurableParamTest, ConfigureFromPropsTest) {
  718. std::string opt_str, mismatch;
  719. std::unordered_set<std::string> names;
  720. std::unique_ptr<Configurable> copy(CreateConfigurable());
  721. ASSERT_OK(object_->ConfigureFromString(config_options_, configuration_));
  722. config_options_.delimiter = "\n";
  723. ASSERT_OK(object_->GetOptionString(config_options_, &opt_str));
  724. std::istringstream iss(opt_str);
  725. std::unordered_map<std::string, std::string> copy_map;
  726. std::string line;
  727. for (int line_num = 0; std::getline(iss, line); line_num++) {
  728. std::string name;
  729. std::string value;
  730. ASSERT_OK(
  731. RocksDBOptionsParser::ParseStatement(&name, &value, line, line_num));
  732. copy_map[name] = value;
  733. }
  734. ASSERT_OK(copy->ConfigureFromMap(config_options_, copy_map));
  735. ASSERT_TRUE(object_->AreEquivalent(config_options_, copy.get(), &mismatch));
  736. }
  737. INSTANTIATE_TEST_CASE_P(
  738. ParamTest, ConfigurableParamTest,
  739. testing::Values(
  740. std::pair<std::string, std::string>("Simple",
  741. "int=42;bool=true;string=s"),
  742. std::pair<std::string, std::string>(
  743. "Mutable", "int=42;unique={int=33;string=unique}"),
  744. std::pair<std::string, std::string>(
  745. "Struct", "struct={int=33;bool=true;string=s;}"),
  746. std::pair<std::string, std::string>("Shared",
  747. "int=33;bool=true;string=outer;"
  748. "shared={int=42;string=shared}"),
  749. std::pair<std::string, std::string>("Unique",
  750. "int=33;bool=true;string=outer;"
  751. "unique={int=42;string=unique}"),
  752. std::pair<std::string, std::string>("Nested",
  753. "int=11;bool=true;string=outer;"
  754. "pointer={int=22;string=pointer};"
  755. "unique={int=33;string=unique};"
  756. "shared={int=44;string=shared}"),
  757. std::pair<std::string, std::string>("ThreeDeep",
  758. "int=11;bool=true;string=outer;"
  759. "unique={int=22;string=inner;"
  760. "unique={int=33;string=unique}};"),
  761. std::pair<std::string, std::string>("DBOptions",
  762. "max_background_jobs=100;"
  763. "max_open_files=200;"),
  764. std::pair<std::string, std::string>("CFOptions",
  765. "table_factory=BlockBasedTable;"
  766. "disable_auto_compactions=true;"),
  767. std::pair<std::string, std::string>("BlockBased",
  768. "block_size=1024;"
  769. "no_block_cache=true;")));
  770. } // namespace ROCKSDB_NAMESPACE::test
  771. int main(int argc, char** argv) {
  772. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  773. ::testing::InitGoogleTest(&argc, argv);
  774. #ifdef GFLAGS
  775. ParseCommandLineFlags(&argc, &argv, true);
  776. #endif // GFLAGS
  777. return RUN_ALL_TESTS();
  778. }