cfgmgr_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // Copyright (C) 2012-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.h>
  15. #include <dhcpsrv/cfgmgr.h>
  16. #include <exceptions/exceptions.h>
  17. #include <gtest/gtest.h>
  18. #include <iostream>
  19. #include <sstream>
  20. #include <arpa/inet.h>
  21. using namespace std;
  22. using namespace isc::asiolink;
  23. using namespace isc::dhcp;
  24. using namespace isc::util;
  25. using namespace isc;
  26. // don't import the entire boost namespace. It will unexpectedly hide uint8_t
  27. // for some systems.
  28. using boost::scoped_ptr;
  29. namespace {
  30. class CfgMgrTest : public ::testing::Test {
  31. public:
  32. CfgMgrTest() {
  33. // make sure we start with a clean configuration
  34. CfgMgr::instance().deleteSubnets4();
  35. CfgMgr::instance().deleteSubnets6();
  36. }
  37. ~CfgMgrTest() {
  38. // clean up after the test
  39. CfgMgr::instance().deleteSubnets4();
  40. CfgMgr::instance().deleteSubnets6();
  41. CfgMgr::instance().deleteOptionDefs();
  42. }
  43. };
  44. // This test verifies that multiple option definitions can be added
  45. // under different option spaces.
  46. TEST_F(CfgMgrTest, getOptionDefs) {
  47. CfgMgr& cfg_mgr = CfgMgr::instance();
  48. // Create a set of option definitions with codes between 100 and 109.
  49. for (uint16_t code = 100; code < 110; ++code) {
  50. std::ostringstream option_name;
  51. // Option name is unique, e.g. option-100, option-101 etc.
  52. option_name << "option-" << code;
  53. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  54. "uint16"));
  55. // Add option definition to "isc" option space.
  56. // Option codes are not duplicated so expect no error
  57. // when adding them.
  58. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
  59. }
  60. // Create a set of option definitions with codes between 105 and 114 and
  61. // add them to the different option space.
  62. for (uint16_t code = 105; code < 115; ++code) {
  63. std::ostringstream option_name;
  64. option_name << "option-" << code;
  65. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  66. "uint16"));
  67. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
  68. }
  69. // Sanity check that all 10 option definitions are there.
  70. OptionDefContainerPtr option_defs1 = cfg_mgr.getOptionDefs("isc");
  71. ASSERT_TRUE(option_defs1);
  72. ASSERT_EQ(10, option_defs1->size());
  73. // Iterate over all option definitions and check that they have
  74. // valid codes. Also, their order should be the same as they
  75. // were added (codes 100-109).
  76. uint16_t code = 100;
  77. for (OptionDefContainer::const_iterator it = option_defs1->begin();
  78. it != option_defs1->end(); ++it, ++code) {
  79. OptionDefinitionPtr def(*it);
  80. ASSERT_TRUE(def);
  81. EXPECT_EQ(code, def->getCode());
  82. }
  83. // Sanity check that all 10 option definitions are there.
  84. OptionDefContainerPtr option_defs2 = cfg_mgr.getOptionDefs("abcde");
  85. ASSERT_TRUE(option_defs2);
  86. ASSERT_EQ(10, option_defs2->size());
  87. // Check that the option codes are valid.
  88. code = 105;
  89. for (OptionDefContainer::const_iterator it = option_defs2->begin();
  90. it != option_defs2->end(); ++it, ++code) {
  91. OptionDefinitionPtr def(*it);
  92. ASSERT_TRUE(def);
  93. EXPECT_EQ(code, def->getCode());
  94. }
  95. // Let's make one more check that the empty set is returned when
  96. // invalid option space is used.
  97. OptionDefContainerPtr option_defs3 = cfg_mgr.getOptionDefs("non-existing");
  98. ASSERT_TRUE(option_defs3);
  99. EXPECT_TRUE(option_defs3->empty());
  100. }
  101. // This test verifies that single option definition is correctly
  102. // returned with getOptionDef function.
  103. TEST_F(CfgMgrTest, getOptionDef) {
  104. CfgMgr& cfg_mgr = CfgMgr::instance();
  105. // Create a set of option definitions with codes between 100 and 109.
  106. for (uint16_t code = 100; code < 110; ++code) {
  107. std::ostringstream option_name;
  108. // Option name is unique, e.g. option-100, option-101 etc.
  109. option_name << "option-" << code;
  110. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  111. "uint16"));
  112. // Add option definition to "isc" option space.
  113. // Option codes are not duplicated so expect no error
  114. // when adding them.
  115. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
  116. }
  117. // Create a set of option definitions with codes between 105 and 114 and
  118. // add them to the different option space.
  119. for (uint16_t code = 105; code < 115; ++code) {
  120. std::ostringstream option_name;
  121. option_name << "option-other-" << code;
  122. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  123. "uint16"));
  124. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
  125. }
  126. // Try to get option definitions one by one using all codes
  127. // that we expect to be there.
  128. for (uint16_t code = 100; code < 110; ++code) {
  129. OptionDefinitionPtr def = cfg_mgr.getOptionDef("isc", code);
  130. ASSERT_TRUE(def);
  131. // Check that the option name is in the format of 'option-[code]'.
  132. // That way we make sure that the options that have the same codes
  133. // within different option spaces are different.
  134. std::ostringstream option_name;
  135. option_name << "option-" << code;
  136. EXPECT_EQ(option_name.str(), def->getName());
  137. EXPECT_EQ(code, def->getCode());
  138. }
  139. // Check that the option codes are valid.
  140. for (uint16_t code = 105; code < 115; ++code) {
  141. OptionDefinitionPtr def = cfg_mgr.getOptionDef("abcde", code);
  142. ASSERT_TRUE(def);
  143. // Check that the option name is in the format of 'option-other-[code]'.
  144. // That way we make sure that the options that have the same codes
  145. // within different option spaces are different.
  146. std::ostringstream option_name;
  147. option_name << "option-other-" << code;
  148. EXPECT_EQ(option_name.str(), def->getName());
  149. EXPECT_EQ(code, def->getCode());
  150. }
  151. // Check that an option definition can be added to the standard
  152. // (dhcp4 and dhcp6) option spaces when the option code is not
  153. // reserved by the standard option.
  154. OptionDefinitionPtr def6(new OptionDefinition("option-foo", 79, "uint16"));
  155. EXPECT_NO_THROW(cfg_mgr.addOptionDef(def6, "dhcp6"));
  156. OptionDefinitionPtr def4(new OptionDefinition("option-foo", 222, "uint16"));
  157. EXPECT_NO_THROW(cfg_mgr.addOptionDef(def4, "dhcp4"));
  158. // Try to query the option definition from an non-existing
  159. // option space and expect NULL pointer.
  160. OptionDefinitionPtr def = cfg_mgr.getOptionDef("non-existing", 56);
  161. EXPECT_FALSE(def);
  162. // Try to get the non-existing option definition from an
  163. // existing option space.
  164. EXPECT_FALSE(cfg_mgr.getOptionDef("isc", 56));
  165. }
  166. // This test verifies that the function that adds new option definition
  167. // throws exceptions when arguments are invalid.
  168. TEST_F(CfgMgrTest, addOptionDefNegative) {
  169. CfgMgr& cfg_mgr = CfgMgr::instance();
  170. // The option code 65 is reserved for standard options either in
  171. // DHCPv4 or DHCPv6. Thus we expect that adding an option to this
  172. // option space fails.
  173. OptionDefinitionPtr def(new OptionDefinition("option-foo", 65, "uint16"));
  174. // Try reserved option space names.
  175. ASSERT_THROW(cfg_mgr.addOptionDef(def, "dhcp4"), isc::BadValue);
  176. ASSERT_THROW(cfg_mgr.addOptionDef(def, "dhcp6"), isc::BadValue);
  177. // Try empty option space name.
  178. ASSERT_THROW(cfg_mgr.addOptionDef(def, ""), isc::BadValue);
  179. // Try NULL option definition.
  180. ASSERT_THROW(cfg_mgr.addOptionDef(OptionDefinitionPtr(), "isc"),
  181. isc::dhcp::MalformedOptionDefinition);
  182. // Try adding option definition twice and make sure that it
  183. // fails on the second attempt.
  184. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
  185. EXPECT_THROW(cfg_mgr.addOptionDef(def, "isc"), DuplicateOptionDefinition);
  186. }
  187. // This test verifies if the configuration manager is able to hold and return
  188. // valid leases
  189. TEST_F(CfgMgrTest, subnet4) {
  190. CfgMgr& cfg_mgr = CfgMgr::instance();
  191. Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
  192. Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
  193. Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
  194. // There shouldn't be any subnet configured at this stage
  195. EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.0")));
  196. cfg_mgr.addSubnet4(subnet1);
  197. // Now we have only one subnet, any request will be served from it
  198. EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.63")));
  199. // Now we add more subnets and check that both old and new subnets
  200. // are accessible.
  201. cfg_mgr.addSubnet4(subnet2);
  202. cfg_mgr.addSubnet4(subnet3);
  203. EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.191")));
  204. EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.15")));
  205. EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.85")));
  206. // Try to find an address that does not belong to any subnet
  207. EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.192")));
  208. // Check that deletion of the subnets works.
  209. cfg_mgr.deleteSubnets4();
  210. EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.191")));
  211. EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.15")));
  212. EXPECT_FALSE(cfg_mgr.getSubnet4(IOAddress("192.0.2.85")));
  213. }
  214. // This test verifies if the configuration manager is able to hold and return
  215. // valid leases
  216. TEST_F(CfgMgrTest, subnet6) {
  217. CfgMgr& cfg_mgr = CfgMgr::instance();
  218. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  219. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  220. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  221. // There shouldn't be any subnet configured at this stage
  222. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("2000::1")));
  223. cfg_mgr.addSubnet6(subnet1);
  224. // Now we have only one subnet, any request will be served from it
  225. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1")));
  226. // If we have only a single subnet and the request came from a local
  227. // address, let's use that subnet
  228. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef")));
  229. cfg_mgr.addSubnet6(subnet2);
  230. cfg_mgr.addSubnet6(subnet3);
  231. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
  232. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
  233. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("5000::1")));
  234. // Check that deletion of the subnets works.
  235. cfg_mgr.deleteSubnets6();
  236. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("200::123")));
  237. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("3000::123")));
  238. EXPECT_FALSE(cfg_mgr.getSubnet6(IOAddress("4000::123")));
  239. }
  240. // This test verifies that new DHCPv4 option spaces can be added to
  241. // the configuration manager and that duplicated option space is
  242. // rejected.
  243. TEST_F(CfgMgrTest, optionSpace4) {
  244. CfgMgr& cfg_mgr = CfgMgr::instance();
  245. // Create some option spaces.
  246. OptionSpacePtr space1(new OptionSpace("isc", false));
  247. OptionSpacePtr space2(new OptionSpace("xyz", true));
  248. // Add option spaces with different names and expect they
  249. // are accepted.
  250. ASSERT_NO_THROW(cfg_mgr.addOptionSpace4(space1));
  251. ASSERT_NO_THROW(cfg_mgr.addOptionSpace4(space2));
  252. // Validate that the option spaces have been added correctly.
  253. const OptionSpaceCollection& spaces = cfg_mgr.getOptionSpaces4();
  254. ASSERT_EQ(2, spaces.size());
  255. EXPECT_FALSE(spaces.find("isc") == spaces.end());
  256. EXPECT_FALSE(spaces.find("xyz") == spaces.end());
  257. // Create another option space with the name that duplicates
  258. // the existing option space.
  259. OptionSpacePtr space3(new OptionSpace("isc", true));
  260. // Expect that the duplicate option space is rejected.
  261. ASSERT_THROW(
  262. cfg_mgr.addOptionSpace4(space3), isc::dhcp::InvalidOptionSpace
  263. );
  264. // @todo decode if a duplicate vendor space is allowed.
  265. }
  266. // This test verifies that new DHCPv6 option spaces can be added to
  267. // the configuration manager and that duplicated option space is
  268. // rejected.
  269. TEST_F(CfgMgrTest, optionSpace6) {
  270. CfgMgr& cfg_mgr = CfgMgr::instance();
  271. // Create some option spaces.
  272. OptionSpacePtr space1(new OptionSpace("isc", false));
  273. OptionSpacePtr space2(new OptionSpace("xyz", true));
  274. // Add option spaces with different names and expect they
  275. // are accepted.
  276. ASSERT_NO_THROW(cfg_mgr.addOptionSpace6(space1));
  277. ASSERT_NO_THROW(cfg_mgr.addOptionSpace6(space2));
  278. // Validate that the option spaces have been added correctly.
  279. const OptionSpaceCollection& spaces = cfg_mgr.getOptionSpaces6();
  280. ASSERT_EQ(2, spaces.size());
  281. EXPECT_FALSE(spaces.find("isc") == spaces.end());
  282. EXPECT_FALSE(spaces.find("xyz") == spaces.end());
  283. // Create another option space with the name that duplicates
  284. // the existing option space.
  285. OptionSpacePtr space3(new OptionSpace("isc", true));
  286. // Expect that the duplicate option space is rejected.
  287. ASSERT_THROW(
  288. cfg_mgr.addOptionSpace6(space3), isc::dhcp::InvalidOptionSpace
  289. );
  290. // @todo decide if a duplicate vendor space is allowed.
  291. }
  292. } // end of anonymous namespace