srv_config_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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/tests/iface_mgr_test_config.h>
  16. #include <dhcpsrv/cfgmgr.h>
  17. #include <dhcpsrv/srv_config.h>
  18. #include <dhcpsrv/subnet.h>
  19. #include <gtest/gtest.h>
  20. using namespace isc::asiolink;
  21. using namespace isc::dhcp;
  22. // Those are the tests for SrvConfig storage. Right now they are minimal,
  23. // but the number is expected to grow significantly once we migrate more
  24. // parameters from CfgMgr storage to SrvConfig storage.
  25. namespace {
  26. /// @brief Number of IPv4 and IPv6 subnets to be created for a test.
  27. const int TEST_SUBNETS_NUM = 3;
  28. /// @brief Test fixture class for testing configuration data storage.
  29. class SrvConfigTest : public ::testing::Test {
  30. public:
  31. /// @brief Constructor.
  32. ///
  33. /// Creates IPv4 and IPv6 subnets for unit test. The number of subnets
  34. /// is @c TEST_SUBNETS_NUM for IPv4 and IPv6 each.
  35. SrvConfigTest()
  36. : iface_mgr_test_config_(true) {
  37. // Remove any subnets dangling from previous unit tests.
  38. clearSubnets();
  39. // Disable DDNS.
  40. enableDDNS(false);
  41. // Create IPv4 subnets.
  42. for (int i = 0; i < TEST_SUBNETS_NUM; ++i) {
  43. // Default triplet carried undefined value.
  44. Triplet<uint32_t> def_triplet;
  45. // Create a collection of subnets: 192.0.X.0/24 where X is
  46. // 0, 1, 2 etc.
  47. Subnet4Ptr subnet(new Subnet4(IOAddress(0xC0000000 | (i << 2)),
  48. 24, def_triplet, def_triplet,
  49. 4000));
  50. test_subnets4_.push_back(subnet);
  51. }
  52. // Create IPv6 subnets.
  53. for (int i = 0; i < TEST_SUBNETS_NUM; ++i) {
  54. // This is a base prefix. All other prefixes will be created by
  55. // modifying this one.
  56. IOAddress prefix("2001:db8:1::0");
  57. std::vector<uint8_t> prefix_bytes = prefix.toBytes();
  58. // Modify 5th byte of the prefix, so 2001:db8:1::0 becomes
  59. // 2001:db8:2::0 etc.
  60. ++prefix_bytes[5];
  61. prefix = IOAddress::fromBytes(prefix.getFamily(), &prefix_bytes[0]);
  62. Subnet6Ptr subnet(new Subnet6(prefix, 64, 1000, 2000, 3000, 4000));
  63. test_subnets6_.push_back(subnet);
  64. }
  65. }
  66. /// @brief Destructor.
  67. ///
  68. /// Removes any dangling configuration.
  69. virtual ~SrvConfigTest() {
  70. clearSubnets();
  71. }
  72. /// @brief Convenience function which adds IPv4 subnet to the configuration.
  73. ///
  74. /// @param index Index of the subnet in the @c test_subnets4_ collection
  75. /// which should be added to the configuration. The configuration is stored
  76. /// in the @ conf_ member. This value must be lower than
  77. /// @c TEST_SUBNETS_NUM.
  78. ///
  79. /// @todo Until the subnets configuration is migrated from the @c CfgMgr to
  80. /// the @c SrvConfig object, this function adds the subnet to the
  81. /// @c CfgMgr. Once, the subnet configuration is held in the
  82. /// @c SrvConfig this function must be modified to store the subnets in
  83. /// the @c conf_ object.
  84. void addSubnet4(const unsigned int index);
  85. /// @brief Convenience function which adds IPv6 subnet to the configuration.
  86. ///
  87. /// @param index Index of the subnet in the @c test_subnets6_ collection
  88. /// which should be added to the configuration. The configuration is stored
  89. /// in the @ conf_ member. This value must be lower than
  90. /// @c TEST_SUBNETS_NUM.
  91. ///
  92. /// @todo Until the subnets configuration is migrated from the @c CfgMgr to
  93. /// the @c SrvConfig object, this function adds the subnet to the
  94. /// @c CfgMgr. Once, the subnet configuration is held in the
  95. /// @c SrvConfig this function must be modified to store the subnets in
  96. /// @c conf_ object.
  97. void addSubnet6(const unsigned int index);
  98. /// @brief Removes all subnets from the configuration.
  99. ///
  100. /// @todo Modify this function once the subnet configuration is migrated
  101. /// from @c CfgMgr to @c SrvConfig.
  102. void clearSubnets();
  103. /// @brief Enable/disable DDNS.
  104. ///
  105. /// @param enable A boolean value indicating if the DDNS should be
  106. /// enabled (true) or disabled (false).
  107. void enableDDNS(const bool enable);
  108. /// @brief Stores configuration.
  109. SrvConfig conf_;
  110. /// @brief A collection of IPv4 subnets used by unit tests.
  111. Subnet4Collection test_subnets4_;
  112. /// @brief A collection of IPv6 subnets used by unit tests.
  113. Subnet6Collection test_subnets6_;
  114. /// @brief Fakes interface configuration.
  115. isc::dhcp::test::IfaceMgrTestConfig iface_mgr_test_config_;
  116. };
  117. void
  118. SrvConfigTest::addSubnet4(const unsigned int index) {
  119. if (index >= TEST_SUBNETS_NUM) {
  120. FAIL() << "Subnet index " << index << "out of range (0.."
  121. << TEST_SUBNETS_NUM << "): " << "unable to add IPv4 subnet";
  122. }
  123. CfgMgr::instance().addSubnet4(test_subnets4_[index]);
  124. }
  125. void
  126. SrvConfigTest::addSubnet6(const unsigned int index) {
  127. if (index >= TEST_SUBNETS_NUM) {
  128. FAIL() << "Subnet index " << index << "out of range (0.."
  129. << TEST_SUBNETS_NUM << "): " << "unable to add IPv6 subnet";
  130. }
  131. CfgMgr::instance().addSubnet6(test_subnets6_[index]);
  132. }
  133. void
  134. SrvConfigTest::clearSubnets() {
  135. CfgMgr::instance().deleteSubnets4();
  136. CfgMgr::instance().deleteSubnets6();
  137. }
  138. void
  139. SrvConfigTest::enableDDNS(const bool enable) {
  140. // D2 configuration should always be non-NULL.
  141. CfgMgr::instance().getD2ClientConfig()->enableUpdates(enable);
  142. }
  143. // Check that by default there are no logging entries
  144. TEST_F(SrvConfigTest, basic) {
  145. EXPECT_TRUE(conf_.getLoggingInfo().empty());
  146. }
  147. // Check that SrvConfig can store logging information.
  148. TEST_F(SrvConfigTest, loggingInfo) {
  149. LoggingInfo log1;
  150. log1.clearDestinations();
  151. log1.name_ = "foo";
  152. log1.severity_ = isc::log::WARN;
  153. log1.debuglevel_ = 77;
  154. LoggingDestination dest;
  155. dest.output_ = "some-logfile.txt";
  156. dest.maxver_ = 5;
  157. dest.maxsize_ = 2097152;
  158. log1.destinations_.push_back(dest);
  159. conf_.addLoggingInfo(log1);
  160. EXPECT_EQ("foo", conf_.getLoggingInfo()[0].name_);
  161. EXPECT_EQ(isc::log::WARN, conf_.getLoggingInfo()[0].severity_);
  162. EXPECT_EQ(77, conf_.getLoggingInfo()[0].debuglevel_);
  163. EXPECT_EQ("some-logfile.txt", conf_.getLoggingInfo()[0].destinations_[0].output_);
  164. EXPECT_EQ(5, conf_.getLoggingInfo()[0].destinations_[0].maxver_);
  165. EXPECT_EQ(2097152, conf_.getLoggingInfo()[0].destinations_[0].maxsize_);
  166. }
  167. // Check that the configuration summary including information about the status
  168. // of DDNS is returned.
  169. TEST_F(SrvConfigTest, summaryDDNS) {
  170. EXPECT_EQ("DDNS: disabled",
  171. conf_.getConfigSummary(SrvConfig::CFGSEL_DDNS));
  172. enableDDNS(true);
  173. EXPECT_EQ("DDNS: enabled",
  174. conf_.getConfigSummary(SrvConfig::CFGSEL_DDNS));
  175. enableDDNS(false);
  176. EXPECT_EQ("no IPv4 subnets!; no IPv6 subnets!; DDNS: disabled",
  177. conf_.getConfigSummary(SrvConfig::CFGSEL_ALL));
  178. }
  179. // Check that the configuration summary including information about added
  180. // subnets is returned.
  181. TEST_F(SrvConfigTest, summarySubnets) {
  182. EXPECT_EQ("no config details available",
  183. conf_.getConfigSummary(SrvConfig::CFGSEL_NONE));
  184. // Initially, there are no subnets added but it should be explicitly
  185. // reported when we query for information about the subnets.
  186. EXPECT_EQ("no IPv4 subnets!; no IPv6 subnets!",
  187. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
  188. // If we just want information about IPv4 subnets, there should be no
  189. // mention of IPv6 subnets, even though there are none added.
  190. EXPECT_EQ("no IPv4 subnets!",
  191. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET4));
  192. // If we just want information about IPv6 subnets, there should be no
  193. // mention of IPv4 subnets, even though there are none added.
  194. EXPECT_EQ("no IPv6 subnets!",
  195. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET6));
  196. // Add IPv4 subnet and make sure it is reported.
  197. addSubnet4(0);
  198. EXPECT_EQ("added IPv4 subnets: 1",
  199. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET4));
  200. EXPECT_EQ("added IPv4 subnets: 1; no IPv6 subnets!",
  201. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
  202. // Add IPv6 subnet and make sure it is reported.
  203. addSubnet6(0);
  204. EXPECT_EQ("added IPv6 subnets: 1",
  205. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET6));
  206. EXPECT_EQ("added IPv4 subnets: 1; added IPv6 subnets: 1",
  207. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
  208. // Add one more subnet and make sure the bumped value is only
  209. // for IPv4, but not for IPv6.
  210. addSubnet4(1);
  211. EXPECT_EQ("added IPv4 subnets: 2; added IPv6 subnets: 1",
  212. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
  213. EXPECT_EQ("added IPv4 subnets: 2",
  214. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET4));
  215. addSubnet6(1);
  216. EXPECT_EQ("added IPv4 subnets: 2; added IPv6 subnets: 2",
  217. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
  218. // Remove all subnets and make sure that there are no reported subnets
  219. // back again.
  220. clearSubnets();
  221. EXPECT_EQ("no IPv4 subnets!; no IPv6 subnets!",
  222. conf_.getConfigSummary(SrvConfig::CFGSEL_SUBNET));
  223. }
  224. // This test checks if entire configuration can be copied and that the sequence
  225. // number is not affected.
  226. TEST_F(SrvConfigTest, copy) {
  227. // Create two configurations with different sequence numbers.
  228. SrvConfig conf1(32);
  229. SrvConfig conf2(64);
  230. // Set logging information for conf1.
  231. LoggingInfo info;
  232. info.name_ = "foo";
  233. info.severity_ = isc::log::DEBUG;
  234. info.debuglevel_ = 64;
  235. info.destinations_.push_back(LoggingDestination());
  236. // Set interface configuration for conf1.
  237. CfgIface cfg_iface;
  238. cfg_iface.use(AF_INET, "eth0");
  239. conf1.addLoggingInfo(info);
  240. conf1.setCfgIface(cfg_iface);
  241. // Add option definition.
  242. OptionDefinitionPtr def(new OptionDefinition("option-foo", 5, "string"));
  243. conf1.getCfgOptionDef()->add(def, "isc");
  244. // Add an option.
  245. OptionPtr option(new Option(Option::V6, 1000, OptionBuffer(10, 0xFF)));
  246. conf1.getCfgOption()->add(option, true, "dhcp6");
  247. // Make sure both configurations are different.
  248. ASSERT_TRUE(conf1 != conf2);
  249. // Copy conf1 to conf2.
  250. ASSERT_NO_THROW(conf1.copy(conf2));
  251. // Now they should be equal.
  252. EXPECT_TRUE(conf1 == conf2);
  253. // But, their sequence numbers should be unequal.
  254. EXPECT_FALSE(conf1.sequenceEquals(conf2));
  255. }
  256. // This test checks that two configurations can be compared for (in)equality.
  257. TEST_F(SrvConfigTest, equality) {
  258. SrvConfig conf1(32);
  259. SrvConfig conf2(64);
  260. // Initially, both objects should be equal, even though the configuration
  261. // sequences are not matching.
  262. EXPECT_TRUE(conf1 == conf2);
  263. EXPECT_FALSE(conf1 != conf2);
  264. // Differ by logging information.
  265. LoggingInfo info1;
  266. LoggingInfo info2;
  267. info1.name_ = "foo";
  268. info2.name_ = "bar";
  269. conf1.addLoggingInfo(info1);
  270. conf2.addLoggingInfo(info2);
  271. EXPECT_FALSE(conf1 == conf2);
  272. EXPECT_TRUE(conf1 != conf2);
  273. conf1.addLoggingInfo(info2);
  274. conf2.addLoggingInfo(info1);
  275. EXPECT_TRUE(conf1 == conf2);
  276. EXPECT_FALSE(conf1 != conf2);
  277. // Differ by interface configuration.
  278. CfgIface cfg_iface1;
  279. CfgIface cfg_iface2;
  280. cfg_iface1.use(AF_INET, "eth0");
  281. conf1.setCfgIface(cfg_iface1);
  282. EXPECT_FALSE(conf1 == conf2);
  283. EXPECT_TRUE(conf1 != conf2);
  284. cfg_iface2.use(AF_INET, "eth0");
  285. conf2.setCfgIface(cfg_iface2);
  286. EXPECT_TRUE(conf1 == conf2);
  287. EXPECT_FALSE(conf1 != conf2);
  288. // Differ by option definitions.
  289. conf1.getCfgOptionDef()->
  290. add(OptionDefinitionPtr(new OptionDefinition("option-foo", 123,
  291. "uint16_t")), "isc");
  292. EXPECT_FALSE(conf1 == conf2);
  293. EXPECT_TRUE(conf1 != conf2);
  294. conf2.getCfgOptionDef()->
  295. add(OptionDefinitionPtr(new OptionDefinition("option-foo", 123,
  296. "uint16_t")), "isc");
  297. EXPECT_TRUE(conf1 == conf2);
  298. EXPECT_FALSE(conf1 != conf2);
  299. // Differ by option data.
  300. OptionPtr option(new Option(Option::V6, 1000, OptionBuffer(1, 0xFF)));
  301. conf1.getCfgOption()->add(option, false, "isc");
  302. EXPECT_FALSE(conf1 == conf2);
  303. EXPECT_TRUE(conf1 != conf2);
  304. conf2.getCfgOption()->add(option, false, "isc");
  305. EXPECT_TRUE(conf1 == conf2);
  306. EXPECT_FALSE(conf1 != conf2);
  307. }
  308. } // end of anonymous namespace