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 
10 #include "rocksdb/customizable.h"
11 
12 #include <cctype>
13 #include <cinttypes>
14 #include <cstring>
15 #include <unordered_map>
16 
17 #include "db/db_test_util.h"
18 #include "options/options_helper.h"
19 #include "options/options_parser.h"
20 #include "port/stack_trace.h"
21 #include "rocksdb/convenience.h"
22 #include "rocksdb/env_encryption.h"
23 #include "rocksdb/file_checksum.h"
24 #include "rocksdb/flush_block_policy.h"
25 #include "rocksdb/secondary_cache.h"
26 #include "rocksdb/slice_transform.h"
27 #include "rocksdb/sst_partitioner.h"
28 #include "rocksdb/statistics.h"
29 #include "rocksdb/utilities/customizable_util.h"
30 #include "rocksdb/utilities/object_registry.h"
31 #include "rocksdb/utilities/options_type.h"
32 #include "table/block_based/flush_block_policy.h"
33 #include "table/mock_table.h"
34 #include "test_util/mock_time_env.h"
35 #include "test_util/testharness.h"
36 #include "test_util/testutil.h"
37 #include "util/file_checksum_helper.h"
38 #include "util/string_util.h"
39 #include "utilities/compaction_filters/remove_emptyvalue_compactionfilter.h"
40 
41 #ifndef GFLAGS
42 bool FLAGS_enable_print = false;
43 #else
44 #include "util/gflags_compat.h"
45 using GFLAGS_NAMESPACE::ParseCommandLineFlags;
46 DEFINE_bool(enable_print, false, "Print options generated to console.");
47 #endif  // GFLAGS
48 
49 namespace ROCKSDB_NAMESPACE {
50 namespace {
51 class StringLogger : public Logger {
52  public:
53   using Logger::Logv;
Logv(const char * format,va_list ap)54   void Logv(const char* format, va_list ap) override {
55     char buffer[1000];
56     vsnprintf(buffer, sizeof(buffer), format, ap);
57     string_.append(buffer);
58   }
str() const59   const std::string& str() const { return string_; }
clear()60   void clear() { string_.clear(); }
61 
62  private:
63   std::string string_;
64 };
65 
66 class TestCustomizable : public Customizable {
67  public:
TestCustomizable(const std::string & name)68   TestCustomizable(const std::string& name) : name_(name) {}
69   // Method to allow CheckedCast to work for this class
kClassName()70   static const char* kClassName() {
71     return "TestCustomizable";
72   }
73 
Name() const74   const char* Name() const override { return name_.c_str(); }
Type()75   static const char* Type() { return "test.custom"; }
76 #ifndef ROCKSDB_LITE
77   static Status CreateFromString(const ConfigOptions& opts,
78                                  const std::string& value,
79                                  std::unique_ptr<TestCustomizable>* result);
80   static Status CreateFromString(const ConfigOptions& opts,
81                                  const std::string& value,
82                                  std::shared_ptr<TestCustomizable>* result);
83   static Status CreateFromString(const ConfigOptions& opts,
84                                  const std::string& value,
85                                  TestCustomizable** result);
86 #endif  // ROCKSDB_LITE
IsInstanceOf(const std::string & name) const87   bool IsInstanceOf(const std::string& name) const override {
88     if (name == kClassName()) {
89       return true;
90     } else {
91       return Customizable::IsInstanceOf(name);
92     }
93   }
94 
95  protected:
96   const std::string name_;
97 };
98 
99 struct AOptions {
kNameROCKSDB_NAMESPACE::__anon251625620111::AOptions100   static const char* kName() { return "A"; }
101   int i = 0;
102   bool b = false;
103 };
104 
105 static std::unordered_map<std::string, OptionTypeInfo> a_option_info = {
106 #ifndef ROCKSDB_LITE
107     {"int",
108      {offsetof(struct AOptions, i), OptionType::kInt,
109       OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
110     {"bool",
111      {offsetof(struct AOptions, b), OptionType::kBoolean,
112       OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
113 #endif  // ROCKSDB_LITE
114 };
115 
116 class ACustomizable : public TestCustomizable {
117  public:
ACustomizable(const std::string & id)118   explicit ACustomizable(const std::string& id)
119       : TestCustomizable("A"), id_(id) {
120     RegisterOptions(&opts_, &a_option_info);
121   }
GetId() const122   std::string GetId() const override { return id_; }
kClassName()123   static const char* kClassName() { return "A"; }
124 
125  private:
126   AOptions opts_;
127   const std::string id_;
128 };
129 
130 struct BOptions {
131   std::string s;
132   bool b = false;
133 };
134 
135 static std::unordered_map<std::string, OptionTypeInfo> b_option_info = {
136 #ifndef ROCKSDB_LITE
137     {"string",
138      {offsetof(struct BOptions, s), OptionType::kString,
139       OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
140     {"bool",
141      {offsetof(struct BOptions, b), OptionType::kBoolean,
142       OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
143 #endif  // ROCKSDB_LITE
144 };
145 
146 class BCustomizable : public TestCustomizable {
147  private:
148  public:
BCustomizable(const std::string & name)149   explicit BCustomizable(const std::string& name) : TestCustomizable(name) {
150     RegisterOptions(name, &opts_, &b_option_info);
151   }
kClassName()152   static const char* kClassName() { return "B"; }
153 
154  private:
155   BOptions opts_;
156 };
157 
158 #ifndef ROCKSDB_LITE
LoadSharedB(const std::string & id,std::shared_ptr<TestCustomizable> * result)159 static bool LoadSharedB(const std::string& id,
160                         std::shared_ptr<TestCustomizable>* result) {
161   if (id == "B") {
162     result->reset(new BCustomizable(id));
163     return true;
164   } else if (id.empty()) {
165     result->reset();
166     return true;
167   } else {
168     return false;
169   }
170 }
171 
172 static int A_count = 0;
RegisterCustomTestObjects(ObjectLibrary & library,const std::string &)173 static int RegisterCustomTestObjects(ObjectLibrary& library,
174                                      const std::string& /*arg*/) {
175   library.Register<TestCustomizable>(
176       "A.*",
177       [](const std::string& name, std::unique_ptr<TestCustomizable>* guard,
178          std::string* /* msg */) {
179         guard->reset(new ACustomizable(name));
180         A_count++;
181         return guard->get();
182       });
183 
184   library.Register<TestCustomizable>(
185       "S", [](const std::string& name,
186               std::unique_ptr<TestCustomizable>* /* guard */,
187               std::string* /* msg */) { return new BCustomizable(name); });
188   size_t num_types;
189   return static_cast<int>(library.GetFactoryCount(&num_types));
190 }
191 #endif  // ROCKSDB_LITE
192 
193 struct SimpleOptions {
kNameROCKSDB_NAMESPACE::__anon251625620111::SimpleOptions194   static const char* kName() { return "simple"; }
195   bool b = true;
196   std::unique_ptr<TestCustomizable> cu;
197   std::shared_ptr<TestCustomizable> cs;
198   TestCustomizable* cp = nullptr;
199 };
200 
201 static std::unordered_map<std::string, OptionTypeInfo> simple_option_info = {
202 #ifndef ROCKSDB_LITE
203     {"bool",
204      {offsetof(struct SimpleOptions, b), OptionType::kBoolean,
205       OptionVerificationType::kNormal, OptionTypeFlags::kNone}},
206     {"unique",
207      OptionTypeInfo::AsCustomUniquePtr<TestCustomizable>(
208          offsetof(struct SimpleOptions, cu), OptionVerificationType::kNormal,
209          OptionTypeFlags::kAllowNull)},
210     {"shared",
211      OptionTypeInfo::AsCustomSharedPtr<TestCustomizable>(
212          offsetof(struct SimpleOptions, cs), OptionVerificationType::kNormal,
213          OptionTypeFlags::kAllowNull)},
214     {"pointer",
215      OptionTypeInfo::AsCustomRawPtr<TestCustomizable>(
216          offsetof(struct SimpleOptions, cp), OptionVerificationType::kNormal,
217          OptionTypeFlags::kAllowNull)},
218 #endif  // ROCKSDB_LITE
219 };
220 
221 class SimpleConfigurable : public Configurable {
222  private:
223   SimpleOptions simple_;
224 
225  public:
SimpleConfigurable()226   SimpleConfigurable() { RegisterOptions(&simple_, &simple_option_info); }
227 
SimpleConfigurable(const std::unordered_map<std::string,OptionTypeInfo> * map)228   explicit SimpleConfigurable(
229       const std::unordered_map<std::string, OptionTypeInfo>* map) {
230     RegisterOptions(&simple_, map);
231   }
232 };
233 
234 #ifndef ROCKSDB_LITE
GetMapFromProperties(const std::string & props,std::unordered_map<std::string,std::string> * map)235 static void GetMapFromProperties(
236     const std::string& props,
237     std::unordered_map<std::string, std::string>* map) {
238   std::istringstream iss(props);
239   std::unordered_map<std::string, std::string> copy_map;
240   std::string line;
241   map->clear();
242   for (int line_num = 0; std::getline(iss, line); line_num++) {
243     std::string name;
244     std::string value;
245     ASSERT_OK(
246         RocksDBOptionsParser::ParseStatement(&name, &value, line, line_num));
247     (*map)[name] = value;
248   }
249 }
250 #endif  // ROCKSDB_LITE
251 }  // namespace
252 
253 #ifndef ROCKSDB_LITE
CreateFromString(const ConfigOptions & config_options,const std::string & value,std::shared_ptr<TestCustomizable> * result)254 Status TestCustomizable::CreateFromString(
255     const ConfigOptions& config_options, const std::string& value,
256     std::shared_ptr<TestCustomizable>* result) {
257   return LoadSharedObject<TestCustomizable>(config_options, value, LoadSharedB,
258                                             result);
259 }
260 
CreateFromString(const ConfigOptions & config_options,const std::string & value,std::unique_ptr<TestCustomizable> * result)261 Status TestCustomizable::CreateFromString(
262     const ConfigOptions& config_options, const std::string& value,
263     std::unique_ptr<TestCustomizable>* result) {
264   return LoadUniqueObject<TestCustomizable>(
265       config_options, value,
266       [](const std::string& id, std::unique_ptr<TestCustomizable>* u) {
267         if (id == "B") {
268           u->reset(new BCustomizable(id));
269           return true;
270         } else if (id.empty()) {
271           u->reset();
272           return true;
273         } else {
274           return false;
275         }
276       },
277       result);
278 }
279 
CreateFromString(const ConfigOptions & config_options,const std::string & value,TestCustomizable ** result)280 Status TestCustomizable::CreateFromString(const ConfigOptions& config_options,
281                                           const std::string& value,
282                                           TestCustomizable** result) {
283   return LoadStaticObject<TestCustomizable>(
284       config_options, value,
285       [](const std::string& id, TestCustomizable** ptr) {
286         if (id == "B") {
287           *ptr = new BCustomizable(id);
288           return true;
289         } else if (id.empty()) {
290           *ptr = nullptr;
291           return true;
292         } else {
293           return false;
294         }
295       },
296       result);
297 }
298 #endif  // ROCKSDB_LITE
299 
300 class CustomizableTest : public testing::Test {
301  public:
CustomizableTest()302   CustomizableTest() {
303     config_options_.invoke_prepare_options = false;
304 #ifndef ROCKSDB_LITE
305     // GetOptionsFromMap is not supported in ROCKSDB_LITE
306     config_options_.registry->AddLibrary("CustomizableTest",
307                                          RegisterCustomTestObjects, "");
308 #endif  // ROCKSDB_LITE
309   }
310 
311   ConfigOptions config_options_;
312 };
313 
314 #ifndef ROCKSDB_LITE  // GetOptionsFromMap is not supported in ROCKSDB_LITE
315 // Tests that a Customizable can be created by:
316 //    - a simple name
317 //    - a XXX.id option
318 //    - a property with a name
TEST_F(CustomizableTest,CreateByNameTest)319 TEST_F(CustomizableTest, CreateByNameTest) {
320   ObjectLibrary::Default()->Register<TestCustomizable>(
321       "TEST.*",
322       [](const std::string& name, std::unique_ptr<TestCustomizable>* guard,
323          std::string* /* msg */) {
324         guard->reset(new TestCustomizable(name));
325         return guard->get();
326       });
327   std::unique_ptr<Configurable> configurable(new SimpleConfigurable());
328   SimpleOptions* simple = configurable->GetOptions<SimpleOptions>();
329   ASSERT_NE(simple, nullptr);
330   ASSERT_OK(
331       configurable->ConfigureFromString(config_options_, "unique={id=TEST_1}"));
332   ASSERT_NE(simple->cu, nullptr);
333   ASSERT_EQ(simple->cu->GetId(), "TEST_1");
334   ASSERT_OK(
335       configurable->ConfigureFromString(config_options_, "unique.id=TEST_2"));
336   ASSERT_NE(simple->cu, nullptr);
337   ASSERT_EQ(simple->cu->GetId(), "TEST_2");
338   ASSERT_OK(
339       configurable->ConfigureFromString(config_options_, "unique=TEST_3"));
340   ASSERT_NE(simple->cu, nullptr);
341   ASSERT_EQ(simple->cu->GetId(), "TEST_3");
342 }
343 
TEST_F(CustomizableTest,ToStringTest)344 TEST_F(CustomizableTest, ToStringTest) {
345   std::unique_ptr<TestCustomizable> custom(new TestCustomizable("test"));
346   ASSERT_EQ(custom->ToString(config_options_), "test");
347 }
348 
TEST_F(CustomizableTest,SimpleConfigureTest)349 TEST_F(CustomizableTest, SimpleConfigureTest) {
350   std::unordered_map<std::string, std::string> opt_map = {
351       {"unique", "id=A;int=1;bool=true"},
352       {"shared", "id=B;string=s"},
353   };
354   std::unique_ptr<Configurable> configurable(new SimpleConfigurable());
355   ASSERT_OK(configurable->ConfigureFromMap(config_options_, opt_map));
356   SimpleOptions* simple = configurable->GetOptions<SimpleOptions>();
357   ASSERT_NE(simple, nullptr);
358   ASSERT_NE(simple->cu, nullptr);
359   ASSERT_EQ(simple->cu->GetId(), "A");
360   std::string opt_str;
361   std::string mismatch;
362   ASSERT_OK(configurable->GetOptionString(config_options_, &opt_str));
363   std::unique_ptr<Configurable> copy(new SimpleConfigurable());
364   ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
365   ASSERT_TRUE(
366       configurable->AreEquivalent(config_options_, copy.get(), &mismatch));
367 }
368 
TEST_F(CustomizableTest,ConfigureFromPropsTest)369 TEST_F(CustomizableTest, ConfigureFromPropsTest) {
370   std::unordered_map<std::string, std::string> opt_map = {
371       {"unique.id", "A"}, {"unique.A.int", "1"},    {"unique.A.bool", "true"},
372       {"shared.id", "B"}, {"shared.B.string", "s"},
373   };
374   std::unique_ptr<Configurable> configurable(new SimpleConfigurable());
375   ASSERT_OK(configurable->ConfigureFromMap(config_options_, opt_map));
376   SimpleOptions* simple = configurable->GetOptions<SimpleOptions>();
377   ASSERT_NE(simple, nullptr);
378   ASSERT_NE(simple->cu, nullptr);
379   ASSERT_EQ(simple->cu->GetId(), "A");
380   std::string opt_str;
381   std::string mismatch;
382   config_options_.delimiter = "\n";
383   std::unordered_map<std::string, std::string> props;
384   ASSERT_OK(configurable->GetOptionString(config_options_, &opt_str));
385   GetMapFromProperties(opt_str, &props);
386   std::unique_ptr<Configurable> copy(new SimpleConfigurable());
387   ASSERT_OK(copy->ConfigureFromMap(config_options_, props));
388   ASSERT_TRUE(
389       configurable->AreEquivalent(config_options_, copy.get(), &mismatch));
390 }
391 
TEST_F(CustomizableTest,ConfigureFromShortTest)392 TEST_F(CustomizableTest, ConfigureFromShortTest) {
393   std::unordered_map<std::string, std::string> opt_map = {
394       {"unique.id", "A"}, {"unique.A.int", "1"},    {"unique.A.bool", "true"},
395       {"shared.id", "B"}, {"shared.B.string", "s"},
396   };
397   std::unique_ptr<Configurable> configurable(new SimpleConfigurable());
398   ASSERT_OK(configurable->ConfigureFromMap(config_options_, opt_map));
399   SimpleOptions* simple = configurable->GetOptions<SimpleOptions>();
400   ASSERT_NE(simple, nullptr);
401   ASSERT_NE(simple->cu, nullptr);
402   ASSERT_EQ(simple->cu->GetId(), "A");
403 }
404 
TEST_F(CustomizableTest,AreEquivalentOptionsTest)405 TEST_F(CustomizableTest, AreEquivalentOptionsTest) {
406   std::unordered_map<std::string, std::string> opt_map = {
407       {"unique", "id=A;int=1;bool=true"},
408       {"shared", "id=A;int=1;bool=true"},
409   };
410   std::string mismatch;
411   ConfigOptions config_options = config_options_;
412   std::unique_ptr<Configurable> c1(new SimpleConfigurable());
413   std::unique_ptr<Configurable> c2(new SimpleConfigurable());
414   ASSERT_OK(c1->ConfigureFromMap(config_options, opt_map));
415   ASSERT_OK(c2->ConfigureFromMap(config_options, opt_map));
416   ASSERT_TRUE(c1->AreEquivalent(config_options, c2.get(), &mismatch));
417   SimpleOptions* simple = c1->GetOptions<SimpleOptions>();
418   ASSERT_TRUE(
419       simple->cu->AreEquivalent(config_options, simple->cs.get(), &mismatch));
420   ASSERT_OK(simple->cu->ConfigureOption(config_options, "int", "2"));
421   ASSERT_FALSE(
422       simple->cu->AreEquivalent(config_options, simple->cs.get(), &mismatch));
423   ASSERT_FALSE(c1->AreEquivalent(config_options, c2.get(), &mismatch));
424   ConfigOptions loosely = config_options;
425   loosely.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
426   ASSERT_TRUE(c1->AreEquivalent(loosely, c2.get(), &mismatch));
427   ASSERT_TRUE(simple->cu->AreEquivalent(loosely, simple->cs.get(), &mismatch));
428 
429   ASSERT_OK(c1->ConfigureOption(config_options, "shared", "id=B;string=3"));
430   ASSERT_TRUE(c1->AreEquivalent(loosely, c2.get(), &mismatch));
431   ASSERT_FALSE(c1->AreEquivalent(config_options, c2.get(), &mismatch));
432   ASSERT_FALSE(simple->cs->AreEquivalent(loosely, simple->cu.get(), &mismatch));
433   simple->cs.reset();
434   ASSERT_TRUE(c1->AreEquivalent(loosely, c2.get(), &mismatch));
435   ASSERT_FALSE(c1->AreEquivalent(config_options, c2.get(), &mismatch));
436 }
437 
438 // Tests that we can initialize a customizable from its options
TEST_F(CustomizableTest,ConfigureStandaloneCustomTest)439 TEST_F(CustomizableTest, ConfigureStandaloneCustomTest) {
440   std::unique_ptr<TestCustomizable> base, copy;
441   const auto& registry = config_options_.registry;
442   ASSERT_OK(registry->NewUniqueObject<TestCustomizable>("A", &base));
443   ASSERT_OK(registry->NewUniqueObject<TestCustomizable>("A", &copy));
444   ASSERT_OK(base->ConfigureFromString(config_options_, "int=33;bool=true"));
445   std::string opt_str;
446   std::string mismatch;
447   ASSERT_OK(base->GetOptionString(config_options_, &opt_str));
448   ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
449   ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
450 }
451 
452 // Tests that we fail appropriately if the pattern is not registered
TEST_F(CustomizableTest,BadNameTest)453 TEST_F(CustomizableTest, BadNameTest) {
454   config_options_.ignore_unsupported_options = false;
455   std::unique_ptr<Configurable> c1(new SimpleConfigurable());
456   ASSERT_NOK(
457       c1->ConfigureFromString(config_options_, "unique.shared.id=bad name"));
458   config_options_.ignore_unsupported_options = true;
459   ASSERT_OK(
460       c1->ConfigureFromString(config_options_, "unique.shared.id=bad name"));
461 }
462 
463 // Tests that we fail appropriately if a bad option is passed to the underlying
464 // configurable
TEST_F(CustomizableTest,BadOptionTest)465 TEST_F(CustomizableTest, BadOptionTest) {
466   std::unique_ptr<Configurable> c1(new SimpleConfigurable());
467   ConfigOptions ignore = config_options_;
468   ignore.ignore_unknown_options = true;
469 
470   ASSERT_NOK(c1->ConfigureFromString(config_options_, "A.int=11"));
471   ASSERT_NOK(c1->ConfigureFromString(config_options_, "shared={id=B;int=1}"));
472   ASSERT_OK(c1->ConfigureFromString(ignore, "shared={id=A;string=s}"));
473   ASSERT_NOK(c1->ConfigureFromString(config_options_, "B.int=11"));
474   ASSERT_OK(c1->ConfigureFromString(ignore, "B.int=11"));
475   ASSERT_NOK(c1->ConfigureFromString(config_options_, "A.string=s"));
476   ASSERT_OK(c1->ConfigureFromString(ignore, "A.string=s"));
477   // Test as detached
478   ASSERT_NOK(
479       c1->ConfigureFromString(config_options_, "shared.id=A;A.string=b}"));
480   ASSERT_OK(c1->ConfigureFromString(ignore, "shared.id=A;A.string=s}"));
481 }
482 
483 // Tests that different IDs lead to different objects
TEST_F(CustomizableTest,UniqueIdTest)484 TEST_F(CustomizableTest, UniqueIdTest) {
485   std::unique_ptr<Configurable> base(new SimpleConfigurable());
486   ASSERT_OK(base->ConfigureFromString(config_options_,
487                                       "unique={id=A_1;int=1;bool=true}"));
488   SimpleOptions* simple = base->GetOptions<SimpleOptions>();
489   ASSERT_NE(simple, nullptr);
490   ASSERT_NE(simple->cu, nullptr);
491   ASSERT_EQ(simple->cu->GetId(), std::string("A_1"));
492   std::string opt_str;
493   std::string mismatch;
494   ASSERT_OK(base->GetOptionString(config_options_, &opt_str));
495   std::unique_ptr<Configurable> copy(new SimpleConfigurable());
496   ASSERT_OK(copy->ConfigureFromString(config_options_, opt_str));
497   ASSERT_TRUE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
498   ASSERT_OK(base->ConfigureFromString(config_options_,
499                                       "unique={id=A_2;int=1;bool=true}"));
500   ASSERT_FALSE(base->AreEquivalent(config_options_, copy.get(), &mismatch));
501   ASSERT_EQ(simple->cu->GetId(), std::string("A_2"));
502 }
503 
TEST_F(CustomizableTest,IsInstanceOfTest)504 TEST_F(CustomizableTest, IsInstanceOfTest) {
505   std::shared_ptr<TestCustomizable> tc = std::make_shared<ACustomizable>("A_1");
506 
507   ASSERT_EQ(tc->GetId(), std::string("A_1"));
508   ASSERT_TRUE(tc->IsInstanceOf("A"));
509   ASSERT_TRUE(tc->IsInstanceOf("TestCustomizable"));
510   ASSERT_FALSE(tc->IsInstanceOf("B"));
511   ASSERT_FALSE(tc->IsInstanceOf("A_1"));
512   ASSERT_EQ(tc->CheckedCast<ACustomizable>(), tc.get());
513   ASSERT_EQ(tc->CheckedCast<TestCustomizable>(), tc.get());
514   ASSERT_EQ(tc->CheckedCast<BCustomizable>(), nullptr);
515 
516   tc.reset(new BCustomizable("B"));
517   ASSERT_TRUE(tc->IsInstanceOf("B"));
518   ASSERT_TRUE(tc->IsInstanceOf("TestCustomizable"));
519   ASSERT_FALSE(tc->IsInstanceOf("A"));
520   ASSERT_EQ(tc->CheckedCast<BCustomizable>(), tc.get());
521   ASSERT_EQ(tc->CheckedCast<TestCustomizable>(), tc.get());
522   ASSERT_EQ(tc->CheckedCast<ACustomizable>(), nullptr);
523 }
524 
TEST_F(CustomizableTest,PrepareOptionsTest)525 TEST_F(CustomizableTest, PrepareOptionsTest) {
526   static std::unordered_map<std::string, OptionTypeInfo> p_option_info = {
527 #ifndef ROCKSDB_LITE
528       {"can_prepare",
529        {0, OptionType::kBoolean, OptionVerificationType::kNormal,
530         OptionTypeFlags::kNone}},
531 #endif  // ROCKSDB_LITE
532   };
533 
534   class PrepareCustomizable : public TestCustomizable {
535    public:
536     bool can_prepare_ = true;
537 
538     PrepareCustomizable() : TestCustomizable("P") {
539       RegisterOptions("Prepare", &can_prepare_, &p_option_info);
540     }
541 
542     Status PrepareOptions(const ConfigOptions& opts) override {
543       if (!can_prepare_) {
544         return Status::InvalidArgument("Cannot Prepare");
545       } else {
546         return TestCustomizable::PrepareOptions(opts);
547       }
548     }
549   };
550 
551   ObjectLibrary::Default()->Register<TestCustomizable>(
552       "P",
553       [](const std::string& /*name*/, std::unique_ptr<TestCustomizable>* guard,
554          std::string* /* msg */) {
555         guard->reset(new PrepareCustomizable());
556         return guard->get();
557       });
558 
559   std::unique_ptr<Configurable> base(new SimpleConfigurable());
560   ConfigOptions prepared(config_options_);
561   prepared.invoke_prepare_options = true;
562 
563   ASSERT_OK(base->ConfigureFromString(
564       prepared, "unique=A_1; shared={id=B;string=s}; pointer.id=S"));
565   SimpleOptions* simple = base->GetOptions<SimpleOptions>();
566   ASSERT_NE(simple, nullptr);
567   ASSERT_NE(simple->cu, nullptr);
568   ASSERT_NE(simple->cs, nullptr);
569   ASSERT_NE(simple->cp, nullptr);
570   delete simple->cp;
571   base.reset(new SimpleConfigurable());
572   ASSERT_OK(base->ConfigureFromString(
573       config_options_, "unique=A_1; shared={id=B;string=s}; pointer.id=S"));
574 
575   simple = base->GetOptions<SimpleOptions>();
576   ASSERT_NE(simple, nullptr);
577   ASSERT_NE(simple->cu, nullptr);
578   ASSERT_NE(simple->cs, nullptr);
579   ASSERT_NE(simple->cp, nullptr);
580 
581   ASSERT_OK(base->PrepareOptions(config_options_));
582   delete simple->cp;
583   base.reset(new SimpleConfigurable());
584   simple = base->GetOptions<SimpleOptions>();
585   ASSERT_NE(simple, nullptr);
586 
587   ASSERT_NOK(
588       base->ConfigureFromString(prepared, "unique={id=P; can_prepare=false}"));
589   ASSERT_EQ(simple->cu, nullptr);
590 
591   ASSERT_OK(
592       base->ConfigureFromString(prepared, "unique={id=P; can_prepare=true}"));
593   ASSERT_NE(simple->cu, nullptr);
594 
595   ASSERT_OK(base->ConfigureFromString(config_options_,
596                                       "unique={id=P; can_prepare=true}"));
597   ASSERT_NE(simple->cu, nullptr);
598   ASSERT_OK(simple->cu->PrepareOptions(prepared));
599 
600   ASSERT_OK(base->ConfigureFromString(config_options_,
601                                       "unique={id=P; can_prepare=false}"));
602   ASSERT_NE(simple->cu, nullptr);
603   ASSERT_NOK(simple->cu->PrepareOptions(prepared));
604 }
605 
606 namespace {
607 static std::unordered_map<std::string, OptionTypeInfo> inner_option_info = {
608 #ifndef ROCKSDB_LITE
609     {"inner",
610      OptionTypeInfo::AsCustomSharedPtr<TestCustomizable>(
611          0, OptionVerificationType::kNormal, OptionTypeFlags::kStringNameOnly)}
612 #endif  // ROCKSDB_LITE
613 };
614 
615 class InnerCustomizable : public Customizable {
616  public:
InnerCustomizable(const std::shared_ptr<Customizable> & w)617   explicit InnerCustomizable(const std::shared_ptr<Customizable>& w)
618       : inner_(w) {}
kClassName()619   static const char* kClassName() { return "Inner"; }
IsInstanceOf(const std::string & name) const620   bool IsInstanceOf(const std::string& name) const override {
621     if (name == kClassName()) {
622       return true;
623     } else {
624       return Customizable::IsInstanceOf(name);
625     }
626   }
627 
628  protected:
Inner() const629   const Customizable* Inner() const override { return inner_.get(); }
630 
631  private:
632   std::shared_ptr<Customizable> inner_;
633 };
634 
635 class WrappedCustomizable1 : public InnerCustomizable {
636  public:
WrappedCustomizable1(const std::shared_ptr<Customizable> & w)637   explicit WrappedCustomizable1(const std::shared_ptr<Customizable>& w)
638       : InnerCustomizable(w) {}
Name() const639   const char* Name() const override { return kClassName(); }
kClassName()640   static const char* kClassName() { return "Wrapped1"; }
641 };
642 
643 class WrappedCustomizable2 : public InnerCustomizable {
644  public:
WrappedCustomizable2(const std::shared_ptr<Customizable> & w)645   explicit WrappedCustomizable2(const std::shared_ptr<Customizable>& w)
646       : InnerCustomizable(w) {}
Name() const647   const char* Name() const override { return kClassName(); }
kClassName()648   static const char* kClassName() { return "Wrapped2"; }
649 };
650 }  // namespace
651 
TEST_F(CustomizableTest,WrappedInnerTest)652 TEST_F(CustomizableTest, WrappedInnerTest) {
653   std::shared_ptr<TestCustomizable> ac =
654       std::make_shared<TestCustomizable>("A");
655 
656   ASSERT_TRUE(ac->IsInstanceOf("A"));
657   ASSERT_TRUE(ac->IsInstanceOf("TestCustomizable"));
658   ASSERT_EQ(ac->CheckedCast<TestCustomizable>(), ac.get());
659   ASSERT_EQ(ac->CheckedCast<InnerCustomizable>(), nullptr);
660   ASSERT_EQ(ac->CheckedCast<WrappedCustomizable1>(), nullptr);
661   ASSERT_EQ(ac->CheckedCast<WrappedCustomizable2>(), nullptr);
662   std::shared_ptr<Customizable> wc1 =
663       std::make_shared<WrappedCustomizable1>(ac);
664 
665   ASSERT_TRUE(wc1->IsInstanceOf(WrappedCustomizable1::kClassName()));
666   ASSERT_EQ(wc1->CheckedCast<WrappedCustomizable1>(), wc1.get());
667   ASSERT_EQ(wc1->CheckedCast<WrappedCustomizable2>(), nullptr);
668   ASSERT_EQ(wc1->CheckedCast<InnerCustomizable>(), wc1.get());
669   ASSERT_EQ(wc1->CheckedCast<TestCustomizable>(), ac.get());
670 
671   std::shared_ptr<Customizable> wc2 =
672       std::make_shared<WrappedCustomizable2>(wc1);
673   ASSERT_TRUE(wc2->IsInstanceOf(WrappedCustomizable2::kClassName()));
674   ASSERT_EQ(wc2->CheckedCast<WrappedCustomizable2>(), wc2.get());
675   ASSERT_EQ(wc2->CheckedCast<WrappedCustomizable1>(), wc1.get());
676   ASSERT_EQ(wc2->CheckedCast<InnerCustomizable>(), wc2.get());
677   ASSERT_EQ(wc2->CheckedCast<TestCustomizable>(), ac.get());
678 }
679 
TEST_F(CustomizableTest,CopyObjectTest)680 TEST_F(CustomizableTest, CopyObjectTest) {
681   class CopyCustomizable : public Customizable {
682    public:
683     CopyCustomizable() : prepared_(0), validated_(0) {}
684     const char* Name() const override { return "CopyCustomizable"; }
685 
686     Status PrepareOptions(const ConfigOptions& options) override {
687       prepared_++;
688       return Customizable::PrepareOptions(options);
689     }
690     Status ValidateOptions(const DBOptions& db_opts,
691                            const ColumnFamilyOptions& cf_opts) const override {
692       validated_++;
693       return Customizable::ValidateOptions(db_opts, cf_opts);
694     }
695     int prepared_;
696     mutable int validated_;
697   };
698 
699   CopyCustomizable c1;
700   ConfigOptions config_options;
701   Options options;
702 
703   ASSERT_OK(c1.PrepareOptions(config_options));
704   ASSERT_OK(c1.ValidateOptions(options, options));
705   ASSERT_EQ(c1.prepared_, 1);
706   ASSERT_EQ(c1.validated_, 1);
707   CopyCustomizable c2 = c1;
708   ASSERT_OK(c1.PrepareOptions(config_options));
709   ASSERT_OK(c1.ValidateOptions(options, options));
710   ASSERT_EQ(c2.prepared_, 1);
711   ASSERT_EQ(c2.validated_, 1);
712   ASSERT_EQ(c1.prepared_, 2);
713   ASSERT_EQ(c1.validated_, 2);
714 }
715 
TEST_F(CustomizableTest,TestStringDepth)716 TEST_F(CustomizableTest, TestStringDepth) {
717   class ShallowCustomizable : public Customizable {
718    public:
719     ShallowCustomizable() {
720       inner_ = std::make_shared<ACustomizable>("a");
721       RegisterOptions("inner", &inner_, &inner_option_info);
722     }
723     static const char* kClassName() { return "shallow"; }
724     const char* Name() const override { return kClassName(); }
725 
726    private:
727     std::shared_ptr<TestCustomizable> inner_;
728   };
729   ConfigOptions shallow = config_options_;
730   std::unique_ptr<Configurable> c(new ShallowCustomizable());
731   std::string opt_str;
732   shallow.depth = ConfigOptions::Depth::kDepthShallow;
733   ASSERT_OK(c->GetOptionString(shallow, &opt_str));
734   ASSERT_EQ(opt_str, "inner=a;");
735   shallow.depth = ConfigOptions::Depth::kDepthDetailed;
736   ASSERT_OK(c->GetOptionString(shallow, &opt_str));
737   ASSERT_NE(opt_str, "inner=a;");
738 }
739 
740 // Tests that we only get a new customizable when it changes
TEST_F(CustomizableTest,NewUniqueCustomizableTest)741 TEST_F(CustomizableTest, NewUniqueCustomizableTest) {
742   std::unique_ptr<Configurable> base(new SimpleConfigurable());
743   A_count = 0;
744   ASSERT_OK(base->ConfigureFromString(config_options_,
745                                       "unique={id=A_1;int=1;bool=true}"));
746   SimpleOptions* simple = base->GetOptions<SimpleOptions>();
747   ASSERT_NE(simple, nullptr);
748   ASSERT_NE(simple->cu, nullptr);
749   ASSERT_EQ(A_count, 1);  // Created one A
750   ASSERT_OK(base->ConfigureFromString(config_options_,
751                                       "unique={id=A_1;int=1;bool=false}"));
752   ASSERT_EQ(A_count, 2);  // Create another A_1
753   ASSERT_OK(base->ConfigureFromString(config_options_, "unique={id=}"));
754   ASSERT_EQ(simple->cu, nullptr);
755   ASSERT_EQ(A_count, 2);
756   ASSERT_OK(base->ConfigureFromString(config_options_,
757                                       "unique={id=A_2;int=1;bool=false}"));
758   ASSERT_EQ(A_count, 3);  // Created another A
759   ASSERT_OK(base->ConfigureFromString(config_options_, "unique.id="));
760   ASSERT_EQ(simple->cu, nullptr);
761   ASSERT_OK(base->ConfigureFromString(config_options_, "unique=nullptr"));
762   ASSERT_EQ(simple->cu, nullptr);
763   ASSERT_OK(base->ConfigureFromString(config_options_, "unique.id=nullptr"));
764   ASSERT_EQ(simple->cu, nullptr);
765   ASSERT_EQ(A_count, 3);
766 }
767 
TEST_F(CustomizableTest,NewEmptyUniqueTest)768 TEST_F(CustomizableTest, NewEmptyUniqueTest) {
769   std::unique_ptr<Configurable> base(new SimpleConfigurable());
770   SimpleOptions* simple = base->GetOptions<SimpleOptions>();
771   ASSERT_EQ(simple->cu, nullptr);
772   simple->cu.reset(new BCustomizable("B"));
773 
774   ASSERT_OK(base->ConfigureFromString(config_options_, "unique={id=}"));
775   ASSERT_EQ(simple->cu, nullptr);
776   simple->cu.reset(new BCustomizable("B"));
777 
778   ASSERT_OK(base->ConfigureFromString(config_options_, "unique={id=nullptr}"));
779   ASSERT_EQ(simple->cu, nullptr);
780   simple->cu.reset(new BCustomizable("B"));
781 
782   ASSERT_OK(base->ConfigureFromString(config_options_, "unique.id="));
783   ASSERT_EQ(simple->cu, nullptr);
784   simple->cu.reset(new BCustomizable("B"));
785 
786   ASSERT_OK(base->ConfigureFromString(config_options_, "unique=nullptr"));
787   ASSERT_EQ(simple->cu, nullptr);
788   simple->cu.reset(new BCustomizable("B"));
789 
790   ASSERT_OK(base->ConfigureFromString(config_options_, "unique.id=nullptr"));
791   ASSERT_EQ(simple->cu, nullptr);
792 }
793 
TEST_F(CustomizableTest,NewEmptySharedTest)794 TEST_F(CustomizableTest, NewEmptySharedTest) {
795   std::unique_ptr<Configurable> base(new SimpleConfigurable());
796 
797   SimpleOptions* simple = base->GetOptions<SimpleOptions>();
798   ASSERT_NE(simple, nullptr);
799   ASSERT_EQ(simple->cs, nullptr);
800   simple->cs.reset(new BCustomizable("B"));
801 
802   ASSERT_OK(base->ConfigureFromString(config_options_, "shared={id=}"));
803   ASSERT_NE(simple, nullptr);
804   ASSERT_EQ(simple->cs, nullptr);
805   simple->cs.reset(new BCustomizable("B"));
806 
807   ASSERT_OK(base->ConfigureFromString(config_options_, "shared={id=nullptr}"));
808   ASSERT_EQ(simple->cs, nullptr);
809   simple->cs.reset(new BCustomizable("B"));
810 
811   ASSERT_OK(base->ConfigureFromString(config_options_, "shared.id="));
812   ASSERT_EQ(simple->cs, nullptr);
813   simple->cs.reset(new BCustomizable("B"));
814 
815   ASSERT_OK(base->ConfigureFromString(config_options_, "shared.id=nullptr"));
816   ASSERT_EQ(simple->cs, nullptr);
817   simple->cs.reset(new BCustomizable("B"));
818 
819   ASSERT_OK(base->ConfigureFromString(config_options_, "shared=nullptr"));
820   ASSERT_EQ(simple->cs, nullptr);
821 }
822 
TEST_F(CustomizableTest,NewEmptyStaticTest)823 TEST_F(CustomizableTest, NewEmptyStaticTest) {
824   std::unique_ptr<Configurable> base(new SimpleConfigurable());
825   ASSERT_OK(base->ConfigureFromString(config_options_, "pointer={id=}"));
826   SimpleOptions* simple = base->GetOptions<SimpleOptions>();
827   ASSERT_NE(simple, nullptr);
828   ASSERT_EQ(simple->cp, nullptr);
829   ASSERT_OK(base->ConfigureFromString(config_options_, "pointer={id=nullptr}"));
830   ASSERT_EQ(simple->cp, nullptr);
831 
832   ASSERT_OK(base->ConfigureFromString(config_options_, "pointer="));
833   ASSERT_EQ(simple->cp, nullptr);
834   ASSERT_OK(base->ConfigureFromString(config_options_, "pointer=nullptr"));
835   ASSERT_EQ(simple->cp, nullptr);
836 
837   ASSERT_OK(base->ConfigureFromString(config_options_, "pointer.id="));
838   ASSERT_EQ(simple->cp, nullptr);
839   ASSERT_OK(base->ConfigureFromString(config_options_, "pointer.id=nullptr"));
840   ASSERT_EQ(simple->cp, nullptr);
841 }
842 
843 namespace {
844 #ifndef ROCKSDB_LITE
845 static std::unordered_map<std::string, OptionTypeInfo> vector_option_info = {
846     {"vector",
847      OptionTypeInfo::Vector<std::shared_ptr<TestCustomizable>>(
848          0, OptionVerificationType::kNormal,
849 
850          OptionTypeFlags::kNone,
851 
852          OptionTypeInfo::AsCustomSharedPtr<TestCustomizable>(
853              0, OptionVerificationType::kNormal, OptionTypeFlags::kNone))},
854 };
855 class VectorConfigurable : public SimpleConfigurable {
856  public:
VectorConfigurable()857   VectorConfigurable() { RegisterOptions("vector", &cv, &vector_option_info); }
858   std::vector<std::shared_ptr<TestCustomizable>> cv;
859 };
860 }  // namespace
861 
TEST_F(CustomizableTest,VectorConfigTest)862 TEST_F(CustomizableTest, VectorConfigTest) {
863   VectorConfigurable orig, copy;
864   std::shared_ptr<TestCustomizable> c1, c2;
865   ASSERT_OK(TestCustomizable::CreateFromString(config_options_, "A", &c1));
866   ASSERT_OK(TestCustomizable::CreateFromString(config_options_, "B", &c2));
867   orig.cv.push_back(c1);
868   orig.cv.push_back(c2);
869   ASSERT_OK(orig.ConfigureFromString(config_options_, "unique=A2"));
870   std::string opt_str, mismatch;
871   ASSERT_OK(orig.GetOptionString(config_options_, &opt_str));
872   ASSERT_OK(copy.ConfigureFromString(config_options_, opt_str));
873   ASSERT_TRUE(orig.AreEquivalent(config_options_, &copy, &mismatch));
874 }
875 
TEST_F(CustomizableTest,NoNameTest)876 TEST_F(CustomizableTest, NoNameTest) {
877   // If Customizables are created without names, they are not
878   // part of the serialization (since they cannot be recreated)
879   VectorConfigurable orig, copy;
880   auto sopts = orig.GetOptions<SimpleOptions>();
881   auto copts = copy.GetOptions<SimpleOptions>();
882   sopts->cu.reset(new ACustomizable(""));
883   orig.cv.push_back(std::make_shared<ACustomizable>(""));
884   orig.cv.push_back(std::make_shared<ACustomizable>("A1"));
885   std::string opt_str, mismatch;
886   ASSERT_OK(orig.GetOptionString(config_options_, &opt_str));
887   ASSERT_OK(copy.ConfigureFromString(config_options_, opt_str));
888   ASSERT_EQ(copy.cv.size(), 1U);
889   ASSERT_EQ(copy.cv[0]->GetId(), "A1");
890   ASSERT_EQ(copts->cu, nullptr);
891 }
892 
893 #endif  // ROCKSDB_LITE
894 
TEST_F(CustomizableTest,IgnoreUnknownObjects)895 TEST_F(CustomizableTest, IgnoreUnknownObjects) {
896   ConfigOptions ignore = config_options_;
897   std::shared_ptr<TestCustomizable> shared;
898   std::unique_ptr<TestCustomizable> unique;
899   TestCustomizable* pointer = nullptr;
900   ignore.ignore_unsupported_options = false;
901   ASSERT_NOK(
902       LoadSharedObject<TestCustomizable>(ignore, "Unknown", nullptr, &shared));
903   ASSERT_NOK(
904       LoadUniqueObject<TestCustomizable>(ignore, "Unknown", nullptr, &unique));
905   ASSERT_NOK(
906       LoadStaticObject<TestCustomizable>(ignore, "Unknown", nullptr, &pointer));
907   ASSERT_EQ(shared.get(), nullptr);
908   ASSERT_EQ(unique.get(), nullptr);
909   ASSERT_EQ(pointer, nullptr);
910   ignore.ignore_unsupported_options = true;
911   ASSERT_OK(
912       LoadSharedObject<TestCustomizable>(ignore, "Unknown", nullptr, &shared));
913   ASSERT_OK(
914       LoadUniqueObject<TestCustomizable>(ignore, "Unknown", nullptr, &unique));
915   ASSERT_OK(
916       LoadStaticObject<TestCustomizable>(ignore, "Unknown", nullptr, &pointer));
917   ASSERT_EQ(shared.get(), nullptr);
918   ASSERT_EQ(unique.get(), nullptr);
919   ASSERT_EQ(pointer, nullptr);
920   ASSERT_OK(LoadSharedObject<TestCustomizable>(ignore, "id=Unknown", nullptr,
921                                                &shared));
922   ASSERT_OK(LoadUniqueObject<TestCustomizable>(ignore, "id=Unknown", nullptr,
923                                                &unique));
924   ASSERT_OK(LoadStaticObject<TestCustomizable>(ignore, "id=Unknown", nullptr,
925                                                &pointer));
926   ASSERT_EQ(shared.get(), nullptr);
927   ASSERT_EQ(unique.get(), nullptr);
928   ASSERT_EQ(pointer, nullptr);
929   ASSERT_OK(LoadSharedObject<TestCustomizable>(ignore, "id=Unknown;option=bad",
930                                                nullptr, &shared));
931   ASSERT_OK(LoadUniqueObject<TestCustomizable>(ignore, "id=Unknown;option=bad",
932                                                nullptr, &unique));
933   ASSERT_OK(LoadStaticObject<TestCustomizable>(ignore, "id=Unknown;option=bad",
934                                                nullptr, &pointer));
935   ASSERT_EQ(shared.get(), nullptr);
936   ASSERT_EQ(unique.get(), nullptr);
937   ASSERT_EQ(pointer, nullptr);
938 }
939 
TEST_F(CustomizableTest,FactoryFunctionTest)940 TEST_F(CustomizableTest, FactoryFunctionTest) {
941   std::shared_ptr<TestCustomizable> shared;
942   std::unique_ptr<TestCustomizable> unique;
943   TestCustomizable* pointer = nullptr;
944   ConfigOptions ignore = config_options_;
945   ignore.ignore_unsupported_options = false;
946   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "B", &shared));
947   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "B", &unique));
948   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "B", &pointer));
949   ASSERT_NE(shared.get(), nullptr);
950   ASSERT_NE(unique.get(), nullptr);
951   ASSERT_NE(pointer, nullptr);
952   delete pointer;
953   pointer = nullptr;
954   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "id=", &shared));
955   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "id=", &unique));
956   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "id=", &pointer));
957   ASSERT_EQ(shared.get(), nullptr);
958   ASSERT_EQ(unique.get(), nullptr);
959   ASSERT_EQ(pointer, nullptr);
960   ASSERT_NOK(TestCustomizable::CreateFromString(ignore, "option=bad", &shared));
961   ASSERT_NOK(TestCustomizable::CreateFromString(ignore, "option=bad", &unique));
962   ASSERT_NOK(
963       TestCustomizable::CreateFromString(ignore, "option=bad", &pointer));
964   ASSERT_EQ(pointer, nullptr);
965 }
966 
TEST_F(CustomizableTest,URLFactoryTest)967 TEST_F(CustomizableTest, URLFactoryTest) {
968   std::unique_ptr<TestCustomizable> unique;
969   ConfigOptions ignore = config_options_;
970   ignore.ignore_unsupported_options = false;
971   ignore.ignore_unsupported_options = false;
972   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "A=1;x=y", &unique));
973   ASSERT_NE(unique, nullptr);
974   ASSERT_EQ(unique->GetId(), "A=1;x=y");
975   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "A;x=y", &unique));
976   ASSERT_NE(unique, nullptr);
977   ASSERT_EQ(unique->GetId(), "A;x=y");
978   unique.reset();
979   ASSERT_OK(TestCustomizable::CreateFromString(ignore, "A=1?x=y", &unique));
980   ASSERT_NE(unique, nullptr);
981   ASSERT_EQ(unique->GetId(), "A=1?x=y");
982 }
983 
TEST_F(CustomizableTest,MutableOptionsTest)984 TEST_F(CustomizableTest, MutableOptionsTest) {
985   static std::unordered_map<std::string, OptionTypeInfo> mutable_option_info = {
986       {"mutable",
987        OptionTypeInfo::AsCustomSharedPtr<TestCustomizable>(
988            0, OptionVerificationType::kNormal, OptionTypeFlags::kMutable)}};
989   static std::unordered_map<std::string, OptionTypeInfo> immutable_option_info =
990       {{"immutable",
991         OptionTypeInfo::AsCustomSharedPtr<TestCustomizable>(
992             0, OptionVerificationType::kNormal, OptionTypeFlags::kAllowNull)}};
993 
994   class MutableCustomizable : public Customizable {
995    private:
996     std::shared_ptr<TestCustomizable> mutable_;
997     std::shared_ptr<TestCustomizable> immutable_;
998 
999    public:
1000     MutableCustomizable() {
1001       RegisterOptions("mutable", &mutable_, &mutable_option_info);
1002       RegisterOptions("immutable", &immutable_, &immutable_option_info);
1003     }
1004     const char* Name() const override { return "MutableCustomizable"; }
1005   };
1006   MutableCustomizable mc, mc2;
1007   std::string mismatch;
1008   std::string opt_str;
1009 
1010   ConfigOptions options = config_options_;
1011   ASSERT_OK(mc.ConfigureOption(options, "mutable", "{id=B;}"));
1012   options.mutable_options_only = true;
1013   ASSERT_OK(mc.GetOptionString(options, &opt_str));
1014   ASSERT_OK(mc2.ConfigureFromString(options, opt_str));
1015   ASSERT_TRUE(mc.AreEquivalent(options, &mc2, &mismatch));
1016 
1017   options.mutable_options_only = false;
1018   ASSERT_OK(mc.ConfigureOption(options, "immutable", "{id=A; int=10}"));
1019   auto* mm = mc.GetOptions<std::shared_ptr<TestCustomizable>>("mutable");
1020   auto* im = mc.GetOptions<std::shared_ptr<TestCustomizable>>("immutable");
1021   ASSERT_NE(mm, nullptr);
1022   ASSERT_NE(mm->get(), nullptr);
1023   ASSERT_NE(im, nullptr);
1024   ASSERT_NE(im->get(), nullptr);
1025 
1026   // Now only deal with mutable options
1027   options.mutable_options_only = true;
1028 
1029   // Setting nested immutable customizable options fails
1030   ASSERT_NOK(mc.ConfigureOption(options, "immutable", "{id=B;}"));
1031   ASSERT_NOK(mc.ConfigureOption(options, "immutable.id", "B"));
1032   ASSERT_NOK(mc.ConfigureOption(options, "immutable.bool", "true"));
1033   ASSERT_NOK(mc.ConfigureOption(options, "immutable", "bool=true"));
1034   ASSERT_NOK(mc.ConfigureOption(options, "immutable", "{int=11;bool=true}"));
1035   auto* im_a = im->get()->GetOptions<AOptions>("A");
1036   ASSERT_NE(im_a, nullptr);
1037   ASSERT_EQ(im_a->i, 10);
1038   ASSERT_EQ(im_a->b, false);
1039 
1040   // Setting nested mutable customizable options succeeds but the object did not
1041   // change
1042   ASSERT_OK(mc.ConfigureOption(options, "immutable.int", "11"));
1043   ASSERT_EQ(im_a->i, 11);
1044   ASSERT_EQ(im_a, im->get()->GetOptions<AOptions>("A"));
1045 
1046   // The mutable configurable itself can be changed
1047   ASSERT_OK(mc.ConfigureOption(options, "mutable.id", "A"));
1048   ASSERT_OK(mc.ConfigureOption(options, "mutable", "A"));
1049   ASSERT_OK(mc.ConfigureOption(options, "mutable", "{id=A}"));
1050   ASSERT_OK(mc.ConfigureOption(options, "mutable", "{bool=true}"));
1051 
1052   // The Nested options in the mutable object can be changed
1053   ASSERT_OK(mc.ConfigureOption(options, "mutable", "{bool=true}"));
1054   auto* mm_a = mm->get()->GetOptions<AOptions>("A");
1055   ASSERT_EQ(mm_a->b, true);
1056   ASSERT_OK(mc.ConfigureOption(options, "mutable", "{int=22;bool=false}"));
1057   mm_a = mm->get()->GetOptions<AOptions>("A");
1058   ASSERT_EQ(mm_a->i, 22);
1059   ASSERT_EQ(mm_a->b, false);
1060 
1061   // Only the mutable options should get serialized
1062   options.mutable_options_only = false;
1063   ASSERT_OK(mc.GetOptionString(options, &opt_str));
1064   ASSERT_OK(mc.ConfigureOption(options, "immutable", "{id=B;}"));
1065   options.mutable_options_only = true;
1066 
1067   ASSERT_OK(mc.GetOptionString(options, &opt_str));
1068   ASSERT_OK(mc2.ConfigureFromString(options, opt_str));
1069   ASSERT_TRUE(mc.AreEquivalent(options, &mc2, &mismatch));
1070   options.mutable_options_only = false;
1071   ASSERT_FALSE(mc.AreEquivalent(options, &mc2, &mismatch));
1072   ASSERT_EQ(mismatch, "immutable");
1073 }
1074 
TEST_F(CustomizableTest,CustomManagedObjects)1075 TEST_F(CustomizableTest, CustomManagedObjects) {
1076   std::shared_ptr<TestCustomizable> object1, object2;
1077   ASSERT_OK(LoadManagedObject<TestCustomizable>(
1078       config_options_, "id=A_1;int=1;bool=true", &object1));
1079   ASSERT_OK(
1080       LoadManagedObject<TestCustomizable>(config_options_, "A_1", &object2));
1081   ASSERT_EQ(object1, object2);
1082   auto* opts = object2->GetOptions<AOptions>("A");
1083   ASSERT_NE(opts, nullptr);
1084   ASSERT_EQ(opts->i, 1);
1085   ASSERT_EQ(opts->b, true);
1086   ASSERT_OK(
1087       LoadManagedObject<TestCustomizable>(config_options_, "A_2", &object2));
1088   ASSERT_NE(object1, object2);
1089   object1.reset();
1090   ASSERT_OK(LoadManagedObject<TestCustomizable>(
1091       config_options_, "id=A_1;int=2;bool=false", &object1));
1092   opts = object1->GetOptions<AOptions>("A");
1093   ASSERT_NE(opts, nullptr);
1094   ASSERT_EQ(opts->i, 2);
1095   ASSERT_EQ(opts->b, false);
1096 }
1097 
TEST_F(CustomizableTest,CreateManagedObjects)1098 TEST_F(CustomizableTest, CreateManagedObjects) {
1099   class ManagedCustomizable : public Customizable {
1100    public:
1101     static const char* Type() { return "ManagedCustomizable"; }
1102     static const char* kClassName() { return "Managed"; }
1103     const char* Name() const override { return kClassName(); }
1104     std::string GetId() const override { return id_; }
1105     ManagedCustomizable() { id_ = GenerateIndividualId(); }
1106     static Status CreateFromString(
1107         const ConfigOptions& opts, const std::string& value,
1108         std::shared_ptr<ManagedCustomizable>* result) {
1109       return LoadManagedObject<ManagedCustomizable>(opts, value, result);
1110     }
1111 
1112    private:
1113     std::string id_;
1114   };
1115 
1116   config_options_.registry->AddLibrary("Managed")
1117       ->Register<ManagedCustomizable>(
1118           "Managed(@.*)?", [](const std::string& /*name*/,
1119                               std::unique_ptr<ManagedCustomizable>* guard,
1120                               std::string* /* msg */) {
1121             guard->reset(new ManagedCustomizable());
1122             return guard->get();
1123           });
1124 
1125   std::shared_ptr<ManagedCustomizable> mc1, mc2, mc3, obj;
1126   // Create a "deadbeef" customizable
1127   std::string deadbeef =
1128       std::string(ManagedCustomizable::kClassName()) + "@0xdeadbeef#0001";
1129   ASSERT_OK(
1130       ManagedCustomizable::CreateFromString(config_options_, deadbeef, &mc1));
1131   // Create an object with the base/class name
1132   ASSERT_OK(ManagedCustomizable::CreateFromString(
1133       config_options_, ManagedCustomizable::kClassName(), &mc2));
1134   // Creating another with the base name returns a different object
1135   ASSERT_OK(ManagedCustomizable::CreateFromString(
1136       config_options_, ManagedCustomizable::kClassName(), &mc3));
1137   // At this point, there should be 4 managed objects (deadbeef, mc1, 2, and 3)
1138   std::vector<std::shared_ptr<ManagedCustomizable>> objects;
1139   ASSERT_OK(config_options_.registry->ListManagedObjects(&objects));
1140   ASSERT_EQ(objects.size(), 4U);
1141   objects.clear();
1142   // Three separate object, none of them equal
1143   ASSERT_NE(mc1, mc2);
1144   ASSERT_NE(mc1, mc3);
1145   ASSERT_NE(mc2, mc3);
1146 
1147   // Creating another object with "deadbeef" object
1148   ASSERT_OK(
1149       ManagedCustomizable::CreateFromString(config_options_, deadbeef, &obj));
1150   ASSERT_EQ(mc1, obj);
1151   // Create another with the IDs of the instances
1152   ASSERT_OK(ManagedCustomizable::CreateFromString(config_options_, mc1->GetId(),
1153                                                   &obj));
1154   ASSERT_EQ(mc1, obj);
1155   ASSERT_OK(ManagedCustomizable::CreateFromString(config_options_, mc2->GetId(),
1156                                                   &obj));
1157   ASSERT_EQ(mc2, obj);
1158   ASSERT_OK(ManagedCustomizable::CreateFromString(config_options_, mc3->GetId(),
1159                                                   &obj));
1160   ASSERT_EQ(mc3, obj);
1161 
1162   // Now get rid of deadbeef.  2 Objects left (m2+m3)
1163   mc1.reset();
1164   ASSERT_EQ(
1165       config_options_.registry->GetManagedObject<ManagedCustomizable>(deadbeef),
1166       nullptr);
1167   ASSERT_OK(config_options_.registry->ListManagedObjects(&objects));
1168   ASSERT_EQ(objects.size(), 2U);
1169   objects.clear();
1170 
1171   // Associate deadbeef with #2
1172   ASSERT_OK(config_options_.registry->SetManagedObject(deadbeef, mc2));
1173   ASSERT_OK(
1174       ManagedCustomizable::CreateFromString(config_options_, deadbeef, &obj));
1175   ASSERT_EQ(mc2, obj);
1176   obj.reset();
1177 
1178   // Get the ID of mc2 and then reset it.  1 Object left
1179   std::string mc2id = mc2->GetId();
1180   mc2.reset();
1181   ASSERT_EQ(
1182       config_options_.registry->GetManagedObject<ManagedCustomizable>(mc2id),
1183       nullptr);
1184   ASSERT_OK(config_options_.registry->ListManagedObjects(&objects));
1185   ASSERT_EQ(objects.size(), 1U);
1186   objects.clear();
1187 
1188   // Create another object with the old mc2id.
1189   ASSERT_OK(
1190       ManagedCustomizable::CreateFromString(config_options_, mc2id, &mc2));
1191   ASSERT_OK(
1192       ManagedCustomizable::CreateFromString(config_options_, mc2id, &obj));
1193   ASSERT_EQ(mc2, obj);
1194 
1195   // For good measure, create another deadbeef object
1196   ASSERT_OK(
1197       ManagedCustomizable::CreateFromString(config_options_, deadbeef, &mc1));
1198   ASSERT_OK(
1199       ManagedCustomizable::CreateFromString(config_options_, deadbeef, &obj));
1200   ASSERT_EQ(mc1, obj);
1201 }
1202 
1203 #endif  // !ROCKSDB_LITE
1204 
1205 namespace {
1206 class TestSecondaryCache : public SecondaryCache {
1207  public:
kClassName()1208   static const char* kClassName() { return "Test"; }
Name() const1209   const char* Name() const override { return kClassName(); }
Insert(const Slice &,void *,const Cache::CacheItemHelper *)1210   Status Insert(const Slice& /*key*/, void* /*value*/,
1211                 const Cache::CacheItemHelper* /*helper*/) override {
1212     return Status::NotSupported();
1213   }
Lookup(const Slice &,const Cache::CreateCallback &,bool)1214   std::unique_ptr<SecondaryCacheResultHandle> Lookup(
1215       const Slice& /*key*/, const Cache::CreateCallback& /*create_cb*/,
1216       bool /*wait*/) override {
1217     return nullptr;
1218   }
Erase(const Slice &)1219   void Erase(const Slice& /*key*/) override {}
1220 
1221   // Wait for a collection of handles to become ready
WaitAll(std::vector<SecondaryCacheResultHandle * >)1222   void WaitAll(std::vector<SecondaryCacheResultHandle*> /*handles*/) override {}
1223 
GetPrintableOptions() const1224   std::string GetPrintableOptions() const override { return ""; }
1225 };
1226 
1227 class TestStatistics : public StatisticsImpl {
1228  public:
TestStatistics()1229   TestStatistics() : StatisticsImpl(nullptr) {}
Name() const1230   const char* Name() const override { return kClassName(); }
kClassName()1231   static const char* kClassName() { return "Test"; }
1232 };
1233 
1234 class TestFlushBlockPolicyFactory : public FlushBlockPolicyFactory {
1235  public:
TestFlushBlockPolicyFactory()1236   TestFlushBlockPolicyFactory() {}
1237 
kClassName()1238   static const char* kClassName() { return "TestFlushBlockPolicyFactory"; }
Name() const1239   const char* Name() const override { return kClassName(); }
1240 
NewFlushBlockPolicy(const BlockBasedTableOptions &,const BlockBuilder &) const1241   FlushBlockPolicy* NewFlushBlockPolicy(
1242       const BlockBasedTableOptions& /*table_options*/,
1243       const BlockBuilder& /*data_block_builder*/) const override {
1244     return nullptr;
1245   }
1246 };
1247 
1248 class MockSliceTransform : public SliceTransform {
1249  public:
Name() const1250   const char* Name() const override { return kClassName(); }
kClassName()1251   static const char* kClassName() { return "Mock"; }
1252 
Transform(const Slice &) const1253   Slice Transform(const Slice& /*key*/) const override { return Slice(); }
1254 
InDomain(const Slice &) const1255   bool InDomain(const Slice& /*key*/) const override { return false; }
1256 
InRange(const Slice &) const1257   bool InRange(const Slice& /*key*/) const override { return false; }
1258 };
1259 
1260 #ifndef ROCKSDB_LITE
1261 class MockEncryptionProvider : public EncryptionProvider {
1262  public:
MockEncryptionProvider(const std::string & id)1263   explicit MockEncryptionProvider(const std::string& id) : id_(id) {}
Name() const1264   const char* Name() const override { return "Mock"; }
GetPrefixLength() const1265   size_t GetPrefixLength() const override { return 0; }
CreateNewPrefix(const std::string &,char *,size_t) const1266   Status CreateNewPrefix(const std::string& /*fname*/, char* /*prefix*/,
1267                          size_t /*prefixLength*/) const override {
1268     return Status::NotSupported();
1269   }
1270 
AddCipher(const std::string &,const char *,size_t,bool)1271   Status AddCipher(const std::string& /*descriptor*/, const char* /*cipher*/,
1272                    size_t /*len*/, bool /*for_write*/) override {
1273     return Status::NotSupported();
1274   }
1275 
CreateCipherStream(const std::string &,const EnvOptions &,Slice &,std::unique_ptr<BlockAccessCipherStream> *)1276   Status CreateCipherStream(
1277       const std::string& /*fname*/, const EnvOptions& /*options*/,
1278       Slice& /*prefix*/,
1279       std::unique_ptr<BlockAccessCipherStream>* /*result*/) override {
1280     return Status::NotSupported();
1281   }
ValidateOptions(const DBOptions & db_opts,const ColumnFamilyOptions & cf_opts) const1282   Status ValidateOptions(const DBOptions& db_opts,
1283                          const ColumnFamilyOptions& cf_opts) const override {
1284     if (EndsWith(id_, "://test")) {
1285       return EncryptionProvider::ValidateOptions(db_opts, cf_opts);
1286     } else {
1287       return Status::InvalidArgument("MockProvider not initialized");
1288     }
1289   }
1290 
1291  private:
1292   std::string id_;
1293 };
1294 
1295 class MockCipher : public BlockCipher {
1296  public:
Name() const1297   const char* Name() const override { return "Mock"; }
BlockSize()1298   size_t BlockSize() override { return 0; }
Encrypt(char *)1299   Status Encrypt(char* /*data*/) override { return Status::NotSupported(); }
Decrypt(char * data)1300   Status Decrypt(char* data) override { return Encrypt(data); }
1301 };
1302 
1303 #endif  // ROCKSDB_LITE
1304 
1305 class MockTablePropertiesCollectorFactory
1306     : public TablePropertiesCollectorFactory {
1307  private:
1308  public:
CreateTablePropertiesCollector(TablePropertiesCollectorFactory::Context)1309   TablePropertiesCollector* CreateTablePropertiesCollector(
1310       TablePropertiesCollectorFactory::Context /*context*/) override {
1311     return nullptr;
1312   }
kClassName()1313   static const char* kClassName() { return "Mock"; }
Name() const1314   const char* Name() const override { return kClassName(); }
1315 };
1316 
1317 class MockSstPartitionerFactory : public SstPartitionerFactory {
1318  public:
kClassName()1319   static const char* kClassName() { return "Mock"; }
Name() const1320   const char* Name() const override { return kClassName(); }
CreatePartitioner(const SstPartitioner::Context &) const1321   std::unique_ptr<SstPartitioner> CreatePartitioner(
1322       const SstPartitioner::Context& /* context */) const override {
1323     return nullptr;
1324   }
1325 };
1326 
1327 class MockFileChecksumGenFactory : public FileChecksumGenFactory {
1328  public:
kClassName()1329   static const char* kClassName() { return "Mock"; }
Name() const1330   const char* Name() const override { return kClassName(); }
CreateFileChecksumGenerator(const FileChecksumGenContext &)1331   std::unique_ptr<FileChecksumGenerator> CreateFileChecksumGenerator(
1332       const FileChecksumGenContext& /*context*/) override {
1333     return nullptr;
1334   }
1335 };
1336 
1337 #ifndef ROCKSDB_LITE
RegisterLocalObjects(ObjectLibrary & library,const std::string &)1338 static int RegisterLocalObjects(ObjectLibrary& library,
1339                                 const std::string& /*arg*/) {
1340   size_t num_types;
1341   library.Register<TableFactory>(
1342       mock::MockTableFactory::kClassName(),
1343       [](const std::string& /*uri*/, std::unique_ptr<TableFactory>* guard,
1344          std::string* /* errmsg */) {
1345         guard->reset(new mock::MockTableFactory());
1346         return guard->get();
1347       });
1348   library.Register<EventListener>(
1349       OnFileDeletionListener::kClassName(),
1350       [](const std::string& /*uri*/, std::unique_ptr<EventListener>* guard,
1351          std::string* /* errmsg */) {
1352         guard->reset(new OnFileDeletionListener());
1353         return guard->get();
1354       });
1355   library.Register<EventListener>(
1356       FlushCounterListener::kClassName(),
1357       [](const std::string& /*uri*/, std::unique_ptr<EventListener>* guard,
1358          std::string* /* errmsg */) {
1359         guard->reset(new FlushCounterListener());
1360         return guard->get();
1361       });
1362   // Load any locally defined objects here
1363   library.Register<const SliceTransform>(
1364       MockSliceTransform::kClassName(),
1365       [](const std::string& /*uri*/,
1366          std::unique_ptr<const SliceTransform>* guard,
1367          std::string* /* errmsg */) {
1368         guard->reset(new MockSliceTransform());
1369         return guard->get();
1370       });
1371   library.Register<Statistics>(
1372       TestStatistics::kClassName(),
1373       [](const std::string& /*uri*/, std::unique_ptr<Statistics>* guard,
1374          std::string* /* errmsg */) {
1375         guard->reset(new TestStatistics());
1376         return guard->get();
1377       });
1378 
1379   library.Register<EncryptionProvider>(
1380       "Mock(://test)?",
1381       [](const std::string& uri, std::unique_ptr<EncryptionProvider>* guard,
1382          std::string* /* errmsg */) {
1383         guard->reset(new MockEncryptionProvider(uri));
1384         return guard->get();
1385       });
1386   library.Register<BlockCipher>("Mock", [](const std::string& /*uri*/,
1387                                            std::unique_ptr<BlockCipher>* guard,
1388                                            std::string* /* errmsg */) {
1389     guard->reset(new MockCipher());
1390     return guard->get();
1391   });
1392   library.Register<FlushBlockPolicyFactory>(
1393       TestFlushBlockPolicyFactory::kClassName(),
1394       [](const std::string& /*uri*/,
1395          std::unique_ptr<FlushBlockPolicyFactory>* guard,
1396          std::string* /* errmsg */) {
1397         guard->reset(new TestFlushBlockPolicyFactory());
1398         return guard->get();
1399       });
1400 
1401   library.Register<SecondaryCache>(
1402       TestSecondaryCache::kClassName(),
1403       [](const std::string& /*uri*/, std::unique_ptr<SecondaryCache>* guard,
1404          std::string* /* errmsg */) {
1405         guard->reset(new TestSecondaryCache());
1406         return guard->get();
1407       });
1408 
1409   library.Register<SstPartitionerFactory>(
1410       MockSstPartitionerFactory::kClassName(),
1411       [](const std::string& /*uri*/,
1412          std::unique_ptr<SstPartitionerFactory>* guard,
1413          std::string* /* errmsg */) {
1414         guard->reset(new MockSstPartitionerFactory());
1415         return guard->get();
1416       });
1417 
1418   library.Register<FileChecksumGenFactory>(
1419       MockFileChecksumGenFactory::kClassName(),
1420       [](const std::string& /*uri*/,
1421          std::unique_ptr<FileChecksumGenFactory>* guard,
1422          std::string* /* errmsg */) {
1423         guard->reset(new MockFileChecksumGenFactory());
1424         return guard->get();
1425       });
1426 
1427   library.Register<TablePropertiesCollectorFactory>(
1428       MockTablePropertiesCollectorFactory::kClassName(),
1429       [](const std::string& /*uri*/,
1430          std::unique_ptr<TablePropertiesCollectorFactory>* guard,
1431          std::string* /* errmsg */) {
1432         guard->reset(new MockTablePropertiesCollectorFactory());
1433         return guard->get();
1434       });
1435   return static_cast<int>(library.GetFactoryCount(&num_types));
1436 }
1437 #endif  // !ROCKSDB_LITE
1438 }  // namespace
1439 
1440 class LoadCustomizableTest : public testing::Test {
1441  public:
LoadCustomizableTest()1442   LoadCustomizableTest() {
1443     config_options_.ignore_unsupported_options = false;
1444     config_options_.invoke_prepare_options = false;
1445   }
RegisterTests(const std::string & arg)1446   bool RegisterTests(const std::string& arg) {
1447 #ifndef ROCKSDB_LITE
1448     config_options_.registry->AddLibrary("custom-tests",
1449                                          test::RegisterTestObjects, arg);
1450     config_options_.registry->AddLibrary("local-tests", RegisterLocalObjects,
1451                                          arg);
1452     return true;
1453 #else
1454     (void)arg;
1455     return false;
1456 #endif  // !ROCKSDB_LITE
1457   }
1458 
1459  protected:
1460   DBOptions db_opts_;
1461   ColumnFamilyOptions cf_opts_;
1462   ConfigOptions config_options_;
1463 };
1464 
TEST_F(LoadCustomizableTest,LoadTableFactoryTest)1465 TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
1466   std::shared_ptr<TableFactory> factory;
1467   ASSERT_NOK(TableFactory::CreateFromString(
1468       config_options_, mock::MockTableFactory::kClassName(), &factory));
1469   ASSERT_OK(TableFactory::CreateFromString(
1470       config_options_, TableFactory::kBlockBasedTableName(), &factory));
1471   ASSERT_NE(factory, nullptr);
1472   ASSERT_STREQ(factory->Name(), TableFactory::kBlockBasedTableName());
1473 #ifndef ROCKSDB_LITE
1474   std::string opts_str = "table_factory=";
1475   ASSERT_OK(GetColumnFamilyOptionsFromString(
1476       config_options_, cf_opts_,
1477       opts_str + TableFactory::kBlockBasedTableName(), &cf_opts_));
1478   ASSERT_NE(cf_opts_.table_factory.get(), nullptr);
1479   ASSERT_STREQ(cf_opts_.table_factory->Name(),
1480                TableFactory::kBlockBasedTableName());
1481 #endif  // ROCKSDB_LITE
1482   if (RegisterTests("Test")) {
1483     ASSERT_OK(TableFactory::CreateFromString(
1484         config_options_, mock::MockTableFactory::kClassName(), &factory));
1485     ASSERT_NE(factory, nullptr);
1486     ASSERT_STREQ(factory->Name(), mock::MockTableFactory::kClassName());
1487 #ifndef ROCKSDB_LITE
1488     ASSERT_OK(GetColumnFamilyOptionsFromString(
1489         config_options_, cf_opts_,
1490         opts_str + mock::MockTableFactory::kClassName(), &cf_opts_));
1491     ASSERT_NE(cf_opts_.table_factory.get(), nullptr);
1492     ASSERT_STREQ(cf_opts_.table_factory->Name(),
1493                  mock::MockTableFactory::kClassName());
1494 #endif  // ROCKSDB_LITE
1495   }
1496 }
1497 
TEST_F(LoadCustomizableTest,LoadSecondaryCacheTest)1498 TEST_F(LoadCustomizableTest, LoadSecondaryCacheTest) {
1499   std::shared_ptr<SecondaryCache> result;
1500   ASSERT_NOK(SecondaryCache::CreateFromString(
1501       config_options_, TestSecondaryCache::kClassName(), &result));
1502   if (RegisterTests("Test")) {
1503     ASSERT_OK(SecondaryCache::CreateFromString(
1504         config_options_, TestSecondaryCache::kClassName(), &result));
1505     ASSERT_NE(result, nullptr);
1506     ASSERT_STREQ(result->Name(), TestSecondaryCache::kClassName());
1507   }
1508 }
1509 
1510 #ifndef ROCKSDB_LITE
TEST_F(LoadCustomizableTest,LoadSstPartitionerFactoryTest)1511 TEST_F(LoadCustomizableTest, LoadSstPartitionerFactoryTest) {
1512   std::shared_ptr<SstPartitionerFactory> factory;
1513   ASSERT_NOK(SstPartitionerFactory::CreateFromString(config_options_, "Mock",
1514                                                      &factory));
1515   ASSERT_OK(SstPartitionerFactory::CreateFromString(
1516       config_options_, SstPartitionerFixedPrefixFactory::kClassName(),
1517       &factory));
1518   ASSERT_NE(factory, nullptr);
1519   ASSERT_STREQ(factory->Name(), SstPartitionerFixedPrefixFactory::kClassName());
1520 
1521   if (RegisterTests("Test")) {
1522     ASSERT_OK(SstPartitionerFactory::CreateFromString(config_options_, "Mock",
1523                                                       &factory));
1524     ASSERT_NE(factory, nullptr);
1525     ASSERT_STREQ(factory->Name(), "Mock");
1526   }
1527 }
1528 #endif  // ROCKSDB_LITE
1529 
TEST_F(LoadCustomizableTest,LoadChecksumGenFactoryTest)1530 TEST_F(LoadCustomizableTest, LoadChecksumGenFactoryTest) {
1531   std::shared_ptr<FileChecksumGenFactory> factory;
1532   ASSERT_NOK(FileChecksumGenFactory::CreateFromString(config_options_, "Mock",
1533                                                       &factory));
1534   ASSERT_OK(FileChecksumGenFactory::CreateFromString(
1535       config_options_, FileChecksumGenCrc32cFactory::kClassName(), &factory));
1536   ASSERT_NE(factory, nullptr);
1537   ASSERT_STREQ(factory->Name(), FileChecksumGenCrc32cFactory::kClassName());
1538 
1539   if (RegisterTests("Test")) {
1540     ASSERT_OK(FileChecksumGenFactory::CreateFromString(config_options_, "Mock",
1541                                                        &factory));
1542     ASSERT_NE(factory, nullptr);
1543     ASSERT_STREQ(factory->Name(), "Mock");
1544   }
1545 }
1546 
TEST_F(LoadCustomizableTest,LoadTablePropertiesCollectorFactoryTest)1547 TEST_F(LoadCustomizableTest, LoadTablePropertiesCollectorFactoryTest) {
1548   std::shared_ptr<TablePropertiesCollectorFactory> factory;
1549   ASSERT_NOK(TablePropertiesCollectorFactory::CreateFromString(
1550       config_options_, MockTablePropertiesCollectorFactory::kClassName(),
1551       &factory));
1552   if (RegisterTests("Test")) {
1553     ASSERT_OK(TablePropertiesCollectorFactory::CreateFromString(
1554         config_options_, MockTablePropertiesCollectorFactory::kClassName(),
1555         &factory));
1556     ASSERT_NE(factory, nullptr);
1557     ASSERT_STREQ(factory->Name(),
1558                  MockTablePropertiesCollectorFactory::kClassName());
1559   }
1560 }
1561 
TEST_F(LoadCustomizableTest,LoadComparatorTest)1562 TEST_F(LoadCustomizableTest, LoadComparatorTest) {
1563   const Comparator* bytewise = BytewiseComparator();
1564   const Comparator* reverse = ReverseBytewiseComparator();
1565 
1566   const Comparator* result = nullptr;
1567   ASSERT_NOK(Comparator::CreateFromString(
1568       config_options_, test::SimpleSuffixReverseComparator::kClassName(),
1569       &result));
1570   ASSERT_OK(
1571       Comparator::CreateFromString(config_options_, bytewise->Name(), &result));
1572   ASSERT_EQ(result, bytewise);
1573   ASSERT_OK(
1574       Comparator::CreateFromString(config_options_, reverse->Name(), &result));
1575   ASSERT_EQ(result, reverse);
1576 
1577   if (RegisterTests("Test")) {
1578     ASSERT_OK(Comparator::CreateFromString(
1579         config_options_, test::SimpleSuffixReverseComparator::kClassName(),
1580         &result));
1581     ASSERT_NE(result, nullptr);
1582     ASSERT_STREQ(result->Name(),
1583                  test::SimpleSuffixReverseComparator::kClassName());
1584   }
1585 }
1586 
TEST_F(LoadCustomizableTest,LoadSliceTransformFactoryTest)1587 TEST_F(LoadCustomizableTest, LoadSliceTransformFactoryTest) {
1588   std::shared_ptr<const SliceTransform> result;
1589   ASSERT_NOK(
1590       SliceTransform::CreateFromString(config_options_, "Mock", &result));
1591   ASSERT_OK(
1592       SliceTransform::CreateFromString(config_options_, "fixed:16", &result));
1593   ASSERT_NE(result.get(), nullptr);
1594   ASSERT_TRUE(result->IsInstanceOf("fixed"));
1595   ASSERT_OK(SliceTransform::CreateFromString(
1596       config_options_, "rocksdb.FixedPrefix.22", &result));
1597   ASSERT_NE(result.get(), nullptr);
1598   ASSERT_TRUE(result->IsInstanceOf("fixed"));
1599 
1600   ASSERT_OK(
1601       SliceTransform::CreateFromString(config_options_, "capped:16", &result));
1602   ASSERT_NE(result.get(), nullptr);
1603   ASSERT_TRUE(result->IsInstanceOf("capped"));
1604 
1605   ASSERT_OK(SliceTransform::CreateFromString(
1606       config_options_, "rocksdb.CappedPrefix.11", &result));
1607   ASSERT_NE(result.get(), nullptr);
1608   ASSERT_TRUE(result->IsInstanceOf("capped"));
1609 
1610   if (RegisterTests("Test")) {
1611     ASSERT_OK(
1612         SliceTransform::CreateFromString(config_options_, "Mock", &result));
1613     ASSERT_NE(result, nullptr);
1614     ASSERT_STREQ(result->Name(), "Mock");
1615   }
1616 }
1617 
TEST_F(LoadCustomizableTest,LoadStatisticsTest)1618 TEST_F(LoadCustomizableTest, LoadStatisticsTest) {
1619   std::shared_ptr<Statistics> stats;
1620   ASSERT_NOK(Statistics::CreateFromString(
1621       config_options_, TestStatistics::kClassName(), &stats));
1622   ASSERT_OK(
1623       Statistics::CreateFromString(config_options_, "BasicStatistics", &stats));
1624   ASSERT_NE(stats, nullptr);
1625   ASSERT_EQ(stats->Name(), std::string("BasicStatistics"));
1626 #ifndef ROCKSDB_LITE
1627   ASSERT_NOK(GetDBOptionsFromString(config_options_, db_opts_,
1628                                     "statistics=Test", &db_opts_));
1629   ASSERT_OK(GetDBOptionsFromString(config_options_, db_opts_,
1630                                    "statistics=BasicStatistics", &db_opts_));
1631   ASSERT_NE(db_opts_.statistics, nullptr);
1632   ASSERT_STREQ(db_opts_.statistics->Name(), "BasicStatistics");
1633 
1634   if (RegisterTests("test")) {
1635     ASSERT_OK(Statistics::CreateFromString(
1636         config_options_, TestStatistics::kClassName(), &stats));
1637     ASSERT_NE(stats, nullptr);
1638     ASSERT_STREQ(stats->Name(), TestStatistics::kClassName());
1639 
1640     ASSERT_OK(GetDBOptionsFromString(config_options_, db_opts_,
1641                                      "statistics=Test", &db_opts_));
1642     ASSERT_NE(db_opts_.statistics, nullptr);
1643     ASSERT_STREQ(db_opts_.statistics->Name(), TestStatistics::kClassName());
1644 
1645     ASSERT_OK(GetDBOptionsFromString(
1646         config_options_, db_opts_, "statistics={id=Test;inner=BasicStatistics}",
1647         &db_opts_));
1648     ASSERT_NE(db_opts_.statistics, nullptr);
1649     ASSERT_STREQ(db_opts_.statistics->Name(), TestStatistics::kClassName());
1650     auto* inner = db_opts_.statistics->GetOptions<std::shared_ptr<Statistics>>(
1651         "StatisticsOptions");
1652     ASSERT_NE(inner, nullptr);
1653     ASSERT_NE(inner->get(), nullptr);
1654     ASSERT_STREQ(inner->get()->Name(), "BasicStatistics");
1655 
1656     ASSERT_OK(Statistics::CreateFromString(
1657         config_options_, "id=BasicStatistics;inner=Test", &stats));
1658     ASSERT_NE(stats, nullptr);
1659     ASSERT_STREQ(stats->Name(), "BasicStatistics");
1660     inner = stats->GetOptions<std::shared_ptr<Statistics>>("StatisticsOptions");
1661     ASSERT_NE(inner, nullptr);
1662     ASSERT_NE(inner->get(), nullptr);
1663     ASSERT_STREQ(inner->get()->Name(), TestStatistics::kClassName());
1664   }
1665 #endif
1666 }
1667 
TEST_F(LoadCustomizableTest,LoadMemTableRepFactoryTest)1668 TEST_F(LoadCustomizableTest, LoadMemTableRepFactoryTest) {
1669   std::unique_ptr<MemTableRepFactory> result;
1670   ASSERT_NOK(MemTableRepFactory::CreateFromString(
1671       config_options_, "SpecialSkipListFactory", &result));
1672   ASSERT_OK(MemTableRepFactory::CreateFromString(
1673       config_options_, SkipListFactory::kClassName(), &result));
1674   ASSERT_NE(result.get(), nullptr);
1675   ASSERT_TRUE(result->IsInstanceOf(SkipListFactory::kClassName()));
1676 
1677   if (RegisterTests("Test")) {
1678     ASSERT_OK(MemTableRepFactory::CreateFromString(
1679         config_options_, "SpecialSkipListFactory", &result));
1680     ASSERT_NE(result, nullptr);
1681     ASSERT_STREQ(result->Name(), "SpecialSkipListFactory");
1682   }
1683 }
1684 
TEST_F(LoadCustomizableTest,LoadMergeOperatorTest)1685 TEST_F(LoadCustomizableTest, LoadMergeOperatorTest) {
1686   std::shared_ptr<MergeOperator> result;
1687 
1688   ASSERT_NOK(
1689       MergeOperator::CreateFromString(config_options_, "Changling", &result));
1690   ASSERT_OK(MergeOperator::CreateFromString(config_options_, "put", &result));
1691   ASSERT_NE(result, nullptr);
1692   ASSERT_STREQ(result->Name(), "PutOperator");
1693   if (RegisterTests("Test")) {
1694     ASSERT_OK(
1695         MergeOperator::CreateFromString(config_options_, "Changling", &result));
1696     ASSERT_NE(result, nullptr);
1697     ASSERT_STREQ(result->Name(), "ChanglingMergeOperator");
1698   }
1699 }
1700 
TEST_F(LoadCustomizableTest,LoadCompactionFilterFactoryTest)1701 TEST_F(LoadCustomizableTest, LoadCompactionFilterFactoryTest) {
1702   std::shared_ptr<CompactionFilterFactory> result;
1703 
1704   ASSERT_NOK(CompactionFilterFactory::CreateFromString(config_options_,
1705                                                        "Changling", &result));
1706   if (RegisterTests("Test")) {
1707     ASSERT_OK(CompactionFilterFactory::CreateFromString(config_options_,
1708                                                         "Changling", &result));
1709     ASSERT_NE(result, nullptr);
1710     ASSERT_STREQ(result->Name(), "ChanglingCompactionFilterFactory");
1711   }
1712 }
1713 
TEST_F(LoadCustomizableTest,LoadCompactionFilterTest)1714 TEST_F(LoadCustomizableTest, LoadCompactionFilterTest) {
1715   const CompactionFilter* result = nullptr;
1716 
1717   ASSERT_NOK(CompactionFilter::CreateFromString(config_options_, "Changling",
1718                                                 &result));
1719 #ifndef ROCKSDB_LITE
1720   ASSERT_OK(CompactionFilter::CreateFromString(
1721       config_options_, RemoveEmptyValueCompactionFilter::kClassName(),
1722       &result));
1723   ASSERT_NE(result, nullptr);
1724   ASSERT_STREQ(result->Name(), RemoveEmptyValueCompactionFilter::kClassName());
1725   delete result;
1726   result = nullptr;
1727   if (RegisterTests("Test")) {
1728     ASSERT_OK(CompactionFilter::CreateFromString(config_options_, "Changling",
1729                                                  &result));
1730     ASSERT_NE(result, nullptr);
1731     ASSERT_STREQ(result->Name(), "ChanglingCompactionFilter");
1732     delete result;
1733   }
1734 #endif  // ROCKSDB_LITE
1735 }
1736 
1737 #ifndef ROCKSDB_LITE
TEST_F(LoadCustomizableTest,LoadEventListenerTest)1738 TEST_F(LoadCustomizableTest, LoadEventListenerTest) {
1739   std::shared_ptr<EventListener> result;
1740 
1741   ASSERT_NOK(EventListener::CreateFromString(
1742       config_options_, OnFileDeletionListener::kClassName(), &result));
1743   ASSERT_NOK(EventListener::CreateFromString(
1744       config_options_, FlushCounterListener::kClassName(), &result));
1745   if (RegisterTests("Test")) {
1746     ASSERT_OK(EventListener::CreateFromString(
1747         config_options_, OnFileDeletionListener::kClassName(), &result));
1748     ASSERT_NE(result, nullptr);
1749     ASSERT_STREQ(result->Name(), OnFileDeletionListener::kClassName());
1750     ASSERT_OK(EventListener::CreateFromString(
1751         config_options_, FlushCounterListener::kClassName(), &result));
1752     ASSERT_NE(result, nullptr);
1753     ASSERT_STREQ(result->Name(), FlushCounterListener::kClassName());
1754   }
1755 }
1756 
TEST_F(LoadCustomizableTest,LoadEncryptionProviderTest)1757 TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) {
1758   std::shared_ptr<EncryptionProvider> result;
1759   ASSERT_NOK(
1760       EncryptionProvider::CreateFromString(config_options_, "Mock", &result));
1761   ASSERT_OK(
1762       EncryptionProvider::CreateFromString(config_options_, "CTR", &result));
1763   ASSERT_NE(result, nullptr);
1764   ASSERT_STREQ(result->Name(), "CTR");
1765   ASSERT_NOK(result->ValidateOptions(db_opts_, cf_opts_));
1766   ASSERT_OK(EncryptionProvider::CreateFromString(config_options_, "CTR://test",
1767                                                  &result));
1768   ASSERT_NE(result, nullptr);
1769   ASSERT_STREQ(result->Name(), "CTR");
1770   ASSERT_OK(result->ValidateOptions(db_opts_, cf_opts_));
1771 
1772   if (RegisterTests("Test")) {
1773     ASSERT_OK(
1774         EncryptionProvider::CreateFromString(config_options_, "Mock", &result));
1775     ASSERT_NE(result, nullptr);
1776     ASSERT_STREQ(result->Name(), "Mock");
1777     ASSERT_OK(EncryptionProvider::CreateFromString(config_options_,
1778                                                    "Mock://test", &result));
1779     ASSERT_NE(result, nullptr);
1780     ASSERT_STREQ(result->Name(), "Mock");
1781     ASSERT_OK(result->ValidateOptions(db_opts_, cf_opts_));
1782   }
1783 }
1784 
TEST_F(LoadCustomizableTest,LoadEncryptionCipherTest)1785 TEST_F(LoadCustomizableTest, LoadEncryptionCipherTest) {
1786   std::shared_ptr<BlockCipher> result;
1787   ASSERT_NOK(BlockCipher::CreateFromString(config_options_, "Mock", &result));
1788   ASSERT_OK(BlockCipher::CreateFromString(config_options_, "ROT13", &result));
1789   ASSERT_NE(result, nullptr);
1790   ASSERT_STREQ(result->Name(), "ROT13");
1791   if (RegisterTests("Test")) {
1792     ASSERT_OK(BlockCipher::CreateFromString(config_options_, "Mock", &result));
1793     ASSERT_NE(result, nullptr);
1794     ASSERT_STREQ(result->Name(), "Mock");
1795   }
1796 }
1797 #endif  // !ROCKSDB_LITE
1798 
TEST_F(LoadCustomizableTest,LoadSystemClockTest)1799 TEST_F(LoadCustomizableTest, LoadSystemClockTest) {
1800   std::shared_ptr<SystemClock> result;
1801   ASSERT_NOK(SystemClock::CreateFromString(
1802       config_options_, MockSystemClock::kClassName(), &result));
1803   ASSERT_OK(SystemClock::CreateFromString(
1804       config_options_, SystemClock::kDefaultName(), &result));
1805   ASSERT_NE(result, nullptr);
1806   ASSERT_TRUE(result->IsInstanceOf(SystemClock::kDefaultName()));
1807   if (RegisterTests("Test")) {
1808     ASSERT_OK(SystemClock::CreateFromString(
1809         config_options_, MockSystemClock::kClassName(), &result));
1810     ASSERT_NE(result, nullptr);
1811     ASSERT_STREQ(result->Name(), MockSystemClock::kClassName());
1812   }
1813 }
1814 
TEST_F(LoadCustomizableTest,LoadFlushBlockPolicyFactoryTest)1815 TEST_F(LoadCustomizableTest, LoadFlushBlockPolicyFactoryTest) {
1816   std::shared_ptr<TableFactory> table;
1817   std::shared_ptr<FlushBlockPolicyFactory> result;
1818   ASSERT_NOK(FlushBlockPolicyFactory::CreateFromString(
1819       config_options_, TestFlushBlockPolicyFactory::kClassName(), &result));
1820 
1821   ASSERT_OK(
1822       FlushBlockPolicyFactory::CreateFromString(config_options_, "", &result));
1823   ASSERT_NE(result, nullptr);
1824   ASSERT_STREQ(result->Name(), FlushBlockBySizePolicyFactory::kClassName());
1825 
1826   ASSERT_OK(FlushBlockPolicyFactory::CreateFromString(
1827       config_options_, FlushBlockEveryKeyPolicyFactory::kClassName(), &result));
1828   ASSERT_NE(result, nullptr);
1829   ASSERT_STREQ(result->Name(), FlushBlockEveryKeyPolicyFactory::kClassName());
1830 
1831   ASSERT_OK(FlushBlockPolicyFactory::CreateFromString(
1832       config_options_, FlushBlockBySizePolicyFactory::kClassName(), &result));
1833   ASSERT_NE(result, nullptr);
1834   ASSERT_STREQ(result->Name(), FlushBlockBySizePolicyFactory::kClassName());
1835 #ifndef ROCKSDB_LITE
1836   std::string table_opts = "id=BlockBasedTable; flush_block_policy_factory=";
1837   ASSERT_OK(TableFactory::CreateFromString(
1838       config_options_,
1839       table_opts + FlushBlockEveryKeyPolicyFactory::kClassName(), &table));
1840   auto bbto = table->GetOptions<BlockBasedTableOptions>();
1841   ASSERT_NE(bbto, nullptr);
1842   ASSERT_NE(bbto->flush_block_policy_factory.get(), nullptr);
1843   ASSERT_STREQ(bbto->flush_block_policy_factory->Name(),
1844                FlushBlockEveryKeyPolicyFactory::kClassName());
1845   if (RegisterTests("Test")) {
1846     ASSERT_OK(FlushBlockPolicyFactory::CreateFromString(
1847         config_options_, TestFlushBlockPolicyFactory::kClassName(), &result));
1848     ASSERT_NE(result, nullptr);
1849     ASSERT_STREQ(result->Name(), TestFlushBlockPolicyFactory::kClassName());
1850     ASSERT_OK(TableFactory::CreateFromString(
1851         config_options_, table_opts + TestFlushBlockPolicyFactory::kClassName(),
1852         &table));
1853     bbto = table->GetOptions<BlockBasedTableOptions>();
1854     ASSERT_NE(bbto, nullptr);
1855     ASSERT_NE(bbto->flush_block_policy_factory.get(), nullptr);
1856     ASSERT_STREQ(bbto->flush_block_policy_factory->Name(),
1857                  TestFlushBlockPolicyFactory::kClassName());
1858   }
1859 #endif  // ROCKSDB_LITE
1860 }
1861 
1862 }  // namespace ROCKSDB_NAMESPACE
main(int argc,char ** argv)1863 int main(int argc, char** argv) {
1864   ::testing::InitGoogleTest(&argc, argv);
1865   ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
1866 #ifdef GFLAGS
1867   ParseCommandLineFlags(&argc, &argv, true);
1868 #endif  // GFLAGS
1869   return RUN_ALL_TESTS();
1870 }
1871