option6_int_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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 <dhcp/dhcp6.h>
  16. #include <dhcp/option.h>
  17. #include <dhcp/option6_int.h>
  18. #include <dhcp/option6_iaaddr.h>
  19. #include <util/buffer.h>
  20. #include <boost/pointer_cast.hpp>
  21. #include <gtest/gtest.h>
  22. using namespace std;
  23. using namespace isc;
  24. using namespace isc::dhcp;
  25. using namespace isc::asiolink;
  26. using namespace isc::util;
  27. namespace {
  28. /// @brief Option6Int test class.
  29. class Option6IntTest : public ::testing::Test {
  30. public:
  31. /// @brief Constructor.
  32. ///
  33. /// Initializes the option buffer with some data.
  34. Option6IntTest(): buf_(255), out_buf_(255) {
  35. for (int i = 0; i < 255; i++) {
  36. buf_[i] = 255 - i;
  37. }
  38. }
  39. /// @brief Basic test for int8 and uint8 types.
  40. ///
  41. /// @note this function does not perform type check. Make
  42. /// sure that only int8_t or uint8_t type is used.
  43. ///
  44. /// @tparam T int8_t or uint8_t.
  45. template<typename T>
  46. void basicTest8() {
  47. // Create option that conveys single 8 bit integer value.
  48. boost::shared_ptr<Option6Int<T> > opt;
  49. // Initialize buffer with this value.
  50. buf_[0] = 0xa1;
  51. // Constructor may throw in case provided buffer is too short.
  52. ASSERT_NO_THROW(
  53. opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_PREFERENCE,
  54. buf_.begin(),
  55. buf_.end()))
  56. );
  57. EXPECT_EQ(Option::V6, opt->getUniverse());
  58. EXPECT_EQ(D6O_PREFERENCE, opt->getType());
  59. // Option should return the same value that we initialized the first
  60. // byte of the buffer with.
  61. EXPECT_EQ(static_cast<T>(0xa1), opt->getValue());
  62. // test for pack()
  63. opt->pack(out_buf_);
  64. // Data length is 1 byte.
  65. EXPECT_EQ(1, opt->len() - opt->getHeaderLen());
  66. EXPECT_EQ(D6O_PREFERENCE, opt->getType());
  67. // The total length is 1 byte for data and 4 bytes for header.
  68. EXPECT_EQ(5, out_buf_.getLength());
  69. // Check if pack worked properly:
  70. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  71. // if option type is correct
  72. EXPECT_EQ(D6O_PREFERENCE, out.readUint16());
  73. // if option length is correct
  74. EXPECT_EQ(1, out.readUint16());
  75. // if data is correct
  76. EXPECT_EQ(0xa1, out.readUint8() );
  77. }
  78. /// @brief Basic test for int16 and uint16 types.
  79. ///
  80. /// @note this function does not perform type check. Make
  81. /// sure that only int16_t or uint16_t type is used.
  82. ///
  83. /// @tparam T int16_t or uint16_t.
  84. template<typename T>
  85. void basicTest16() {
  86. // Create option that conveys single 16-bit integer value.
  87. boost::shared_ptr<Option6Int<T> > opt;
  88. // Initialize buffer with uint16_t value.
  89. buf_[0] = 0xa1;
  90. buf_[1] = 0xa2;
  91. // Constructor may throw in case provided buffer is too short.
  92. ASSERT_NO_THROW(
  93. opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_ELAPSED_TIME,
  94. buf_.begin(),
  95. buf_.end()))
  96. );
  97. EXPECT_EQ(Option::V6, opt->getUniverse());
  98. EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
  99. // Option should return the value equal to the contents of first
  100. // and second byte of the buffer.
  101. EXPECT_EQ(static_cast<T>(0xa1a2), opt->getValue());
  102. // Test for pack()
  103. opt->pack(out_buf_);
  104. // Data length is 2 bytes.
  105. EXPECT_EQ(2, opt->len() - opt->getHeaderLen());
  106. EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
  107. // The total length is 2 byte for data and 4 bytes for header.
  108. EXPECT_EQ(6, out_buf_.getLength());
  109. // Check if pack worked properly:
  110. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  111. // if option type is correct
  112. EXPECT_EQ(D6O_ELAPSED_TIME, out.readUint16());
  113. // if option length is correct
  114. EXPECT_EQ(2, out.readUint16());
  115. // if data is correct
  116. EXPECT_EQ(0xa1a2, out.readUint16() );
  117. }
  118. /// @brief Basic test for int32 and uint32 types.
  119. ///
  120. /// @note this function does not perform type check. Make
  121. /// sure that only int32_t or uint32_t type is used.
  122. ///
  123. /// @tparam T int32_t or uint32_t.
  124. template<typename T>
  125. void basicTest32() {
  126. // Create option that conveys single 32-bit integer value.
  127. boost::shared_ptr<Option6Int<T> > opt;
  128. // Initialize buffer with 32-bit integer value.
  129. buf_[0] = 0xa1;
  130. buf_[1] = 0xa2;
  131. buf_[2] = 0xa3;
  132. buf_[3] = 0xa4;
  133. // Constructor may throw in case provided buffer is too short.
  134. ASSERT_NO_THROW(
  135. opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_CLT_TIME,
  136. buf_.begin(),
  137. buf_.end()))
  138. );
  139. EXPECT_EQ(Option::V6, opt->getUniverse());
  140. EXPECT_EQ(D6O_CLT_TIME, opt->getType());
  141. // Option should return the value equal to the value made of
  142. // first 4 bytes of the buffer.
  143. EXPECT_EQ(static_cast<T>(0xa1a2a3a4), opt->getValue());
  144. // Test for pack()
  145. opt->pack(out_buf_);
  146. // Data length is 4 bytes.
  147. EXPECT_EQ(4, opt->len() - opt->getHeaderLen());
  148. EXPECT_EQ(D6O_CLT_TIME, opt->getType());
  149. // The total length is 4 bytes for data and 4 bytes for header.
  150. EXPECT_EQ(8, out_buf_.getLength());
  151. // Check if pack worked properly:
  152. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  153. // if option type is correct
  154. EXPECT_EQ(D6O_CLT_TIME, out.readUint16());
  155. // if option length is correct
  156. EXPECT_EQ(4, out.readUint16());
  157. // if data is correct
  158. EXPECT_EQ(0xa1a2a3a4, out.readUint32());
  159. }
  160. OptionBuffer buf_; ///< Option buffer
  161. OutputBuffer out_buf_; ///< Output buffer
  162. };
  163. /// @todo: below, there is a bunch of tests for options that
  164. /// convey unsigned value. We should maybe extend these tests for
  165. /// signed types too.
  166. TEST_F(Option6IntTest, useInvalidType) {
  167. EXPECT_THROW(
  168. boost::scoped_ptr<Option6Int<bool> >(new Option6Int<bool>(D6O_ELAPSED_TIME, 10)),
  169. InvalidDataType
  170. );
  171. EXPECT_THROW(
  172. boost::scoped_ptr<Option6Int<int64_t> >(new Option6Int<int64_t>(D6O_ELAPSED_TIME, 10)),
  173. InvalidDataType
  174. );
  175. }
  176. TEST_F(Option6IntTest, basicUint8) {
  177. basicTest8<uint8_t>();
  178. }
  179. TEST_F(Option6IntTest, basicUint16) {
  180. basicTest16<uint16_t>();
  181. }
  182. TEST_F(Option6IntTest, basicUint32) {
  183. basicTest32<uint32_t>();
  184. }
  185. TEST_F(Option6IntTest, basicInt8) {
  186. basicTest8<int8_t>();
  187. }
  188. TEST_F(Option6IntTest, basicInt16) {
  189. basicTest16<int16_t>();
  190. }
  191. TEST_F(Option6IntTest, basicInt32) {
  192. basicTest32<int32_t>();
  193. }
  194. TEST_F(Option6IntTest, setValueUint8) {
  195. boost::shared_ptr<Option6Int<uint8_t> > opt(new Option6Int<uint8_t>(D6O_PREFERENCE, 123));
  196. // Check if constructor intitialized the option value correctly.
  197. EXPECT_EQ(123, opt->getValue());
  198. // Override the value.
  199. opt->setValue(111);
  200. EXPECT_EQ(Option::V6, opt->getUniverse());
  201. EXPECT_EQ(D6O_PREFERENCE, opt->getType());
  202. // Check if the value has been overriden.
  203. EXPECT_EQ(111, opt->getValue());
  204. }
  205. TEST_F(Option6IntTest, setValueInt8) {
  206. boost::shared_ptr<Option6Int<int8_t> > opt(new Option6Int<int8_t>(D6O_PREFERENCE, -123));
  207. // Check if constructor intitialized the option value correctly.
  208. EXPECT_EQ(-123, opt->getValue());
  209. // Override the value.
  210. opt->setValue(-111);
  211. EXPECT_EQ(Option::V6, opt->getUniverse());
  212. EXPECT_EQ(D6O_PREFERENCE, opt->getType());
  213. // Check if the value has been overriden.
  214. EXPECT_EQ(-111, opt->getValue());
  215. }
  216. TEST_F(Option6IntTest, setValueUint16) {
  217. boost::shared_ptr<Option6Int<uint16_t> > opt(new Option6Int<uint16_t>(D6O_ELAPSED_TIME, 123));
  218. // Check if constructor intitialized the option value correctly.
  219. EXPECT_EQ(123, opt->getValue());
  220. // Override the value.
  221. opt->setValue(0x0102);
  222. EXPECT_EQ(Option::V6, opt->getUniverse());
  223. EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
  224. // Check if the value has been overriden.
  225. EXPECT_EQ(0x0102, opt->getValue());
  226. }
  227. TEST_F(Option6IntTest, setValueInt16) {
  228. boost::shared_ptr<Option6Int<int16_t> > opt(new Option6Int<int16_t>(D6O_ELAPSED_TIME, -16500));
  229. // Check if constructor intitialized the option value correctly.
  230. EXPECT_EQ(-16500, opt->getValue());
  231. // Override the value.
  232. opt->setValue(-20100);
  233. EXPECT_EQ(Option::V6, opt->getUniverse());
  234. EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
  235. // Check if the value has been overriden.
  236. EXPECT_EQ(-20100, opt->getValue());
  237. }
  238. TEST_F(Option6IntTest, setValueUint32) {
  239. boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(D6O_CLT_TIME, 123));
  240. // Check if constructor intitialized the option value correctly.
  241. EXPECT_EQ(123, opt->getValue());
  242. // Override the value.
  243. opt->setValue(0x01020304);
  244. EXPECT_EQ(Option::V6, opt->getUniverse());
  245. EXPECT_EQ(D6O_CLT_TIME, opt->getType());
  246. // Check if the value has been overriden.
  247. EXPECT_EQ(0x01020304, opt->getValue());
  248. }
  249. TEST_F(Option6IntTest, setValueint32) {
  250. boost::shared_ptr<Option6Int<int32_t> > opt(new Option6Int<int32_t>(D6O_CLT_TIME, -120100));
  251. // Check if constructor intitialized the option value correctly.
  252. EXPECT_EQ(-120100, opt->getValue());
  253. // Override the value.
  254. opt->setValue(-125000);
  255. EXPECT_EQ(Option::V6, opt->getUniverse());
  256. EXPECT_EQ(D6O_CLT_TIME, opt->getType());
  257. // Check if the value has been overriden.
  258. EXPECT_EQ(-125000, opt->getValue());
  259. }
  260. TEST_F(Option6IntTest, packSuboptions) {
  261. // option code is really uint16_t, but using uint8_t
  262. // for easier conversion to uint8_t array.
  263. uint8_t opt_code = 80;
  264. boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(opt_code, 0x01020304));
  265. OptionPtr sub1(new Option(Option::V6, 0xcafe));
  266. boost::shared_ptr<Option6IAAddr> addr1(
  267. new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000));
  268. opt->addOption(sub1);
  269. opt->addOption(addr1);
  270. ASSERT_EQ(28, addr1->len());
  271. ASSERT_EQ(4, sub1->len());
  272. ASSERT_EQ(40, opt->len());
  273. uint8_t expected[] = {
  274. 0, opt_code, // type
  275. 0, 36, // length
  276. 0x01, 0x02, 0x03, 0x04, // uint32_t value
  277. // iaaddr suboption
  278. D6O_IAADDR / 256, D6O_IAADDR % 256, // type
  279. 0, 24, // len
  280. 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
  281. 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
  282. 0, 0, 0x50, 0, // preferred-lifetime
  283. 0, 0, 0x70, 0, // valid-lifetime
  284. // suboption
  285. 0xca, 0xfe, // type
  286. 0, 0 // len
  287. };
  288. // Create on-wire format of option and suboptions.
  289. opt->pack(out_buf_);
  290. // Compare the on-wire data with the reference buffer.
  291. ASSERT_EQ(40, out_buf_.getLength());
  292. EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40));
  293. }
  294. TEST_F(Option6IntTest, unpackSuboptions) {
  295. // option code is really uint16_t, but using uint8_t
  296. // for easier conversion to uint8_t array.
  297. const uint8_t opt_code = 80;
  298. // Prepare reference data.
  299. uint8_t expected[] = {
  300. 0, opt_code, // type
  301. 0, 34, // length
  302. 0x01, 0x02, // uint16_t value
  303. // iaaddr suboption
  304. D6O_IAADDR / 256, D6O_IAADDR % 256, // type
  305. 0, 24, // len
  306. 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
  307. 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
  308. 0, 0, 0x50, 0, // preferred-lifetime
  309. 0, 0, 0x70, 0, // valid-lifetime
  310. // suboption
  311. 0xca, 0xfe, // type
  312. 0, 0 // len
  313. };
  314. ASSERT_EQ(38, sizeof(expected));
  315. memcpy(&buf_[0], expected, sizeof(expected));
  316. boost::shared_ptr<Option6Int<uint16_t> > opt;
  317. EXPECT_NO_THROW(
  318. opt = boost::shared_ptr<
  319. Option6Int<uint16_t> >(new Option6Int<uint16_t>(opt_code, buf_.begin() + 4,
  320. buf_.begin() + sizeof(expected)));
  321. );
  322. ASSERT_TRUE(opt);
  323. EXPECT_EQ(opt_code, opt->getType());
  324. EXPECT_EQ(0x0102, opt->getValue());
  325. // Checks for address option
  326. OptionPtr subopt = opt->getOption(D6O_IAADDR);
  327. ASSERT_TRUE(subopt);
  328. boost::shared_ptr<Option6IAAddr> addr(boost::dynamic_pointer_cast<Option6IAAddr>(subopt));
  329. ASSERT_TRUE(addr);
  330. EXPECT_EQ(D6O_IAADDR, addr->getType());
  331. EXPECT_EQ(28, addr->len());
  332. EXPECT_EQ(0x5000, addr->getPreferred());
  333. EXPECT_EQ(0x7000, addr->getValid());
  334. EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText());
  335. // Checks for dummy option
  336. subopt = opt->getOption(0xcafe);
  337. ASSERT_TRUE(subopt); // should be non-NULL
  338. EXPECT_EQ(0xcafe, subopt->getType());
  339. EXPECT_EQ(4, subopt->len());
  340. // There should be no data at all
  341. EXPECT_EQ(0, subopt->getData().size());
  342. // Try to get non-existent option.
  343. subopt = opt->getOption(1);
  344. // Expecting NULL which means that option does not exist.
  345. ASSERT_FALSE(subopt);
  346. }
  347. } // anonymous namespace