srv_config_unittest.cc 13 KB

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