config_parser_unittest.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 <iostream>
  16. #include <fstream>
  17. #include <sstream>
  18. #include <arpa/inet.h>
  19. #include <gtest/gtest.h>
  20. #include <dhcp6/dhcp6_srv.h>
  21. #include <dhcp6/config_parser.h>
  22. #include <config/ccsession.h>
  23. #include <dhcp/subnet.h>
  24. #include <dhcp/cfgmgr.h>
  25. using namespace std;
  26. using namespace isc;
  27. using namespace isc::dhcp;
  28. using namespace isc::asiolink;
  29. using namespace isc::data;
  30. using namespace isc::config;
  31. namespace {
  32. class Dhcp6ParserTest : public ::testing::Test {
  33. public:
  34. Dhcp6ParserTest()
  35. :rcode_(-1) {
  36. // Open port 0 means to not do anything at all. We don't want to
  37. // deal with sockets here, just check if configuration handling
  38. // is sane.
  39. srv_ = new Dhcpv6Srv(0);
  40. }
  41. ~Dhcp6ParserTest() {
  42. delete srv_;
  43. };
  44. Dhcpv6Srv* srv_;
  45. int rcode_;
  46. ConstElementPtr comment_;
  47. };
  48. // Goal of this test is a verification if a very simple config update
  49. // with just a bumped version number. That's the simplest possible
  50. // config update.
  51. TEST_F(Dhcp6ParserTest, version) {
  52. ConstElementPtr x;
  53. EXPECT_NO_THROW(x = configureDhcp6Server(*srv_,
  54. Element::fromJSON("{\"version\": 0}")));
  55. // returned value must be 0 (configuration accepted)
  56. ASSERT_TRUE(x);
  57. comment_ = parseAnswer(rcode_, x);
  58. EXPECT_EQ(0, rcode_);
  59. }
  60. /// The goal of this test is to verify that the code accepts only
  61. /// valid commands and malformed or unsupported parameters are rejected.
  62. TEST_F(Dhcp6ParserTest, bogus_command) {
  63. ConstElementPtr x;
  64. EXPECT_NO_THROW(x = configureDhcp6Server(*srv_,
  65. Element::fromJSON("{\"bogus\": 5}")));
  66. // returned value must be 1 (configuration parse error)
  67. ASSERT_TRUE(x);
  68. comment_ = parseAnswer(rcode_, x);
  69. EXPECT_EQ(1, rcode_);
  70. }
  71. /// The goal of this test is to verify if wrongly defined subnet will
  72. /// be rejected. Properly defined subnet must include at least one
  73. /// pool definition.
  74. TEST_F(Dhcp6ParserTest, empty_subnet) {
  75. ConstElementPtr status;
  76. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_,
  77. Element::fromJSON("{ \"interface\": [ \"all\" ],"
  78. "\"preferred-lifetime\": 3000,"
  79. "\"rebind-timer\": 2000, "
  80. "\"renew-timer\": 1000, "
  81. "\"subnet6\": [ ], "
  82. "\"valid-lifetime\": 4000 }")));
  83. // returned value should be 0 (success)
  84. ASSERT_TRUE(status);
  85. comment_ = parseAnswer(rcode_, status);
  86. EXPECT_EQ(0, rcode_);
  87. }
  88. /// The goal of this test is to verify if defined subnet uses global
  89. /// parameter timer definitions.
  90. TEST_F(Dhcp6ParserTest, subnet_global_defaults) {
  91. ConstElementPtr status;
  92. string config = "{ \"interface\": [ \"all\" ],"
  93. "\"preferred-lifetime\": 3000,"
  94. "\"rebind-timer\": 2000, "
  95. "\"renew-timer\": 1000, "
  96. "\"subnet6\": [ { "
  97. " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
  98. " \"subnet\": \"2001:db8:1::/64\" } ],"
  99. "\"valid-lifetime\": 4000 }";
  100. cout << config << endl;
  101. ElementPtr json = Element::fromJSON(config);
  102. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  103. // check if returned status is OK
  104. ASSERT_TRUE(status);
  105. comment_ = parseAnswer(rcode_, status);
  106. EXPECT_EQ(0, rcode_);
  107. // Now check if the configuration was indeed handled and we have
  108. // expected pool configured.
  109. Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
  110. ASSERT_TRUE(subnet);
  111. EXPECT_EQ(1000, subnet->getT1());
  112. EXPECT_EQ(2000, subnet->getT2());
  113. EXPECT_EQ(3000, subnet->getPreferred());
  114. EXPECT_EQ(4000, subnet->getValid());
  115. }
  116. // This test checks if it is possible to override global values
  117. // on a per subnet basis.
  118. TEST_F(Dhcp6ParserTest, subnet_local) {
  119. ConstElementPtr status;
  120. string config = "{ \"interface\": [ \"all\" ],"
  121. "\"preferred-lifetime\": 3000,"
  122. "\"rebind-timer\": 2000, "
  123. "\"renew-timer\": 1000, "
  124. "\"subnet6\": [ { "
  125. " \"pool\": [ \"2001:db8:1::1 - 2001:db8:1::ffff\" ],"
  126. " \"renew-timer\": 1, "
  127. " \"rebind-timer\": 2, "
  128. " \"preferred-lifetime\": 3,"
  129. " \"valid-lifetime\": 4,"
  130. " \"subnet\": \"2001:db8:1::/64\" } ],"
  131. "\"valid-lifetime\": 4000 }";
  132. cout << config << endl;
  133. ElementPtr json = Element::fromJSON(config);
  134. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  135. // returned value should be 0 (configuration success)
  136. ASSERT_TRUE(status);
  137. comment_ = parseAnswer(rcode_, status);
  138. EXPECT_EQ(0, rcode_);
  139. Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
  140. ASSERT_TRUE(subnet);
  141. EXPECT_EQ(1, subnet->getT1());
  142. EXPECT_EQ(2, subnet->getT2());
  143. EXPECT_EQ(3, subnet->getPreferred());
  144. EXPECT_EQ(4, subnet->getValid());
  145. }
  146. // Test verifies that a subnet with pool values that do not belong to that
  147. // pool are rejected.
  148. TEST_F(Dhcp6ParserTest, pool_out_of_subnet) {
  149. ConstElementPtr status;
  150. string config = "{ \"interface\": [ \"all\" ],"
  151. "\"preferred-lifetime\": 3000,"
  152. "\"rebind-timer\": 2000, "
  153. "\"renew-timer\": 1000, "
  154. "\"subnet6\": [ { "
  155. " \"pool\": [ \"4001:db8:1::/80\" ],"
  156. " \"subnet\": \"2001:db8:1::/64\" } ],"
  157. "\"valid-lifetime\": 4000 }";
  158. cout << config << endl;
  159. ElementPtr json = Element::fromJSON(config);
  160. EXPECT_NO_THROW(status = configureDhcp6Server(*srv_, json));
  161. // returned value must be 2 (values error)
  162. // as the pool does not belong to that subnet
  163. ASSERT_TRUE(status);
  164. comment_ = parseAnswer(rcode_, status);
  165. EXPECT_EQ(2, rcode_);
  166. }
  167. // Goal of this test is to verify if pools can be defined
  168. // using prefix/length notation. There is no separate test for min-max
  169. // notation as it was tested in several previous tests.
  170. TEST_F(Dhcp6ParserTest, pool_prefix_len) {
  171. ConstElementPtr x;
  172. string config = "{ \"interface\": [ \"all\" ],"
  173. "\"preferred-lifetime\": 3000,"
  174. "\"rebind-timer\": 2000, "
  175. "\"renew-timer\": 1000, "
  176. "\"subnet6\": [ { "
  177. " \"pool\": [ \"2001:db8:1::/80\" ],"
  178. " \"subnet\": \"2001:db8:1::/64\" } ],"
  179. "\"valid-lifetime\": 4000 }";
  180. cout << config << endl;
  181. ElementPtr json = Element::fromJSON(config);
  182. EXPECT_NO_THROW(x = configureDhcp6Server(*srv_, json));
  183. // returned value must be 1 (configuration parse error)
  184. ASSERT_TRUE(x);
  185. comment_ = parseAnswer(rcode_, x);
  186. EXPECT_EQ(0, rcode_);
  187. Subnet6Ptr subnet = CfgMgr::instance().getSubnet6(IOAddress("2001:db8:1::5"));
  188. ASSERT_TRUE(subnet);
  189. EXPECT_EQ(1000, subnet->getT1());
  190. EXPECT_EQ(2000, subnet->getT2());
  191. EXPECT_EQ(3000, subnet->getPreferred());
  192. EXPECT_EQ(4000, subnet->getValid());
  193. }
  194. };