d_cfg_mgr_unittests.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <cc/command_interpreter.h>
  8. #include <config/module_spec.h>
  9. #include <dhcpsrv/parsers/dhcp_parsers.h>
  10. #include <process/testutils/d_test_stubs.h>
  11. #include <process/d_cfg_mgr.h>
  12. #include <boost/foreach.hpp>
  13. #include <boost/date_time/posix_time/posix_time.hpp>
  14. #include <gtest/gtest.h>
  15. #include <sstream>
  16. using namespace std;
  17. using namespace isc;
  18. using namespace isc::config;
  19. using namespace isc::process;
  20. using namespace isc::data;
  21. using namespace boost::posix_time;
  22. namespace {
  23. /// @brief Test Class for verifying that configuration context cannot be null
  24. /// during construction.
  25. class DCtorTestCfgMgr : public DCfgMgrBase {
  26. public:
  27. /// @brief Constructor - Note that is passes in an empty configuration
  28. /// pointer to the base class constructor.
  29. DCtorTestCfgMgr() : DCfgMgrBase(DCfgContextBasePtr()) {
  30. }
  31. /// @brief Destructor
  32. virtual ~DCtorTestCfgMgr() {
  33. }
  34. /// @brief Dummy implementation as this method is abstract.
  35. virtual DCfgContextBasePtr createNewContext() {
  36. return (DCfgContextBasePtr());
  37. }
  38. /// @brief Returns summary of configuration in the textual format.
  39. virtual std::string getConfigSummary(const uint32_t) {
  40. return ("");
  41. }
  42. };
  43. /// @brief Test fixture class for testing DCfgMgrBase class.
  44. /// It maintains an member instance of DStubCfgMgr and derives from
  45. /// ConfigParseTest fixture, thus providing methods for converting JSON
  46. /// strings to configuration element sets, checking parse results, and
  47. /// accessing the configuration context.
  48. class DStubCfgMgrTest : public ConfigParseTest {
  49. public:
  50. /// @brief Constructor
  51. DStubCfgMgrTest():cfg_mgr_(new DStubCfgMgr) {
  52. }
  53. /// @brief Destructor
  54. ~DStubCfgMgrTest() {
  55. }
  56. /// @brief Convenience method which returns a DStubContextPtr to the
  57. /// configuration context.
  58. ///
  59. /// @return returns a DStubContextPtr.
  60. DStubContextPtr getStubContext() {
  61. return (boost::dynamic_pointer_cast<DStubContext>
  62. (cfg_mgr_->getContext()));
  63. }
  64. /// @brief Configuration manager instance.
  65. DStubCfgMgrPtr cfg_mgr_;
  66. };
  67. ///@brief Tests basic construction/destruction of configuration manager.
  68. /// Verifies that:
  69. /// 1. Proper construction succeeds.
  70. /// 2. Configuration context is initialized by construction.
  71. /// 3. Destruction works properly.
  72. /// 4. Construction with a null context is not allowed.
  73. TEST(DCfgMgrBase, construction) {
  74. DCfgMgrBasePtr cfg_mgr;
  75. // Verify that configuration manager constructions without error.
  76. ASSERT_NO_THROW(cfg_mgr.reset(new DStubCfgMgr()));
  77. // Verify that the context can be retrieved and is not null.
  78. DCfgContextBasePtr context = cfg_mgr->getContext();
  79. EXPECT_TRUE(context);
  80. // Verify that the manager can be destructed without error.
  81. EXPECT_NO_THROW(cfg_mgr.reset());
  82. // Verify that an attempt to construct a manger with a null context fails.
  83. ASSERT_THROW(DCtorTestCfgMgr(), DCfgMgrBaseError);
  84. }
  85. ///@brief Tests fundamental aspects of configuration parsing.
  86. /// Verifies that:
  87. /// 1. A correctly formed simple configuration parses without error.
  88. /// 2. An error building the element is handled.
  89. /// 3. An error committing the element is handled.
  90. /// 4. An unknown element error is handled.
  91. TEST_F(DStubCfgMgrTest, basicParseTest) {
  92. // Create a simple configuration.
  93. string config = "{ \"test-value\": [] } ";
  94. ASSERT_TRUE(fromJSON(config));
  95. // Verify that we can parse a simple configuration.
  96. answer_ = cfg_mgr_->parseConfig(config_set_);
  97. EXPECT_TRUE(checkAnswer(0));
  98. // Verify that an unknown element error is caught and returns a failed
  99. // parse result.
  100. SimFailure::set(SimFailure::ftElementUnknown);
  101. answer_ = cfg_mgr_->parseConfig(config_set_);
  102. EXPECT_TRUE(checkAnswer(1));
  103. }
  104. ///@brief Tests ordered and non-ordered element parsing
  105. /// This test verifies that:
  106. /// 1. Non-ordered parsing parses elements in the order they are presented
  107. /// by the configuration set (as-they-come).
  108. /// 2. A parse order list with too few elements is detected.
  109. /// 3. Ordered parsing parses the elements in the order specified by the
  110. /// configuration manager's parse order list.
  111. /// 4. A parse order list with too many elements is detected.
  112. TEST_F(DStubCfgMgrTest, parseOrderTest) {
  113. // Element ids used for test.
  114. std::string charlie("charlie");
  115. std::string bravo("bravo");
  116. std::string alpha("alpha");
  117. std::string string_test("string_test");
  118. std::string uint32_test("uint32_test");
  119. std::string bool_test("bool_test");
  120. // Create the test configuration with the elements in "random" order.
  121. // NOTE that element sets produced by isc::data::Element::fromJSON(),
  122. // are in lexical order by element_id. This means that iterating over
  123. // such an element set, will present the elements in lexical order. Should
  124. // this change, this test will need to be modified accordingly.
  125. string config = "{"
  126. " \"string_test\": \"hoopla\", "
  127. " \"bravo\": [], "
  128. " \"uint32_test\": 55, "
  129. " \"alpha\": {}, "
  130. " \"charlie\": [], "
  131. " \"bool_test\": true "
  132. "} ";
  133. ASSERT_TRUE(fromJSON(config));
  134. // Verify that non-ordered parsing, results in an as-they-come parse order.
  135. // Create an expected parse order.
  136. // (NOTE that iterating over Element sets produced by fromJSON() will
  137. // present the elements in lexical order. Should this change, the expected
  138. // order list below would need to be changed accordingly).
  139. ElementIdList order_expected;
  140. // scalar params should be first and lexically
  141. order_expected.push_back(bool_test);
  142. order_expected.push_back(string_test);
  143. order_expected.push_back(uint32_test);
  144. // objects second and lexically
  145. order_expected.push_back(alpha);
  146. order_expected.push_back(bravo);
  147. order_expected.push_back(charlie);
  148. // Verify that the manager has an EMPTY parse order list. (Empty list
  149. // instructs the manager to parse them as-they-come.)
  150. EXPECT_EQ(0, cfg_mgr_->getParseOrder().size());
  151. // Parse the configuration, verify it parses without error.
  152. answer_ = cfg_mgr_->parseConfig(config_set_);
  153. EXPECT_TRUE(checkAnswer(0));
  154. // Verify that the parsed order matches what we expected.
  155. EXPECT_TRUE(cfg_mgr_->parsed_order_ == order_expected);
  156. // Clear the manager's parse order "memory".
  157. cfg_mgr_->parsed_order_.clear();
  158. // Create a parse order list that has too few entries. Verify that
  159. // when parsing the test config, it fails.
  160. cfg_mgr_->addToParseOrder(charlie);
  161. // Verify the parse order list is the size we expect.
  162. EXPECT_EQ(1, cfg_mgr_->getParseOrder().size());
  163. // Verify the configuration fails.
  164. answer_ = cfg_mgr_->parseConfig(config_set_);
  165. EXPECT_TRUE(checkAnswer(1));
  166. // Verify that the configuration parses correctly, when the parse order
  167. // is correct. Add the needed entries to the parse order
  168. cfg_mgr_->addToParseOrder(bravo);
  169. cfg_mgr_->addToParseOrder(alpha);
  170. // Verify the parse order list is the size we expect.
  171. EXPECT_EQ(3, cfg_mgr_->getParseOrder().size());
  172. // Clear the manager's parse order "memory".
  173. cfg_mgr_->parsed_order_.clear();
  174. // Verify the configuration parses without error.
  175. answer_ = cfg_mgr_->parseConfig(config_set_);
  176. EXPECT_TRUE(checkAnswer(0));
  177. // Build expected order
  178. // primitives should be first and lexically
  179. order_expected.clear();
  180. order_expected.push_back(bool_test);
  181. order_expected.push_back(string_test);
  182. order_expected.push_back(uint32_test);
  183. // objects second and by the parse order
  184. order_expected.push_back(charlie);
  185. order_expected.push_back(bravo);
  186. order_expected.push_back(alpha);
  187. // Verify that the parsed order is the order we configured.
  188. EXPECT_TRUE(cfg_mgr_->parsed_order_ == order_expected);
  189. // Create a parse order list that has too many entries. Verify that
  190. // when parsing the test config, it fails.
  191. cfg_mgr_->addToParseOrder("delta");
  192. // Verify the parse order list is the size we expect.
  193. EXPECT_EQ(4, cfg_mgr_->getParseOrder().size());
  194. // Verify the configuration fails.
  195. answer_ = cfg_mgr_->parseConfig(config_set_);
  196. EXPECT_TRUE(checkAnswer(1));
  197. }
  198. /// @brief Tests that element ids supported by the base class as well as those
  199. /// added by the derived class function properly.
  200. /// This test verifies that:
  201. /// 1. Boolean parameters can be parsed and retrieved.
  202. /// 2. Uint32 parameters can be parsed and retrieved.
  203. /// 3. String parameters can be parsed and retrieved.
  204. /// 4. Map elements can be parsed and retrieved.
  205. /// 5. List elements can be parsed and retrieved.
  206. /// 6. Parsing a second configuration, updates the existing context values
  207. /// correctly.
  208. TEST_F(DStubCfgMgrTest, simpleTypesTest) {
  209. // Create a configuration with all of the parameters.
  210. string config = "{ \"bool_test\": true , "
  211. " \"uint32_test\": 77 , "
  212. " \"string_test\": \"hmmm chewy\" , "
  213. " \"map_test\" : {} , "
  214. " \"list_test\": [] }";
  215. ASSERT_TRUE(fromJSON(config));
  216. // Verify that the configuration parses without error.
  217. answer_ = cfg_mgr_->parseConfig(config_set_);
  218. ASSERT_TRUE(checkAnswer(0));
  219. DStubContextPtr context = getStubContext();
  220. ASSERT_TRUE(context);
  221. // Verify that the boolean parameter was parsed correctly by retrieving
  222. // its value from the context.
  223. bool actual_bool = false;
  224. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  225. EXPECT_EQ(true, actual_bool);
  226. // Verify that the uint32 parameter was parsed correctly by retrieving
  227. // its value from the context.
  228. uint32_t actual_uint32 = 0;
  229. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  230. EXPECT_EQ(77, actual_uint32);
  231. // Verify that the string parameter was parsed correctly by retrieving
  232. // its value from the context.
  233. std::string actual_string = "";
  234. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  235. EXPECT_EQ("hmmm chewy", actual_string);
  236. isc::data::ConstElementPtr object;
  237. EXPECT_NO_THROW(context->getObjectParam("map_test", object));
  238. EXPECT_TRUE(object);
  239. EXPECT_NO_THROW(context->getObjectParam("list_test", object));
  240. EXPECT_TRUE(object);
  241. // Create a configuration which "updates" all of the parameter values.
  242. string config2 = "{ \"bool_test\": false , "
  243. " \"uint32_test\": 88 , "
  244. " \"string_test\": \"ewww yuk!\" , "
  245. " \"map_test2\" : {} , "
  246. " \"list_test2\": [] }";
  247. ASSERT_TRUE(fromJSON(config2));
  248. // Verify that the configuration parses without error.
  249. answer_ = cfg_mgr_->parseConfig(config_set_);
  250. EXPECT_TRUE(checkAnswer(0));
  251. context = getStubContext();
  252. ASSERT_TRUE(context);
  253. // Verify that the boolean parameter was updated correctly by retrieving
  254. // its value from the context.
  255. actual_bool = true;
  256. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  257. EXPECT_FALSE(actual_bool);
  258. // Verify that the uint32 parameter was updated correctly by retrieving
  259. // its value from the context.
  260. actual_uint32 = 0;
  261. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  262. EXPECT_EQ(88, actual_uint32);
  263. // Verify that the string parameter was updated correctly by retrieving
  264. // its value from the context.
  265. actual_string = "";
  266. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  267. EXPECT_EQ("ewww yuk!", actual_string);
  268. // Verify previous objects are not there.
  269. EXPECT_THROW(context->getObjectParam("map_test", object),
  270. isc::dhcp::DhcpConfigError);
  271. EXPECT_THROW(context->getObjectParam("list_test", object),
  272. isc::dhcp::DhcpConfigError);
  273. // Verify new map object is there.
  274. EXPECT_NO_THROW(context->getObjectParam("map_test2", object));
  275. EXPECT_TRUE(object);
  276. // Verify new list object is there.
  277. EXPECT_NO_THROW(context->getObjectParam("list_test2", object));
  278. EXPECT_TRUE(object);
  279. }
  280. /// @brief Tests that the configuration context is preserved after failure
  281. /// during parsing causes a rollback.
  282. /// 1. Verifies configuration context rollback.
  283. TEST_F(DStubCfgMgrTest, rollBackTest) {
  284. // Create a configuration with all of the parameters.
  285. string config = "{ \"bool_test\": true , "
  286. " \"uint32_test\": 77 , "
  287. " \"string_test\": \"hmmm chewy\" , "
  288. " \"map_test\" : {} , "
  289. " \"list_test\": [] }";
  290. ASSERT_TRUE(fromJSON(config));
  291. // Verify that the configuration parses without error.
  292. answer_ = cfg_mgr_->parseConfig(config_set_);
  293. EXPECT_TRUE(checkAnswer(0));
  294. DStubContextPtr context = getStubContext();
  295. ASSERT_TRUE(context);
  296. // Verify that all of parameters have the expected values.
  297. bool actual_bool = false;
  298. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  299. EXPECT_EQ(true, actual_bool);
  300. uint32_t actual_uint32 = 0;
  301. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  302. EXPECT_EQ(77, actual_uint32);
  303. std::string actual_string = "";
  304. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  305. EXPECT_EQ("hmmm chewy", actual_string);
  306. isc::data::ConstElementPtr object;
  307. EXPECT_NO_THROW(context->getObjectParam("map_test", object));
  308. EXPECT_TRUE(object);
  309. EXPECT_NO_THROW(context->getObjectParam("list_test", object));
  310. EXPECT_TRUE(object);
  311. // Create a configuration which "updates" all of the parameter values
  312. // plus one unknown at the end.
  313. string config2 = "{ \"bool_test\": false , "
  314. " \"uint32_test\": 88 , "
  315. " \"string_test\": \"ewww yuk!\" , "
  316. " \"map_test2\" : {} , "
  317. " \"list_test2\": [] , "
  318. " \"zeta_unknown\": 33 } ";
  319. ASSERT_TRUE(fromJSON(config2));
  320. // Force a failure on the last element
  321. SimFailure::set(SimFailure::ftElementUnknown);
  322. answer_ = cfg_mgr_->parseConfig(config_set_);
  323. EXPECT_TRUE(checkAnswer(1));
  324. context = getStubContext();
  325. ASSERT_TRUE(context);
  326. // Verify that all of parameters have the original values.
  327. actual_bool = false;
  328. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  329. EXPECT_EQ(true, actual_bool);
  330. actual_uint32 = 0;
  331. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  332. EXPECT_EQ(77, actual_uint32);
  333. actual_string = "";
  334. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  335. EXPECT_EQ("hmmm chewy", actual_string);
  336. EXPECT_NO_THROW(context->getObjectParam("map_test", object));
  337. EXPECT_TRUE(object);
  338. EXPECT_NO_THROW(context->getObjectParam("list_test", object));
  339. EXPECT_TRUE(object);
  340. }
  341. // Tests that configuration element position is returned by getParam variants.
  342. TEST_F(DStubCfgMgrTest, paramPosition) {
  343. // Create a configuration with one of each scalar types. We end them
  344. // with line feeds so we can test position value.
  345. string config = "{ \"bool_test\": true , \n"
  346. " \"uint32_test\": 77 , \n"
  347. " \"string_test\": \"hmmm chewy\" }";
  348. ASSERT_TRUE(fromJSON(config));
  349. // Verify that the configuration parses without error.
  350. answer_ = cfg_mgr_->parseConfig(config_set_);
  351. ASSERT_TRUE(checkAnswer(0));
  352. DStubContextPtr context = getStubContext();
  353. ASSERT_TRUE(context);
  354. // Verify that the boolean parameter was parsed correctly by retrieving
  355. // its value from the context.
  356. bool actual_bool = false;
  357. isc::data::Element::Position pos;
  358. EXPECT_NO_THROW(pos = context->getParam("bool_test", actual_bool));
  359. EXPECT_EQ(true, actual_bool);
  360. EXPECT_EQ(1, pos.line_);
  361. // Verify that the uint32 parameter was parsed correctly by retrieving
  362. // its value from the context.
  363. uint32_t actual_uint32 = 0;
  364. EXPECT_NO_THROW(pos = context->getParam("uint32_test", actual_uint32));
  365. EXPECT_EQ(77, actual_uint32);
  366. EXPECT_EQ(2, pos.line_);
  367. // Verify that the string parameter was parsed correctly by retrieving
  368. // its value from the context.
  369. std::string actual_string = "";
  370. EXPECT_NO_THROW(pos = context->getParam("string_test", actual_string));
  371. EXPECT_EQ("hmmm chewy", actual_string);
  372. EXPECT_EQ(3, pos.line_);
  373. // Verify that an optional parameter that is not defined, returns the
  374. // zero position.
  375. pos = isc::data::Element::ZERO_POSITION();
  376. EXPECT_NO_THROW(pos = context->getParam("bogus_value",
  377. actual_string, true));
  378. EXPECT_EQ(pos.file_, isc::data::Element::ZERO_POSITION().file_);
  379. }
  380. } // end of anonymous namespace