d_cfg_mgr_unittests.cc 18 KB

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