d_cfg_mgr_unittests.cc 16 KB

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