cfg_option_def_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright (C) 2014 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 <dhcp/dhcp4.h>
  16. #include <dhcp/dhcp6.h>
  17. #include <dhcp/option_space.h>
  18. #include <dhcpsrv/cfg_option_def.h>
  19. #include <gtest/gtest.h>
  20. using namespace isc;
  21. using namespace isc::dhcp;
  22. namespace {
  23. // This test checks that two option definition configurations can be
  24. // compared for equality.
  25. TEST(CfgOptionDefTest, equal) {
  26. CfgOptionDef cfg1;
  27. CfgOptionDef cfg2;
  28. // Default objects must be equal.
  29. ASSERT_TRUE(cfg1 == cfg2);
  30. ASSERT_FALSE(cfg1 != cfg2);
  31. // Let's add the same option but to two different option spaces.
  32. cfg1.add(OptionDefinitionPtr(new OptionDefinition("option-foo",
  33. 5, "uint16")), "isc");
  34. cfg2.add(OptionDefinitionPtr(new OptionDefinition("option-foo",
  35. 5, "uint16")), "dns");
  36. // Configurations must be unequal.
  37. ASSERT_FALSE(cfg1 == cfg2);
  38. ASSERT_TRUE(cfg1 != cfg2);
  39. // Now, let's add them again but to original option spaces. Both objects
  40. // should now contain the same options under two option spaces. The
  41. // order should not matter so configurations should be equal.
  42. cfg1.add(OptionDefinitionPtr(new OptionDefinition("option-foo",
  43. 5, "uint16")), "dns");
  44. cfg2.add(OptionDefinitionPtr(new OptionDefinition("option-foo",
  45. 5, "uint16")), "isc");
  46. EXPECT_TRUE(cfg1 == cfg2);
  47. EXPECT_FALSE(cfg1 != cfg2);
  48. }
  49. // This test verifies that multiple option definitions can be added
  50. // under different option spaces.
  51. TEST(CfgOptionDefTest, getAll) {
  52. CfgOptionDef cfg;
  53. // Create a set of option definitions with codes between 100 and 109.
  54. for (uint16_t code = 100; code < 110; ++code) {
  55. std::ostringstream option_name;
  56. // Option name is unique, e.g. option-100, option-101 etc.
  57. option_name << "option-" << code;
  58. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  59. "uint16"));
  60. // Add option definition to "isc" option space.
  61. // Option codes are not duplicated so expect no error
  62. // when adding them.
  63. ASSERT_NO_THROW(cfg.add(def, "isc"));
  64. }
  65. // Create a set of option definitions with codes between 105 and 114 and
  66. // add them to the different option space.
  67. for (uint16_t code = 105; code < 115; ++code) {
  68. std::ostringstream option_name;
  69. option_name << "option-" << code;
  70. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  71. "uint16"));
  72. ASSERT_NO_THROW(cfg.add(def, "abcde"));
  73. }
  74. // Sanity check that all 10 option definitions are there.
  75. OptionDefContainerPtr option_defs1 = cfg.getAll("isc");
  76. ASSERT_TRUE(option_defs1);
  77. ASSERT_EQ(10, option_defs1->size());
  78. // Iterate over all option definitions and check that they have
  79. // valid codes. Also, their order should be the same as they
  80. // were added (codes 100-109).
  81. uint16_t code = 100;
  82. for (OptionDefContainer::const_iterator it = option_defs1->begin();
  83. it != option_defs1->end(); ++it, ++code) {
  84. OptionDefinitionPtr def(*it);
  85. ASSERT_TRUE(def);
  86. EXPECT_EQ(code, def->getCode());
  87. }
  88. // Sanity check that all 10 option definitions are there.
  89. OptionDefContainerPtr option_defs2 = cfg.getAll("abcde");
  90. ASSERT_TRUE(option_defs2);
  91. ASSERT_EQ(10, option_defs2->size());
  92. // Check that the option codes are valid.
  93. code = 105;
  94. for (OptionDefContainer::const_iterator it = option_defs2->begin();
  95. it != option_defs2->end(); ++it, ++code) {
  96. OptionDefinitionPtr def(*it);
  97. ASSERT_TRUE(def);
  98. EXPECT_EQ(code, def->getCode());
  99. }
  100. // Let's make one more check that the empty set is returned when
  101. // invalid option space is used.
  102. OptionDefContainerPtr option_defs3 = cfg.getAll("non-existing");
  103. ASSERT_TRUE(option_defs3);
  104. EXPECT_TRUE(option_defs3->empty());
  105. }
  106. // This test verifies that single option definition is correctly
  107. // returned with get function.
  108. TEST(CfgOptionDefTest, get) {
  109. CfgOptionDef cfg;
  110. // Create a set of option definitions with codes between 100 and 109.
  111. for (uint16_t code = 100; code < 110; ++code) {
  112. std::ostringstream option_name;
  113. // Option name is unique, e.g. option-100, option-101 etc.
  114. option_name << "option-" << code;
  115. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  116. "uint16"));
  117. // Add option definition to "isc" option space.
  118. // Option codes are not duplicated so expect no error
  119. // when adding them.
  120. ASSERT_NO_THROW(cfg.add(def, "isc"));
  121. }
  122. // Create a set of option definitions with codes between 105 and 114 and
  123. // add them to the different option space.
  124. for (uint16_t code = 105; code < 115; ++code) {
  125. std::ostringstream option_name;
  126. option_name << "option-other-" << code;
  127. OptionDefinitionPtr def(new OptionDefinition(option_name.str(), code,
  128. "uint16"));
  129. ASSERT_NO_THROW(cfg.add(def, "abcde"));
  130. }
  131. // Try to get option definitions one by one using all codes
  132. // that we expect to be there.
  133. for (uint16_t code = 100; code < 110; ++code) {
  134. OptionDefinitionPtr def = cfg.get("isc", code);
  135. ASSERT_TRUE(def);
  136. // Check that the option name is in the format of 'option-[code]'.
  137. // That way we make sure that the options that have the same codes
  138. // within different option spaces are different.
  139. std::ostringstream option_name;
  140. option_name << "option-" << code;
  141. EXPECT_EQ(option_name.str(), def->getName());
  142. EXPECT_EQ(code, def->getCode());
  143. // Try to get the same option definition using an option name as
  144. // a key.
  145. def = cfg.get("isc", option_name.str());
  146. ASSERT_TRUE(def);
  147. EXPECT_EQ(code, def->getCode());
  148. }
  149. // Check that the option codes are valid.
  150. for (uint16_t code = 105; code < 115; ++code) {
  151. OptionDefinitionPtr def = cfg.get("abcde", code);
  152. ASSERT_TRUE(def);
  153. // Check that the option name is in the format of 'option-other-[code]'.
  154. // That way we make sure that the options that have the same codes
  155. // within different option spaces are different.
  156. std::ostringstream option_name;
  157. option_name << "option-other-" << code;
  158. EXPECT_EQ(option_name.str(), def->getName());
  159. EXPECT_EQ(code, def->getCode());
  160. // Try to get the same option definition using an option name as
  161. // a key.
  162. def = cfg.get("abcde", option_name.str());
  163. ASSERT_TRUE(def);
  164. EXPECT_EQ(code, def->getCode());
  165. }
  166. // Check that an option definition can be added to the standard
  167. // (dhcp4 and dhcp6) option spaces when the option code is not
  168. // reserved by the standard option.
  169. OptionDefinitionPtr def6(new OptionDefinition("option-foo", 79, "uint16"));
  170. EXPECT_NO_THROW(cfg.add(def6, DHCP6_OPTION_SPACE));
  171. OptionDefinitionPtr def4(new OptionDefinition("option-foo", 222, "uint16"));
  172. EXPECT_NO_THROW(cfg.add(def4, DHCP4_OPTION_SPACE));
  173. // Try to query the option definition from an non-existing
  174. // option space and expect NULL pointer.
  175. OptionDefinitionPtr def = cfg.get("non-existing", 56);
  176. EXPECT_FALSE(def);
  177. // Try to get the non-existing option definition from an
  178. // existing option space.
  179. EXPECT_FALSE(cfg.get("isc", 56));
  180. }
  181. // This test verifies that it is not allowed to override a definition of the
  182. // standard option which has its definition defined in libdhcp++, but it is
  183. // allowed to create a definition for the standard option which doesn't have
  184. // its definition in libdhcp++.
  185. TEST(CfgOptionDefTest, overrideStdOptionDef) {
  186. CfgOptionDef cfg;
  187. OptionDefinitionPtr def;
  188. // There is a definition for routers option in libdhcp++, so an attempt
  189. // to add (override) another definition for this option should fail.
  190. def.reset(new OptionDefinition("routers", DHO_ROUTERS, "uint32"));
  191. EXPECT_THROW(cfg.add(def, DHCP4_OPTION_SPACE), isc::BadValue);
  192. /// @todo There is no definition for the NIS Server Addr option in
  193. /// libdhcp++. Once it is implemented it should be not allowed to
  194. /// add a custom definition for it. At the moment, it should be ok
  195. /// to add a definition for this option (using configuration mechanism)
  196. /// because we haven't implemented the one in libdhcp++.
  197. def.reset(new OptionDefinition("nis-server-addr", 65, "uint16"));
  198. EXPECT_NO_THROW(cfg.add(def, DHCP4_OPTION_SPACE));
  199. // It is not allowed to override the definition of the option which
  200. // has its definition in the libdhcp++.
  201. def.reset(new OptionDefinition("sntp-servers", D6O_SNTP_SERVERS,
  202. "ipv4-address"));
  203. EXPECT_THROW(cfg.add(def, DHCP6_OPTION_SPACE), isc::BadValue);
  204. // There is no definition for option 63 in libdhcp++ yet, so it should
  205. // be possible provide a custom definition.
  206. def.reset(new OptionDefinition("geolocation", 63, "uint32"));
  207. EXPECT_NO_THROW(cfg.add(def, DHCP6_OPTION_SPACE));
  208. }
  209. // This test verifies that the function that adds new option definition
  210. // throws exceptions when arguments are invalid.
  211. TEST(CfgOptionDefTest, addNegative) {
  212. CfgOptionDef cfg;
  213. OptionDefinitionPtr def(new OptionDefinition("option-foo", 1000, "uint16"));
  214. // Try empty option space name.
  215. ASSERT_THROW(cfg.add(def, ""), isc::BadValue);
  216. // Try NULL option definition.
  217. ASSERT_THROW(cfg.add(OptionDefinitionPtr(), "isc"),
  218. isc::dhcp::MalformedOptionDefinition);
  219. // Try adding option definition twice and make sure that it
  220. // fails on the second attempt.
  221. ASSERT_NO_THROW(cfg.add(def, "isc"));
  222. EXPECT_THROW(cfg.add(def, "isc"), DuplicateOptionDefinition);
  223. }
  224. }