cfgmgr_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright (C) 2012 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. }
  34. ~CfgMgrTest() {
  35. CfgMgr::instance().deleteSubnets6();
  36. CfgMgr::instance().deleteOptionDefs();
  37. }
  38. };
  39. // This test verifies that multiple option definitions can be added
  40. // under different option spaces.
  41. TEST_F(CfgMgrTest, getOptionDefs) {
  42. CfgMgr& cfg_mgr = CfgMgr::instance();
  43. // Create a set of option definitions with codes between 100 and 109.
  44. for (uint16_t code = 100; code < 110; ++code) {
  45. std::ostringstream option_name;
  46. // Option name is unique, e.g. option-100, option-101 etc.
  47. option_name << "option-" << code;
  48. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  49. "uint16"));
  50. // Add option definition to "isc" option space.
  51. // Option codes are not duplicated so expect no error
  52. // when adding them.
  53. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
  54. }
  55. // Create a set of option definitions with codes between 105 and 114 and
  56. // add them to the different option space.
  57. for (uint16_t code = 105; code < 115; ++code) {
  58. std::ostringstream option_name;
  59. option_name << "option-" << code;
  60. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  61. "uint16"));
  62. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
  63. }
  64. // Sanity check that all 10 option definitions are there.
  65. OptionDefContainerPtr option_defs1 = cfg_mgr.getOptionDefs("isc");
  66. ASSERT_TRUE(option_defs1);
  67. ASSERT_EQ(10, option_defs1->size());
  68. // Iterate over all option definitions and check that they have
  69. // valid codes. Also, their order should be the same as they
  70. // were added (codes 100-109).
  71. uint16_t code = 100;
  72. for (OptionDefContainer::const_iterator it = option_defs1->begin();
  73. it != option_defs1->end(); ++it, ++code) {
  74. OptionDefinitionPtr def(*it);
  75. ASSERT_TRUE(def);
  76. EXPECT_EQ(code, def->getCode());
  77. }
  78. // Sanity check that all 10 option definitions are there.
  79. OptionDefContainerPtr option_defs2 = cfg_mgr.getOptionDefs("abcde");
  80. ASSERT_TRUE(option_defs2);
  81. ASSERT_EQ(10, option_defs2->size());
  82. // Check that the option codes are valid.
  83. code = 105;
  84. for (OptionDefContainer::const_iterator it = option_defs2->begin();
  85. it != option_defs2->end(); ++it, ++code) {
  86. OptionDefinitionPtr def(*it);
  87. ASSERT_TRUE(def);
  88. EXPECT_EQ(code, def->getCode());
  89. }
  90. // Let's make one more check that the empty set is returned when
  91. // invalid option space is used.
  92. OptionDefContainerPtr option_defs3 = cfg_mgr.getOptionDefs("non-existing");
  93. ASSERT_TRUE(option_defs3);
  94. EXPECT_TRUE(option_defs3->empty());
  95. }
  96. // This test verifies that single option definition is correctly
  97. // returned with getOptionDef function.
  98. TEST_F(CfgMgrTest, getOptionDef) {
  99. CfgMgr& cfg_mgr = CfgMgr::instance();
  100. // Create a set of option definitions with codes between 100 and 109.
  101. for (uint16_t code = 100; code < 110; ++code) {
  102. std::ostringstream option_name;
  103. // Option name is unique, e.g. option-100, option-101 etc.
  104. option_name << "option-" << code;
  105. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  106. "uint16"));
  107. // Add option definition to "isc" option space.
  108. // Option codes are not duplicated so expect no error
  109. // when adding them.
  110. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
  111. }
  112. // Create a set of option definitions with codes between 105 and 114 and
  113. // add them to the different option space.
  114. for (uint16_t code = 105; code < 115; ++code) {
  115. std::ostringstream option_name;
  116. option_name << "option-other-" << code;
  117. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  118. "uint16"));
  119. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "abcde"));
  120. }
  121. // Try to get option definitions one by one using all codes
  122. // that we expect to be there.
  123. for (uint16_t code = 100; code < 110; ++code) {
  124. OptionDefinitionPtr def = cfg_mgr.getOptionDef("isc", code);
  125. ASSERT_TRUE(def);
  126. // Check that the option name is in the format of 'option-[code]'.
  127. // That way we make sure that the options that have the same codes
  128. // within different option spaces are different.
  129. std::ostringstream option_name;
  130. option_name << "option-" << code;
  131. EXPECT_EQ(option_name.str(), def->getName());
  132. EXPECT_EQ(code, def->getCode());
  133. }
  134. // Check that the option codes are valid.
  135. for (uint16_t code = 105; code < 115; ++code) {
  136. OptionDefinitionPtr def = cfg_mgr.getOptionDef("abcde", code);
  137. ASSERT_TRUE(def);
  138. // Check that the option name is in the format of 'option-other-[code]'.
  139. // That way we make sure that the options that have the same codes
  140. // within different option spaces are different.
  141. std::ostringstream option_name;
  142. option_name << "option-other-" << code;
  143. EXPECT_EQ(option_name.str(), def->getName());
  144. EXPECT_EQ(code, def->getCode());
  145. }
  146. // Check that an option definition can be added to the standard
  147. // (dhcp4 and dhcp6) option spaces when the option code is not
  148. // reserved by the standard option.
  149. OptionDefinitionPtr def6(new OptionDefinition("option-foo", 79, "uint16"));
  150. EXPECT_NO_THROW(cfg_mgr.addOptionDef(def6, "dhcp6"));
  151. OptionDefinitionPtr def4(new OptionDefinition("option-foo", 222, "uint16"));
  152. EXPECT_NO_THROW(cfg_mgr.addOptionDef(def4, "dhcp4"));
  153. // Try to query the option definition from an non-existing
  154. // option space and expect NULL pointer.
  155. OptionDefinitionPtr def = cfg_mgr.getOptionDef("non-existing", 56);
  156. EXPECT_FALSE(def);
  157. // Try to get the non-existing option definition from an
  158. // existing option space.
  159. EXPECT_FALSE(cfg_mgr.getOptionDef("isc", 56));
  160. }
  161. // This test verifies that the function that adds new option definition
  162. // throws exceptions when arguments are invalid.
  163. TEST_F(CfgMgrTest, addOptionDefNegative) {
  164. CfgMgr& cfg_mgr = CfgMgr::instance();
  165. // The option code 65 is reserved for standard options either in
  166. // DHCPv4 or DHCPv6. Thus we expect that adding an option to this
  167. // option space fails.
  168. OptionDefinitionPtr def(new OptionDefinition("option-foo", 65, "uint16"));
  169. // Try reserved option space names.
  170. ASSERT_THROW(cfg_mgr.addOptionDef(def, "dhcp4"), isc::BadValue);
  171. ASSERT_THROW(cfg_mgr.addOptionDef(def, "dhcp6"), isc::BadValue);
  172. // Try empty option space name.
  173. ASSERT_THROW(cfg_mgr.addOptionDef(def, ""), isc::BadValue);
  174. // Try NULL option definition.
  175. ASSERT_THROW(cfg_mgr.addOptionDef(OptionDefinitionPtr(), "isc"),
  176. isc::dhcp::MalformedOptionDefinition);
  177. // Try adding option definition twice and make sure that it
  178. // fails on the second attempt.
  179. ASSERT_NO_THROW(cfg_mgr.addOptionDef(def, "isc"));
  180. EXPECT_THROW(cfg_mgr.addOptionDef(def, "isc"), DuplicateOptionDefinition);
  181. }
  182. // This test verifies if the configuration manager is able to hold and return
  183. // valid leases
  184. TEST_F(CfgMgrTest, subnet4) {
  185. CfgMgr& cfg_mgr = CfgMgr::instance();
  186. Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"), 26, 1, 2, 3));
  187. Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.64"), 26, 1, 2, 3));
  188. Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.2.128"), 26, 1, 2, 3));
  189. // there shouldn't be any subnet configured at this stage
  190. EXPECT_EQ( Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.0")));
  191. cfg_mgr.addSubnet4(subnet1);
  192. // Now we have only one subnet, any request will be served from it
  193. EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.63")));
  194. // Now we add more subnets and check that both old and new subnets
  195. // are accessible.
  196. cfg_mgr.addSubnet4(subnet2);
  197. cfg_mgr.addSubnet4(subnet3);
  198. EXPECT_EQ(subnet3, cfg_mgr.getSubnet4(IOAddress("192.0.2.191")));
  199. EXPECT_EQ(subnet1, cfg_mgr.getSubnet4(IOAddress("192.0.2.15")));
  200. EXPECT_EQ(subnet2, cfg_mgr.getSubnet4(IOAddress("192.0.2.85")));
  201. // Try to find an address that does not belong to any subnet
  202. EXPECT_EQ(Subnet4Ptr(), cfg_mgr.getSubnet4(IOAddress("192.0.2.192")));
  203. }
  204. // This test verifies if the configuration manager is able to hold and return
  205. // valid leases
  206. TEST_F(CfgMgrTest, subnet6) {
  207. CfgMgr& cfg_mgr = CfgMgr::instance();
  208. Subnet6Ptr subnet1(new Subnet6(IOAddress("2000::"), 48, 1, 2, 3, 4));
  209. Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 48, 1, 2, 3, 4));
  210. Subnet6Ptr subnet3(new Subnet6(IOAddress("4000::"), 48, 1, 2, 3, 4));
  211. // there shouldn't be any subnet configured at this stage
  212. EXPECT_EQ( Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("2000::1")));
  213. cfg_mgr.addSubnet6(subnet1);
  214. // Now we have only one subnet, any request will be served from it
  215. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("2000::1")));
  216. // If we have only a single subnet and the request came from a local
  217. // address, let's use that subnet
  218. EXPECT_EQ(subnet1, cfg_mgr.getSubnet6(IOAddress("fe80::dead:beef")));
  219. cfg_mgr.addSubnet6(subnet2);
  220. cfg_mgr.addSubnet6(subnet3);
  221. EXPECT_EQ(subnet3, cfg_mgr.getSubnet6(IOAddress("4000::123")));
  222. EXPECT_EQ(subnet2, cfg_mgr.getSubnet6(IOAddress("3000::dead:beef")));
  223. EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("5000::1")));
  224. cfg_mgr.deleteSubnets6();
  225. EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("200::123")));
  226. EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("3000::123")));
  227. EXPECT_EQ(Subnet6Ptr(), cfg_mgr.getSubnet6(IOAddress("4000::123")));
  228. }
  229. } // end of anonymous namespace