host_unittest.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. // Copyright (C) 2014-2016 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 <dhcpsrv/host.h>
  8. #include <boost/scoped_ptr.hpp>
  9. #include <gtest/gtest.h>
  10. using namespace isc;
  11. using namespace isc::dhcp;
  12. using namespace isc::asiolink;
  13. namespace {
  14. // This test verifies that it is possible to create IPv6 address
  15. // reservation.
  16. TEST(IPv6ResrvTest, constructorAddress) {
  17. IPv6Resrv resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::cafe"));
  18. EXPECT_EQ("2001:db8:1::cafe", resrv.getPrefix().toText());
  19. EXPECT_EQ(128, resrv.getPrefixLen());
  20. EXPECT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
  21. }
  22. // This test verifies that it is possible to create IPv6 prefix
  23. // reservation.
  24. TEST(IPv6ResrvTest, constructorPrefix) {
  25. IPv6Resrv resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 64);
  26. EXPECT_EQ("2001:db8:1::", resrv.getPrefix().toText());
  27. EXPECT_EQ(64, resrv.getPrefixLen());
  28. EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType());
  29. }
  30. // This test verifies that the toText() function prints correctly.
  31. TEST(IPv6ResrvTest, toText) {
  32. IPv6Resrv resrv_prefix(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 64);
  33. EXPECT_EQ("2001:db8:1::/64", resrv_prefix.toText());
  34. IPv6Resrv resrv_address(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:111::23"));
  35. EXPECT_EQ("2001:db8:111::23", resrv_address.toText());
  36. }
  37. // This test verifies that invalid prefix is rejected.
  38. TEST(IPv6ResrvTest, constructorInvalidPrefix) {
  39. // IPv4 address is invalid for IPv6 reservation.
  40. EXPECT_THROW(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("10.0.0.1"), 128),
  41. isc::BadValue);
  42. // Multicast address is invalid for IPv6 reservation.
  43. EXPECT_THROW(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("ff02:1::2"), 128),
  44. isc::BadValue);
  45. }
  46. // This test verifies that invalid prefix length is rejected.
  47. TEST(IPv6ResrvTest, constructiorInvalidPrefixLength) {
  48. ASSERT_NO_THROW(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"),
  49. 128));
  50. EXPECT_THROW(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 129),
  51. isc::BadValue);
  52. EXPECT_THROW(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 244),
  53. isc::BadValue);
  54. EXPECT_THROW(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::"), 64),
  55. isc::BadValue);
  56. }
  57. // This test verifies that it is possible to modify prefix and its
  58. // length in an existing reservation.
  59. TEST(IPv6ResrvTest, setPrefix) {
  60. // Create a reservation using an address and prefix length 128.
  61. IPv6Resrv resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"));
  62. ASSERT_EQ("2001:db8:1::1", resrv.getPrefix().toText());
  63. ASSERT_EQ(128, resrv.getPrefixLen());
  64. ASSERT_EQ(IPv6Resrv::TYPE_NA, resrv.getType());
  65. // Modify the reservation to use a prefix having a length of 48.
  66. ASSERT_NO_THROW(resrv.set(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 48));
  67. EXPECT_EQ("2001:db8::", resrv.getPrefix().toText());
  68. EXPECT_EQ(48, resrv.getPrefixLen());
  69. EXPECT_EQ(IPv6Resrv::TYPE_PD, resrv.getType());
  70. // IPv4 address is invalid for IPv6 reservation.
  71. EXPECT_THROW(resrv.set(IPv6Resrv::TYPE_NA, IOAddress("10.0.0.1"), 128),
  72. isc::BadValue);
  73. // IPv6 multicast address is invalid for IPv6 reservation.
  74. EXPECT_THROW(resrv.set(IPv6Resrv::TYPE_NA, IOAddress("ff02::1:2"), 128),
  75. isc::BadValue);
  76. // Prefix length greater than 128 is invalid.
  77. EXPECT_THROW(resrv.set(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 129),
  78. isc::BadValue);
  79. }
  80. // This test checks that the equality operators work fine.
  81. TEST(IPv6ResrvTest, equal) {
  82. EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64) ==
  83. IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64));
  84. EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64) !=
  85. IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64));
  86. EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1")) ==
  87. IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1")));
  88. EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1")) !=
  89. IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1")));
  90. EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1")) ==
  91. IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2")));
  92. EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1")) !=
  93. IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2")));
  94. EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64) ==
  95. IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 48));
  96. EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 64) !=
  97. IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::"), 48));
  98. EXPECT_FALSE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"), 128) ==
  99. IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"), 128));
  100. EXPECT_TRUE(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::1"), 128) !=
  101. IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8::1"), 128));
  102. }
  103. // This test verfies that it is possible to create a Host object
  104. // using hardware address in the textual format.
  105. TEST(HostTest, createFromHWAddrString) {
  106. boost::scoped_ptr<Host> host;
  107. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  108. SubnetID(1), SubnetID(2),
  109. IOAddress("192.0.2.3"),
  110. "somehost.example.org")));
  111. // The HW address should be set to non-null.
  112. HWAddrPtr hwaddr = host->getHWAddress();
  113. ASSERT_TRUE(hwaddr);
  114. EXPECT_EQ("hwtype=1 01:02:03:04:05:06", hwaddr->toText());
  115. // DUID should be null if hardware address is in use.
  116. EXPECT_FALSE(host->getDuid());
  117. EXPECT_EQ(1, host->getIPv4SubnetID());
  118. EXPECT_EQ(2, host->getIPv6SubnetID());
  119. EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
  120. EXPECT_EQ("somehost.example.org", host->getHostname());
  121. // Use invalid identifier name
  122. EXPECT_THROW(Host("01:02:03:04:05:06", "bogus", SubnetID(1), SubnetID(2),
  123. IOAddress("192.0.2.3"), "somehost.example.org"),
  124. isc::BadValue);
  125. // Use invalid HW address.
  126. EXPECT_THROW(Host("010203040506", "hw-address", SubnetID(1), SubnetID(2),
  127. IOAddress("192.0.2.3"), "somehost.example.org"),
  128. isc::BadValue);
  129. }
  130. // This test verifies that it is possible to create Host object using
  131. // a DUID in the textual format.
  132. TEST(HostTest, createFromDUIDString) {
  133. boost::scoped_ptr<Host> host;
  134. ASSERT_NO_THROW(host.reset(new Host("a1:b2:c3:d4:e5:06", "duid",
  135. SubnetID(10), SubnetID(20),
  136. IOAddress("192.0.2.5"),
  137. "me.example.org")));
  138. // DUID should be set to non-null value.
  139. DuidPtr duid = host->getDuid();
  140. ASSERT_TRUE(duid);
  141. EXPECT_EQ("a1:b2:c3:d4:e5:06", duid->toText());
  142. // Hardware address must be null if DUID is in use.
  143. EXPECT_FALSE(host->getHWAddress());
  144. EXPECT_EQ(10, host->getIPv4SubnetID());
  145. EXPECT_EQ(20, host->getIPv6SubnetID());
  146. EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
  147. EXPECT_EQ("me.example.org", host->getHostname());
  148. // Use invalid DUID.
  149. EXPECT_THROW(Host("bogus", "duid", SubnetID(1), SubnetID(2),
  150. IOAddress("192.0.2.3"), "somehost.example.org"),
  151. isc::BadValue);
  152. // Empty DUID is also not allowed.
  153. EXPECT_THROW(Host("", "duid", SubnetID(1), SubnetID(2),
  154. IOAddress("192.0.2.3"), "somehost.example.org"),
  155. isc::BadValue);
  156. }
  157. // This test verifies that it is possible to create Host object using
  158. // hardware address in the binary format.
  159. TEST(HostTest, createFromHWAddrBinary) {
  160. boost::scoped_ptr<Host> host;
  161. // Prepare the hardware address in binary format.
  162. const uint8_t hwaddr_data[] = {
  163. 0xaa, 0xab, 0xca, 0xda, 0xbb, 0xee
  164. };
  165. ASSERT_NO_THROW(host.reset(new Host(hwaddr_data,
  166. sizeof(hwaddr_data),
  167. Host::IDENT_HWADDR,
  168. SubnetID(1), SubnetID(2),
  169. IOAddress("192.0.2.3"),
  170. "somehost.example.org")));
  171. // Hardware address should be non-null.
  172. HWAddrPtr hwaddr = host->getHWAddress();
  173. ASSERT_TRUE(hwaddr);
  174. EXPECT_EQ("hwtype=1 aa:ab:ca:da:bb:ee", hwaddr->toText());
  175. // DUID should be null if hardware address is in use.
  176. EXPECT_FALSE(host->getDuid());
  177. EXPECT_EQ(1, host->getIPv4SubnetID());
  178. EXPECT_EQ(2, host->getIPv6SubnetID());
  179. EXPECT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
  180. EXPECT_EQ("somehost.example.org", host->getHostname());
  181. }
  182. // This test verifies that it is possible to create a Host object using
  183. // DUID in the binary format.
  184. TEST(HostTest, createFromDuidBinary) {
  185. boost::scoped_ptr<Host> host;
  186. // Prepare DUID binary.
  187. const uint8_t duid_data[] = {
  188. 1, 2, 3, 4, 5, 6
  189. };
  190. ASSERT_NO_THROW(host.reset(new Host(duid_data,
  191. sizeof(duid_data),
  192. Host::IDENT_DUID,
  193. SubnetID(10), SubnetID(20),
  194. IOAddress("192.0.2.5"),
  195. "me.example.org")));
  196. // DUID should be non null.
  197. DuidPtr duid = host->getDuid();
  198. ASSERT_TRUE(duid);
  199. EXPECT_EQ("01:02:03:04:05:06", duid->toText());
  200. // Hardware address should be null if DUID is in use.
  201. EXPECT_FALSE(host->getHWAddress());
  202. EXPECT_EQ(10, host->getIPv4SubnetID());
  203. EXPECT_EQ(20, host->getIPv6SubnetID());
  204. EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText());
  205. EXPECT_EQ("me.example.org", host->getHostname());
  206. }
  207. // Test that it is possible to replace an identifier for a particular
  208. // Host instance (HW address -> DUID and vice versa) with a new
  209. // indentifier in the textual format.
  210. TEST(HostTest, setIdentifierString) {
  211. boost::scoped_ptr<Host> host;
  212. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  213. SubnetID(1), SubnetID(2),
  214. IOAddress("192.0.2.3"),
  215. "me.example.com")));
  216. // Initially, there should be a HW address, but not a DUID set.
  217. ASSERT_TRUE(host->getHWAddress());
  218. ASSERT_FALSE(host->getDuid());
  219. // Now, use a DUID as identifier.
  220. ASSERT_NO_THROW(host->setIdentifier("aabbccddee", "duid"));
  221. // Verify that the DUID is correct.
  222. DuidPtr duid = host->getDuid();
  223. ASSERT_TRUE(duid);
  224. EXPECT_EQ("aa:bb:cc:dd:ee", duid->toText());
  225. // HW address should be not set.
  226. EXPECT_FALSE(host->getHWAddress());
  227. // Now, let's do another way around.
  228. ASSERT_NO_THROW(host->setIdentifier("09:08:07:06:05:04", "hw-address"));
  229. // Verify that HW address is correct.
  230. HWAddrPtr hw_addr = host->getHWAddress();
  231. ASSERT_TRUE(hw_addr);
  232. EXPECT_EQ("hwtype=1 09:08:07:06:05:04", hw_addr->toText());
  233. // DUID should be not set.
  234. EXPECT_FALSE(host->getDuid());
  235. }
  236. // Test that it is possible to replace an identifier for a particular
  237. // Host instance (HW address -> DUID and vice versa) with the new
  238. // identifier in the binary format.
  239. TEST(HostTest, setIdentifierBinary) {
  240. boost::scoped_ptr<Host> host;
  241. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  242. SubnetID(1), SubnetID(2),
  243. IOAddress("192.0.2.3"),
  244. "me.example.com")));
  245. // Initially, there should be a HW address, but not a DUID set.
  246. ASSERT_TRUE(host->getHWAddress());
  247. ASSERT_FALSE(host->getDuid());
  248. // Now, use a DUID as identifier.
  249. const uint8_t duid_data[] = {
  250. 0xaa, 0xbb, 0xcc, 0xdd, 0xee
  251. };
  252. ASSERT_NO_THROW(host->setIdentifier(duid_data, sizeof(duid_data),
  253. Host::IDENT_DUID));
  254. // Verify that the DUID is correct.
  255. DuidPtr duid = host->getDuid();
  256. ASSERT_TRUE(duid);
  257. EXPECT_EQ("aa:bb:cc:dd:ee", duid->toText());
  258. // HW address should be not set.
  259. EXPECT_FALSE(host->getHWAddress());
  260. // Now, let's do another way around.
  261. const uint8_t hwaddr_data[] = {
  262. 9, 8, 7, 6, 5, 4
  263. };
  264. ASSERT_NO_THROW(host->setIdentifier(hwaddr_data, sizeof(hwaddr_data),
  265. Host::IDENT_HWADDR));
  266. // Verify that HW address is correct.
  267. HWAddrPtr hw_addr = host->getHWAddress();
  268. ASSERT_TRUE(hw_addr);
  269. EXPECT_EQ("hwtype=1 09:08:07:06:05:04", hw_addr->toText());
  270. // DUID should be not set.
  271. EXPECT_FALSE(host->getDuid());
  272. }
  273. /// @brief Checks if the reservation is in the range of reservations.
  274. ///
  275. /// @param resrv Reservation to be searched for.
  276. /// @param range Range of reservations returned by the @c Host object
  277. /// in which the reservation will be searched.
  278. bool
  279. reservationExists(const IPv6Resrv& resrv, const IPv6ResrvRange& range) {
  280. for (IPv6ResrvIterator it = range.first; it != range.second;
  281. ++it) {
  282. if (resrv == it->second) {
  283. return (true);
  284. }
  285. }
  286. return (false);
  287. }
  288. // This test verifies that the IPv6 reservations of a different type can
  289. // be added for the host.
  290. TEST(HostTest, addReservations) {
  291. boost::scoped_ptr<Host> host;
  292. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  293. SubnetID(1), SubnetID(2),
  294. IOAddress("192.0.2.3"))));
  295. EXPECT_FALSE(host->hasIPv6Reservation());
  296. // Add 4 reservations: 2 for NAs, 2 for PDs.
  297. ASSERT_NO_THROW(
  298. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  299. IOAddress("2001:db8:1::cafe")));
  300. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
  301. IOAddress("2001:db8:1:1::"), 64));
  302. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
  303. IOAddress("2001:db8:1:2::"), 64));
  304. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  305. IOAddress("2001:db8:1::1")));
  306. );
  307. EXPECT_TRUE(host->hasIPv6Reservation());
  308. // Check that reservations exist.
  309. EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  310. IOAddress("2001:db8:1::cafe"))));
  311. EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
  312. IOAddress("2001:db8:1:1::"),
  313. 64)));
  314. EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
  315. IOAddress("2001:db8:1:2::"),
  316. 64)));
  317. EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  318. IOAddress("2001:db8:1::1"))));
  319. // Get only NA reservations.
  320. IPv6ResrvRange addresses = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
  321. ASSERT_EQ(2, std::distance(addresses.first, addresses.second));
  322. EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA,
  323. IOAddress("2001:db8:1::cafe")),
  324. addresses));
  325. EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_NA,
  326. IOAddress("2001:db8:1::1")),
  327. addresses));
  328. // Get only PD reservations.
  329. IPv6ResrvRange prefixes = host->getIPv6Reservations(IPv6Resrv::TYPE_PD);
  330. ASSERT_EQ(2, std::distance(prefixes.first, prefixes.second));
  331. EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_PD,
  332. IOAddress("2001:db8:1:1::"), 64),
  333. prefixes));
  334. EXPECT_TRUE(reservationExists(IPv6Resrv(IPv6Resrv::TYPE_PD,
  335. IOAddress("2001:db8:1:2::"), 64),
  336. prefixes));
  337. }
  338. // This test checks that various modifiers may be used to replace the current
  339. // values of the Host class.
  340. TEST(HostTest, setValues) {
  341. boost::scoped_ptr<Host> host;
  342. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  343. SubnetID(1), SubnetID(2),
  344. IOAddress("192.0.2.3"),
  345. "some-host.example.org")));
  346. ASSERT_EQ(1, host->getIPv4SubnetID());
  347. ASSERT_EQ(2, host->getIPv6SubnetID());
  348. ASSERT_EQ("192.0.2.3", host->getIPv4Reservation().toText());
  349. ASSERT_EQ("some-host.example.org", host->getHostname());
  350. host->setIPv4SubnetID(SubnetID(123));
  351. host->setIPv6SubnetID(SubnetID(234));
  352. host->setIPv4Reservation(IOAddress("10.0.0.1"));
  353. host->setHostname("other-host.example.org");
  354. EXPECT_EQ(123, host->getIPv4SubnetID());
  355. EXPECT_EQ(234, host->getIPv6SubnetID());
  356. EXPECT_EQ("10.0.0.1", host->getIPv4Reservation().toText());
  357. EXPECT_EQ("other-host.example.org", host->getHostname());
  358. // Remove IPv4 reservation.
  359. host->removeIPv4Reservation();
  360. EXPECT_EQ(IOAddress::IPV4_ZERO_ADDRESS(), host->getIPv4Reservation());
  361. // An IPv6 address can't be used for IPv4 reservations.
  362. EXPECT_THROW(host->setIPv4Reservation(IOAddress("2001:db8:1::1")),
  363. isc::BadValue);
  364. // Zero address can't be set, the removeIPv4Reservation should be
  365. // used intead.
  366. EXPECT_THROW(host->setIPv4Reservation(IOAddress::IPV4_ZERO_ADDRESS()),
  367. isc::BadValue);
  368. // Broadcast address can't be set.
  369. EXPECT_THROW(host->setIPv4Reservation(IOAddress::IPV4_BCAST_ADDRESS()),
  370. isc::BadValue);
  371. }
  372. // Test that Host constructors initialize client classes from string.
  373. TEST(HostTest, clientClassesFromConstructor) {
  374. boost::scoped_ptr<Host> host;
  375. // Prepare the hardware address in binary format.
  376. const uint8_t hwaddr_data[] = {
  377. 0xaa, 0xab, 0xca, 0xda, 0xbb, 0xee
  378. };
  379. // Try the "from binary" constructor.
  380. ASSERT_NO_THROW(host.reset(new Host(hwaddr_data,
  381. sizeof(hwaddr_data),
  382. Host::IDENT_HWADDR,
  383. SubnetID(1), SubnetID(2),
  384. IOAddress("192.0.2.3"),
  385. "somehost.example.org",
  386. "alpha, , beta",
  387. "gamma")));
  388. EXPECT_TRUE(host->getClientClasses4().contains("alpha"));
  389. EXPECT_TRUE(host->getClientClasses4().contains("beta"));
  390. EXPECT_FALSE(host->getClientClasses4().contains("gamma"));
  391. EXPECT_TRUE(host->getClientClasses6().contains("gamma"));
  392. EXPECT_FALSE(host->getClientClasses6().contains("alpha"));
  393. EXPECT_FALSE(host->getClientClasses6().contains("beta"));
  394. // Try the "from string" constructor.
  395. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  396. SubnetID(1), SubnetID(2),
  397. IOAddress("192.0.2.3"),
  398. "somehost.example.org",
  399. "alpha, beta, gamma",
  400. "beta, gamma")));
  401. EXPECT_TRUE(host->getClientClasses4().contains("alpha"));
  402. EXPECT_TRUE(host->getClientClasses4().contains("beta"));
  403. EXPECT_TRUE(host->getClientClasses4().contains("gamma"));
  404. EXPECT_FALSE(host->getClientClasses6().contains("alpha"));
  405. EXPECT_TRUE(host->getClientClasses6().contains("beta"));
  406. EXPECT_TRUE(host->getClientClasses6().contains("gamma"));
  407. }
  408. // Test that new client classes can be added for the Host.
  409. TEST(HostTest, addClientClasses) {
  410. boost::scoped_ptr<Host> host;
  411. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  412. SubnetID(1), SubnetID(2),
  413. IOAddress("192.0.2.3"))));
  414. EXPECT_FALSE(host->getClientClasses4().contains("foo"));
  415. EXPECT_FALSE(host->getClientClasses6().contains("foo"));
  416. EXPECT_FALSE(host->getClientClasses4().contains("bar"));
  417. EXPECT_FALSE(host->getClientClasses6().contains("bar"));
  418. host->addClientClass4("foo");
  419. host->addClientClass6("bar");
  420. EXPECT_TRUE(host->getClientClasses4().contains("foo"));
  421. EXPECT_FALSE(host->getClientClasses6().contains("foo"));
  422. EXPECT_FALSE(host->getClientClasses4().contains("bar"));
  423. EXPECT_TRUE(host->getClientClasses6().contains("bar"));
  424. host->addClientClass4("bar");
  425. host->addClientClass6("foo");
  426. EXPECT_TRUE(host->getClientClasses4().contains("foo"));
  427. EXPECT_TRUE(host->getClientClasses6().contains("foo"));
  428. EXPECT_TRUE(host->getClientClasses4().contains("bar"));
  429. EXPECT_TRUE(host->getClientClasses6().contains("bar"));
  430. }
  431. // This test checks that it is possible to add DHCPv4 options for a host.
  432. TEST(HostTest, addOptions4) {
  433. Host host("01:02:03:04:05:06", "hw-address", SubnetID(1), SubnetID(2),
  434. IOAddress("192.0.2.3"));
  435. // Differentiate options by their codes (100-109)
  436. for (uint16_t code = 100; code < 110; ++code) {
  437. OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
  438. ASSERT_NO_THROW(host.getCfgOption4()->add(option, false, "dhcp4"));
  439. }
  440. // Add 7 options to another option space. The option codes partially overlap
  441. // with option codes that we have added to dhcp4 option space.
  442. for (uint16_t code = 105; code < 112; ++code) {
  443. OptionPtr option(new Option(Option::V4, code, OptionBuffer(10, 0xFF)));
  444. ASSERT_NO_THROW(host.getCfgOption4()->add(option, false, "isc"));
  445. }
  446. // Get options from the Subnet and check if all 10 are there.
  447. OptionContainerPtr options = host.getCfgOption4()->getAll("dhcp4");
  448. ASSERT_TRUE(options);
  449. ASSERT_EQ(10, options->size());
  450. // It should be possible to retrieve DHCPv6 options but the container
  451. // should be empty.
  452. OptionContainerPtr options6 = host.getCfgOption6()->getAll("dhcp6");
  453. ASSERT_TRUE(options6);
  454. EXPECT_TRUE(options6->empty());
  455. // Also make sure that for dhcp4 option space no DHCPv6 options are
  456. // returned. This is to check that containers for DHCPv4 and DHCPv6
  457. // options do not share information.
  458. options6 = host.getCfgOption6()->getAll("dhcp4");
  459. ASSERT_TRUE(options6);
  460. EXPECT_TRUE(options6->empty());
  461. // Validate codes of options added to dhcp4 option space.
  462. uint16_t expected_code = 100;
  463. for (OptionContainer::const_iterator option_desc = options->begin();
  464. option_desc != options->end(); ++option_desc) {
  465. ASSERT_TRUE(option_desc->option_);
  466. EXPECT_EQ(expected_code, option_desc->option_->getType());
  467. ++expected_code;
  468. }
  469. options = host.getCfgOption4()->getAll("isc");
  470. ASSERT_TRUE(options);
  471. ASSERT_EQ(7, options->size());
  472. // Validate codes of options added to isc option space.
  473. expected_code = 105;
  474. for (OptionContainer::const_iterator option_desc = options->begin();
  475. option_desc != options->end(); ++option_desc) {
  476. ASSERT_TRUE(option_desc->option_);
  477. EXPECT_EQ(expected_code, option_desc->option_->getType());
  478. ++expected_code;
  479. }
  480. // Try to get options from a non-existing option space.
  481. options = host.getCfgOption4()->getAll("abcd");
  482. ASSERT_TRUE(options);
  483. EXPECT_TRUE(options->empty());
  484. }
  485. // This test checks that it is possible to add DHCPv6 options for a host.
  486. TEST(HostTest, addOptions6) {
  487. Host host("01:02:03:04:05:06", "hw-address", SubnetID(1), SubnetID(2),
  488. IOAddress("192.0.2.3"));
  489. // Differentiate options by their codes (100-109)
  490. for (uint16_t code = 100; code < 110; ++code) {
  491. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  492. ASSERT_NO_THROW(host.getCfgOption6()->add(option, false, "dhcp6"));
  493. }
  494. // Add 7 options to another option space. The option codes partially overlap
  495. // with option codes that we have added to dhcp6 option space.
  496. for (uint16_t code = 105; code < 112; ++code) {
  497. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  498. ASSERT_NO_THROW(host.getCfgOption6()->add(option, false, "isc"));
  499. }
  500. // Get options from the Subnet and check if all 10 are there.
  501. OptionContainerPtr options = host.getCfgOption6()->getAll("dhcp6");
  502. ASSERT_TRUE(options);
  503. ASSERT_EQ(10, options->size());
  504. // It should be possible to retrieve DHCPv4 options but the container
  505. // should be empty.
  506. OptionContainerPtr options4 = host.getCfgOption4()->getAll("dhcp4");
  507. ASSERT_TRUE(options4);
  508. EXPECT_TRUE(options4->empty());
  509. // Also make sure that for dhcp6 option space no DHCPv4 options are
  510. // returned. This is to check that containers for DHCPv4 and DHCPv6
  511. // options do not share information.
  512. options4 = host.getCfgOption4()->getAll("dhcp6");
  513. ASSERT_TRUE(options4);
  514. EXPECT_TRUE(options4->empty());
  515. // Validate codes of options added to dhcp6 option space.
  516. uint16_t expected_code = 100;
  517. for (OptionContainer::const_iterator option_desc = options->begin();
  518. option_desc != options->end(); ++option_desc) {
  519. ASSERT_TRUE(option_desc->option_);
  520. EXPECT_EQ(expected_code, option_desc->option_->getType());
  521. ++expected_code;
  522. }
  523. options = host.getCfgOption6()->getAll("isc");
  524. ASSERT_TRUE(options);
  525. ASSERT_EQ(7, options->size());
  526. // Validate codes of options added to isc option space.
  527. expected_code = 105;
  528. for (OptionContainer::const_iterator option_desc = options->begin();
  529. option_desc != options->end(); ++option_desc) {
  530. ASSERT_TRUE(option_desc->option_);
  531. EXPECT_EQ(expected_code, option_desc->option_->getType());
  532. ++expected_code;
  533. }
  534. // Try to get options from a non-existing option space.
  535. options = host.getCfgOption6()->getAll("abcd");
  536. ASSERT_TRUE(options);
  537. EXPECT_TRUE(options->empty());
  538. }
  539. // This test verifies that it is possible to retrieve a textual
  540. // representation of the host identifier.
  541. TEST(HostTest, getIdentifierAsText) {
  542. Host host1("01:02:03:04:05:06", "hw-address",
  543. SubnetID(1), SubnetID(2),
  544. IOAddress("192.0.2.3"));
  545. EXPECT_EQ("hwaddr=010203040506", host1.getIdentifierAsText());
  546. Host host2("0a:0b:0c:0d:0e:0f:ab:cd:ef", "duid",
  547. SubnetID(1), SubnetID(2),
  548. IOAddress("192.0.2.3"));
  549. EXPECT_EQ("duid=0A0B0C0D0E0FABCDEF",
  550. host2.getIdentifierAsText());
  551. }
  552. // This test checks that Host object is correctly described in the
  553. // textual format using the toText method.
  554. TEST(HostTest, toText) {
  555. boost::scoped_ptr<Host> host;
  556. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  557. SubnetID(1), SubnetID(2),
  558. IOAddress("192.0.2.3"),
  559. "myhost.example.com")));
  560. // Add 4 reservations: 2 for NAs, 2 for PDs.
  561. ASSERT_NO_THROW(
  562. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  563. IOAddress("2001:db8:1::cafe")));
  564. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
  565. IOAddress("2001:db8:1:1::"), 64));
  566. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_PD,
  567. IOAddress("2001:db8:1:2::"), 64));
  568. host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA,
  569. IOAddress("2001:db8:1::1")));
  570. );
  571. // Make sure that the output is correct,
  572. EXPECT_EQ("hwaddr=010203040506 ipv4_subnet_id=1 ipv6_subnet_id=2"
  573. " hostname=myhost.example.com"
  574. " ipv4_reservation=192.0.2.3"
  575. " ipv6_reservation0=2001:db8:1::cafe"
  576. " ipv6_reservation1=2001:db8:1::1"
  577. " ipv6_reservation2=2001:db8:1:1::/64"
  578. " ipv6_reservation3=2001:db8:1:2::/64",
  579. host->toText());
  580. // Reset some of the data and make sure that the output is affected.
  581. host->setHostname("");
  582. host->removeIPv4Reservation();
  583. host->setIPv4SubnetID(0);
  584. EXPECT_EQ("hwaddr=010203040506 ipv6_subnet_id=2"
  585. " hostname=(empty) ipv4_reservation=(no)"
  586. " ipv6_reservation0=2001:db8:1::cafe"
  587. " ipv6_reservation1=2001:db8:1::1"
  588. " ipv6_reservation2=2001:db8:1:1::/64"
  589. " ipv6_reservation3=2001:db8:1:2::/64",
  590. host->toText());
  591. // Create host identified by DUID, instead of HWADDR, with a very
  592. // basic configuration.
  593. ASSERT_NO_THROW(host.reset(new Host("11:12:13:14:15", "duid",
  594. SubnetID(0), SubnetID(0),
  595. IOAddress::IPV4_ZERO_ADDRESS(),
  596. "myhost")));
  597. EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
  598. " ipv6_reservations=(none)", host->toText());
  599. // Add some classes.
  600. host->addClientClass4("modem");
  601. host->addClientClass4("router");
  602. EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
  603. " ipv6_reservations=(none)"
  604. " dhcp4_class0=modem dhcp4_class1=router",
  605. host->toText());
  606. host->addClientClass6("hub");
  607. host->addClientClass6("device");
  608. EXPECT_EQ("duid=1112131415 hostname=myhost ipv4_reservation=(no)"
  609. " ipv6_reservations=(none)"
  610. " dhcp4_class0=modem dhcp4_class1=router"
  611. " dhcp6_class0=device dhcp6_class1=hub",
  612. host->toText());
  613. }
  614. // Test verifies if the host can store HostId properly.
  615. TEST(HostTest, hostId) {
  616. boost::scoped_ptr<Host> host;
  617. ASSERT_NO_THROW(host.reset(new Host("01:02:03:04:05:06", "hw-address",
  618. SubnetID(1), SubnetID(2),
  619. IOAddress("192.0.2.3"),
  620. "myhost.example.com")));
  621. EXPECT_EQ(0, host->getHostId());
  622. EXPECT_NO_THROW(host->setHostId(12345));
  623. EXPECT_EQ(12345, host->getHostId());
  624. }
  625. } // end of anonymous namespace