d_cfg_mgr_unittests.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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/date_time/posix_time/posix_time.hpp>
  20. #include <gtest/gtest.h>
  21. #include <config.h>
  22. #include <sstream>
  23. using namespace std;
  24. using namespace isc;
  25. using namespace isc::config;
  26. using namespace isc::d2;
  27. using namespace boost::posix_time;
  28. namespace {
  29. /// @brief Test Class for verifying that configuration context cannot be null
  30. /// during construction.
  31. class DCtorTestCfgMgr : public DCfgMgrBase {
  32. public:
  33. /// @brief Constructor - Note that is passes in an empty configuration
  34. /// pointer to the base class constructor.
  35. DCtorTestCfgMgr() : DCfgMgrBase(DCfgContextBasePtr()) {
  36. }
  37. /// @brief Destructor
  38. virtual ~DCtorTestCfgMgr() {
  39. }
  40. /// @brief Dummy implementation as this method is abstract.
  41. virtual isc::dhcp::ParserPtr
  42. createConfigParser(const std::string& /* element_id */) {
  43. return (isc::dhcp::ParserPtr());
  44. }
  45. };
  46. /// @brief Test fixture class for testing DCfgMgrBase class.
  47. /// It maintains an member instance of DStubCfgMgr and derives from
  48. /// ConfigParseTest fixture, thus providing methods for converting JSON
  49. /// strings to configuration element sets, checking parse results, and
  50. /// accessing the configuration context.
  51. class DStubCfgMgrTest : public ConfigParseTest {
  52. public:
  53. /// @brief Constructor
  54. DStubCfgMgrTest():cfg_mgr_(new DStubCfgMgr) {
  55. }
  56. /// @brief Destructor
  57. ~DStubCfgMgrTest() {
  58. }
  59. /// @brief Convenience method which returns a DStubContextPtr to the
  60. /// configuration context.
  61. ///
  62. /// @return returns a DStubContextPtr.
  63. DStubContextPtr getStubContext() {
  64. return (boost::dynamic_pointer_cast<DStubContext>
  65. (cfg_mgr_->getContext()));
  66. }
  67. /// @brief Configuration manager instance.
  68. DStubCfgMgrPtr cfg_mgr_;
  69. };
  70. ///@brief Tests basic construction/destruction of configuration manager.
  71. /// Verifies that:
  72. /// 1. Proper construction succeeds.
  73. /// 2. Configuration context is initialized by construction.
  74. /// 3. Destruction works properly.
  75. /// 4. Construction with a null context is not allowed.
  76. TEST(DCfgMgrBase, construction) {
  77. DCfgMgrBasePtr cfg_mgr;
  78. // Verify that configuration manager constructions without error.
  79. ASSERT_NO_THROW(cfg_mgr.reset(new DStubCfgMgr()));
  80. // Verify that the context can be retrieved and is not null.
  81. DCfgContextBasePtr context = cfg_mgr->getContext();
  82. EXPECT_TRUE(context);
  83. // Verify that the manager can be destructed without error.
  84. EXPECT_NO_THROW(cfg_mgr.reset());
  85. // Verify that an attempt to construct a manger with a null context fails.
  86. ASSERT_THROW(DCtorTestCfgMgr(), DCfgMgrBaseError);
  87. }
  88. ///@brief Tests fundamental aspects of configuration parsing.
  89. /// Verifies that:
  90. /// 1. A correctly formed simple configuration parses without error.
  91. /// 2. An error building the element is handled.
  92. /// 3. An error committing the element is handled.
  93. /// 4. An unknown element error is handled.
  94. TEST_F(DStubCfgMgrTest, basicParseTest) {
  95. // Create a simple configuration.
  96. string config = "{ \"test-value\": 1000 } ";
  97. ASSERT_TRUE(fromJSON(config));
  98. // Verify that we can parse a simple configuration.
  99. answer_ = cfg_mgr_->parseConfig(config_set_);
  100. EXPECT_TRUE(checkAnswer(0));
  101. // Verify that an error building the element is caught and returns a
  102. // failed parse result.
  103. SimFailure::set(SimFailure::ftElementBuild);
  104. answer_ = cfg_mgr_->parseConfig(config_set_);
  105. EXPECT_TRUE(checkAnswer(1));
  106. // Verify that an error committing the element is caught and returns a
  107. // failed parse result.
  108. SimFailure::set(SimFailure::ftElementCommit);
  109. answer_ = cfg_mgr_->parseConfig(config_set_);
  110. EXPECT_TRUE(checkAnswer(1));
  111. // Verify that an unknown element error is caught and returns a failed
  112. // parse result.
  113. SimFailure::set(SimFailure::ftElementUnknown);
  114. answer_ = cfg_mgr_->parseConfig(config_set_);
  115. EXPECT_TRUE(checkAnswer(1));
  116. }
  117. ///@brief Tests ordered and non-ordered element parsing
  118. /// This test verifies that:
  119. /// 1. Non-ordered parsing parses elements in the order they are presented
  120. /// by the configuration set (as-they-come).
  121. /// 2. A parse order list with too few elements is detected.
  122. /// 3. Ordered parsing parses the elements in the order specified by the
  123. /// configuration manager's parse order list.
  124. /// 4. A parse order list with too many elements is detected.
  125. TEST_F(DStubCfgMgrTest, parseOrderTest) {
  126. // Element ids used for test.
  127. std::string charlie("charlie");
  128. std::string bravo("bravo");
  129. std::string alpha("alpha");
  130. // Create the test configuration with the elements in "random" order.
  131. // NOTE that element sets produced by isc::data::Element::fromJSON(),
  132. // are in lexical order by element_id. This means that iterating over
  133. // such an element set, will present the elements in lexical order. Should
  134. // this change, this test will need to be modified accordingly.
  135. string config = "{ \"bravo\": 2, "
  136. " \"alpha\": 1, "
  137. " \"charlie\": 3 } ";
  138. ASSERT_TRUE(fromJSON(config));
  139. // Verify that non-ordered parsing, results in an as-they-come parse order.
  140. // Create an expected parse order.
  141. // (NOTE that iterating over Element sets produced by fromJSON() will
  142. // present the elements in lexical order. Should this change, the expected
  143. // order list below would need to be changed accordingly).
  144. ElementIdList order_expected;
  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. // Verify that the parsed order is the order we configured.
  178. EXPECT_TRUE(cfg_mgr_->getParseOrder() == cfg_mgr_->parsed_order_);
  179. // Create a parse order list that has too many entries. Verify that
  180. // when parsing the test config, it fails.
  181. cfg_mgr_->addToParseOrder("delta");
  182. // Verify the parse order list is the size we expect.
  183. EXPECT_EQ(4, cfg_mgr_->getParseOrder().size());
  184. // Verify the configuration fails.
  185. answer_ = cfg_mgr_->parseConfig(config_set_);
  186. EXPECT_TRUE(checkAnswer(1));
  187. }
  188. /// @brief Tests that element ids supported by the base class as well as those
  189. /// added by the derived class function properly.
  190. /// This test verifies that:
  191. /// 1. Boolean parameters can be parsed and retrieved.
  192. /// 2. Uint32 parameters can be parsed and retrieved.
  193. /// 3. String parameters can be parsed and retrieved.
  194. /// 4. Derivation-specific parameters can be parsed and retrieved.
  195. /// 5. Parsing a second configuration, updates the existing context values
  196. /// correctly.
  197. TEST_F(DStubCfgMgrTest, simpleTypesTest) {
  198. // Fetch a derivation specific pointer to the context.
  199. DStubContextPtr context = getStubContext();
  200. ASSERT_TRUE(context);
  201. // Create a configuration with all of the parameters.
  202. string config = "{ \"bool_test\": true , "
  203. " \"uint32_test\": 77 , "
  204. " \"string_test\": \"hmmm chewy\" , "
  205. " \"extra_test\": 430 } ";
  206. ASSERT_TRUE(fromJSON(config));
  207. // Verify that the configuration parses without error.
  208. answer_ = cfg_mgr_->parseConfig(config_set_);
  209. ASSERT_TRUE(checkAnswer(0));
  210. // Verify that the boolean parameter was parsed correctly by retrieving
  211. // its value from the context.
  212. bool actual_bool = false;
  213. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  214. EXPECT_EQ(true, actual_bool);
  215. // Verify that the uint32 parameter was parsed correctly by retrieving
  216. // its value from the context.
  217. uint32_t actual_uint32 = 0;
  218. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  219. EXPECT_EQ(77, actual_uint32);
  220. // Verify that the string parameter was parsed correctly by retrieving
  221. // its value from the context.
  222. std::string actual_string = "";
  223. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  224. EXPECT_EQ("hmmm chewy", actual_string);
  225. // Verify that the "extra" parameter was parsed correctly by retrieving
  226. // its value from the context.
  227. uint32_t actual_extra = 0;
  228. EXPECT_NO_THROW(context->getExtraParam("extra_test", actual_extra));
  229. EXPECT_EQ(430, actual_extra);
  230. // Create a configuration which "updates" all of the parameter values.
  231. string config2 = "{ \"bool_test\": false , "
  232. " \"uint32_test\": 88 , "
  233. " \"string_test\": \"ewww yuk!\" , "
  234. " \"extra_test\": 11 } ";
  235. ASSERT_TRUE(fromJSON(config2));
  236. // Verify that the configuration parses without error.
  237. answer_ = cfg_mgr_->parseConfig(config_set_);
  238. EXPECT_TRUE(checkAnswer(0));
  239. // Verify that the boolean parameter was updated correctly by retrieving
  240. // its value from the context.
  241. actual_bool = true;
  242. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  243. EXPECT_FALSE(actual_bool);
  244. // Verify that the uint32 parameter was updated correctly by retrieving
  245. // its value from the context.
  246. actual_uint32 = 0;
  247. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  248. EXPECT_EQ(88, actual_uint32);
  249. // Verify that the string parameter was updated correctly by retrieving
  250. // its value from the context.
  251. actual_string = "";
  252. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  253. EXPECT_EQ("ewww yuk!", actual_string);
  254. // Verify that the "extra" parameter was updated correctly by retrieving
  255. // its value from the context.
  256. actual_extra = 0;
  257. EXPECT_NO_THROW(context->getExtraParam("extra_test", actual_extra));
  258. EXPECT_EQ(11, actual_extra);
  259. }
  260. /// @brief Tests that the configuration context is preserved after failure
  261. /// during parsing causes a rollback.
  262. /// 1. Verifies configuration context rollback.
  263. TEST_F(DStubCfgMgrTest, rollBackTest) {
  264. // Fetch a derivation specific pointer to the context.
  265. DStubContextPtr context = getStubContext();
  266. ASSERT_TRUE(context);
  267. // Create a configuration with all of the parameters.
  268. string config = "{ \"bool_test\": true , "
  269. " \"uint32_test\": 77 , "
  270. " \"string_test\": \"hmmm chewy\" , "
  271. " \"extra_test\": 430 } ";
  272. ASSERT_TRUE(fromJSON(config));
  273. // Verify that the configuration parses without error.
  274. answer_ = cfg_mgr_->parseConfig(config_set_);
  275. EXPECT_TRUE(checkAnswer(0));
  276. // Verify that all of parameters have the expected values.
  277. bool actual_bool = false;
  278. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  279. EXPECT_EQ(true, actual_bool);
  280. uint32_t actual_uint32 = 0;
  281. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  282. EXPECT_EQ(77, actual_uint32);
  283. std::string actual_string = "";
  284. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  285. EXPECT_EQ("hmmm chewy", actual_string);
  286. uint32_t actual_extra = 0;
  287. EXPECT_NO_THROW(context->getExtraParam("extra_test", actual_extra));
  288. EXPECT_EQ(430, actual_extra);
  289. // Create a configuration which "updates" all of the parameter values
  290. // plus one unknown at the end.
  291. string config2 = "{ \"bool_test\": false , "
  292. " \"uint32_test\": 88 , "
  293. " \"string_test\": \"ewww yuk!\" , "
  294. " \"extra_test\": 11 , "
  295. " \"zeta_unknown\": 33 } ";
  296. ASSERT_TRUE(fromJSON(config2));
  297. // Force a failure on the last element
  298. SimFailure::set(SimFailure::ftElementUnknown);
  299. answer_ = cfg_mgr_->parseConfig(config_set_);
  300. EXPECT_TRUE(checkAnswer(1));
  301. // Refresh our local pointer.
  302. context = getStubContext();
  303. // Verify that all of parameters have the original values.
  304. actual_bool = false;
  305. EXPECT_NO_THROW(context->getParam("bool_test", actual_bool));
  306. EXPECT_EQ(true, actual_bool);
  307. actual_uint32 = 0;
  308. EXPECT_NO_THROW(context->getParam("uint32_test", actual_uint32));
  309. EXPECT_EQ(77, actual_uint32);
  310. actual_string = "";
  311. EXPECT_NO_THROW(context->getParam("string_test", actual_string));
  312. EXPECT_EQ("hmmm chewy", actual_string);
  313. actual_extra = 0;
  314. EXPECT_NO_THROW(context->getExtraParam("extra_test", actual_extra));
  315. EXPECT_EQ(430, actual_extra);
  316. }
  317. } // end of anonymous namespace