option_int_array_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. // Copyright (C) 2012, 2015 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_iaaddr.h>
  18. #include <dhcp/option_int_array.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 OptionIntArray test class.
  29. class OptionIntArrayTest : public ::testing::Test {
  30. public:
  31. /// @brief Constructor.
  32. ///
  33. /// Initializes the option buffer with some data.
  34. OptionIntArrayTest(): buf_(255), out_buf_(255) {
  35. for (unsigned i = 0; i < 255; i++) {
  36. buf_[i] = 255 - i;
  37. }
  38. }
  39. /// @brief Test parsing buffer into array of int8_t or uint8_t values.
  40. ///
  41. /// @warning this function does not perform type check. Make
  42. /// sure that only int8_t or uint8_t type is used.
  43. ///
  44. /// @param u universe (v4 or V6).
  45. /// @tparam T int8_t or uint8_t.
  46. template<typename T>
  47. void bufferToIntTest8(const Option::Universe u) {
  48. // Create option that conveys array of multiple uint8_t or int8_t values.
  49. // In fact there is no need to use this template class for array
  50. // of uint8_t values because Option class is sufficient - it
  51. // returns the buffer which is actually the array of uint8_t.
  52. // However, since we allow using uint8_t types with this template
  53. // class we have to test it here.
  54. boost::shared_ptr<OptionIntArray<T> > opt;
  55. const int opt_len = 10;
  56. const uint16_t opt_code = 80;
  57. // Constructor throws exception if provided buffer is empty.
  58. EXPECT_THROW(
  59. OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
  60. isc::OutOfRange
  61. );
  62. // Provided buffer is not empty so it should not throw exception.
  63. ASSERT_NO_THROW(
  64. opt = boost::shared_ptr<
  65. OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
  66. buf_.begin() + opt_len))
  67. );
  68. EXPECT_EQ(u, opt->getUniverse());
  69. EXPECT_EQ(opt_code, opt->getType());
  70. // Option should return the collection of int8_t or uint8_t values that
  71. // we can match with the buffer we used to create the option.
  72. std::vector<T> values = opt->getValues();
  73. // We need to copy values from the buffer to apply sign if signed
  74. // type is used.
  75. std::vector<T> reference_values;
  76. for (int i = 0; i < opt_len; ++i) {
  77. // Values have been read from the buffer in network
  78. // byte order. We put them back in the same order here.
  79. reference_values.push_back(static_cast<T>(buf_[i]));
  80. }
  81. // Compare the values against the reference buffer.
  82. ASSERT_EQ(opt_len, values.size());
  83. EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
  84. + opt_len, values.begin()));
  85. // test for pack()
  86. opt->pack(out_buf_);
  87. // Data length is 10 bytes.
  88. EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
  89. EXPECT_EQ(opt_code, opt->getType());
  90. // Check if pack worked properly:
  91. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  92. if (u == Option::V4) {
  93. // The total length is 10 bytes for data and 2 bytes for a header.
  94. ASSERT_EQ(12, out_buf_.getLength());
  95. // if option type is correct
  96. EXPECT_EQ(opt_code, out.readUint8());
  97. // if option length is correct
  98. EXPECT_EQ(10, out.readUint8());
  99. } else {
  100. // The total length is 10 bytes for data and 4 bytes for a header.
  101. ASSERT_EQ(14, out_buf_.getLength());
  102. // if option type is correct
  103. EXPECT_EQ(opt_code, out.readUint16());
  104. // if option length is correct
  105. EXPECT_EQ(10, out.readUint16());
  106. }
  107. // if data is correct
  108. std::vector<uint8_t> out_data;
  109. ASSERT_NO_THROW(out.readVector(out_data, opt_len));
  110. ASSERT_EQ(opt_len, out_data.size());
  111. EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
  112. }
  113. /// @brief Test parsing buffer into array of int16_t or uint16_t values.
  114. ///
  115. /// @warning this function does not perform type check. Make
  116. /// sure that only int16_t or uint16_t type is used.
  117. ///
  118. /// @param u universe (V4 or V6).
  119. /// @tparam T int16_t or uint16_t.
  120. template<typename T>
  121. void bufferToIntTest16(const Option::Universe u) {
  122. // Create option that conveys array of multiple uint16_t or int16_t values.
  123. boost::shared_ptr<OptionIntArray<T> > opt;
  124. const int opt_len = 20;
  125. const uint16_t opt_code = 81;
  126. // Constructor throws exception if provided buffer is empty.
  127. EXPECT_THROW(
  128. OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
  129. isc::OutOfRange
  130. );
  131. // Constructor throws exception if provided buffer's length is not
  132. // multiple of 2-bytes.
  133. EXPECT_THROW(
  134. OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 5),
  135. isc::OutOfRange
  136. );
  137. // Now the buffer length is correct.
  138. ASSERT_NO_THROW(
  139. opt = boost::shared_ptr<
  140. OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
  141. buf_.begin() + opt_len))
  142. );
  143. EXPECT_EQ(u, opt->getUniverse());
  144. EXPECT_EQ(opt_code, opt->getType());
  145. // Option should return vector of uint16_t values which should be
  146. // constructed from the buffer we provided.
  147. std::vector<T> values = opt->getValues();
  148. ASSERT_EQ(opt_len, values.size() * sizeof(T));
  149. // Create reference values from the buffer so as we can
  150. // simply compare two vectors.
  151. std::vector<T> reference_values;
  152. for (int i = 0; i < opt_len; i += 2) {
  153. reference_values.push_back((buf_[i] << 8) |
  154. buf_[i + 1]);
  155. }
  156. EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
  157. values.begin()));
  158. // Test for pack()
  159. opt->pack(out_buf_);
  160. // Data length is 20 bytes.
  161. EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
  162. EXPECT_EQ(opt_code, opt->getType());
  163. // Check if pack worked properly:
  164. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  165. if (u == Option::V4) {
  166. // The total length is 20 bytes for data and 2 bytes for a header.
  167. ASSERT_EQ(22, out_buf_.getLength());
  168. // if option type is correct
  169. EXPECT_EQ(opt_code, out.readUint8());
  170. // if option length is correct
  171. EXPECT_EQ(20, out.readUint8());
  172. } else {
  173. // The total length is 20 bytes for data and 4 bytes for a header.
  174. ASSERT_EQ(24, out_buf_.getLength());
  175. // if option type is correct
  176. EXPECT_EQ(opt_code, out.readUint16());
  177. // if option length is correct
  178. EXPECT_EQ(20, out.readUint16());
  179. }
  180. // if data is correct
  181. std::vector<uint8_t> out_data;
  182. ASSERT_NO_THROW(out.readVector(out_data, opt_len));
  183. ASSERT_EQ(opt_len, out_data.size());
  184. EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
  185. }
  186. /// @brief Test parsing buffer into array of int32_t or uint32_t values.
  187. ///
  188. /// @warning this function does not perform type check. Make
  189. /// sure that only int32_t or uint32_t type is used.
  190. ///
  191. /// @param u universe (V4 or V6)
  192. /// @tparam T int32_t or uint32_t.
  193. template<typename T>
  194. void bufferToIntTest32(const Option::Universe u) {
  195. // Create option that conveys array of multiple uint16_t values.
  196. boost::shared_ptr<OptionIntArray<T> > opt;
  197. const int opt_len = 40;
  198. const uint16_t opt_code = 82;
  199. // Constructor throws exception if provided buffer is empty.
  200. EXPECT_THROW(
  201. OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
  202. isc::OutOfRange
  203. );
  204. // Constructor throws exception if provided buffer's length is not
  205. // multiple of 4-bytes.
  206. EXPECT_THROW(
  207. OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 9),
  208. isc::OutOfRange
  209. );
  210. // Now the buffer length is correct.
  211. ASSERT_NO_THROW(
  212. opt = boost::shared_ptr<
  213. OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
  214. buf_.begin() + opt_len))
  215. );
  216. EXPECT_EQ(u, opt->getUniverse());
  217. EXPECT_EQ(opt_code, opt->getType());
  218. // Option should return vector of uint32_t values which should be
  219. // constructed from the buffer we provided.
  220. std::vector<T> values = opt->getValues();
  221. ASSERT_EQ(opt_len, values.size() * sizeof(T));
  222. // Create reference values from the buffer so as we can
  223. // simply compare two vectors.
  224. std::vector<T> reference_values;
  225. for (int i = 0; i < opt_len; i += 4) {
  226. reference_values.push_back((buf_[i] << 24) |
  227. (buf_[i + 1] << 16 & 0x00FF0000) |
  228. (buf_[i + 2] << 8 & 0xFF00) |
  229. (buf_[i + 3] & 0xFF));
  230. }
  231. EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
  232. values.begin()));
  233. // Test for pack()
  234. opt->pack(out_buf_);
  235. // Data length is 40 bytes.
  236. EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
  237. EXPECT_EQ(opt_code, opt->getType());
  238. // Check if pack worked properly:
  239. InputBuffer out(out_buf_.getData(), out_buf_.getLength());
  240. if (u == Option::V4) {
  241. // The total length is 40 bytes for data and 2 bytes for a header.
  242. ASSERT_EQ(42, out_buf_.getLength());
  243. // if option type is correct
  244. EXPECT_EQ(opt_code, out.readUint8());
  245. // if option length is correct
  246. EXPECT_EQ(40, out.readUint8());
  247. } else {
  248. // The total length is 40 bytes for data and 4 bytes for a header.
  249. ASSERT_EQ(44, out_buf_.getLength());
  250. // if option type is correct
  251. EXPECT_EQ(opt_code, out.readUint16());
  252. // if option length is correct
  253. EXPECT_EQ(40, out.readUint16());
  254. }
  255. // if data is correct
  256. std::vector<uint8_t> out_data;
  257. ASSERT_NO_THROW(out.readVector(out_data, opt_len));
  258. ASSERT_EQ(opt_len, out_data.size());
  259. EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
  260. }
  261. /// @brief Test ability to set all values.
  262. ///
  263. /// @tparam T numeric type to perform the test for.
  264. template<typename T>
  265. void setValuesTest() {
  266. const uint16_t opt_code = 100;
  267. // Create option with empty vector of values.
  268. boost::shared_ptr<OptionIntArray<T> >
  269. opt(new OptionIntArray<T>(Option::V6, opt_code));
  270. // Initialize vector with some data and pass to the option.
  271. std::vector<T> values;
  272. for (int i = 0; i < 10; ++i) {
  273. values.push_back(numeric_limits<uint8_t>::max() - i);
  274. }
  275. opt->setValues(values);
  276. // Check if universe, option type and data was set correctly.
  277. EXPECT_EQ(Option::V6, opt->getUniverse());
  278. EXPECT_EQ(opt_code, opt->getType());
  279. std::vector<T> returned_values = opt->getValues();
  280. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  281. }
  282. /// @brief Test ability to add values one by one.
  283. ///
  284. /// @tparam T numeric type to perform the test for.
  285. template<typename T>
  286. void addValuesTest() {
  287. const uint16_t opt_code = 100;
  288. // Create option with empty vector of values.
  289. boost::shared_ptr<OptionIntArray<T> >
  290. opt(new OptionIntArray<T>(Option::V6, opt_code));
  291. // Initialize vector with some data and add the same data
  292. // to the option.
  293. std::vector<T> values;
  294. for (int i = 0; i < 10; ++i) {
  295. values.push_back(numeric_limits<T>::max() - i);
  296. opt->addValue(numeric_limits<T>::max() - i);
  297. }
  298. // Check if universe, option type and data was set correctly.
  299. EXPECT_EQ(Option::V6, opt->getUniverse());
  300. EXPECT_EQ(opt_code, opt->getType());
  301. std::vector<T> returned_values = opt->getValues();
  302. EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
  303. }
  304. OptionBuffer buf_; ///< Option buffer
  305. OutputBuffer out_buf_; ///< Output buffer
  306. };
  307. /// @todo: below, there is a bunch of tests for options that
  308. /// convey unsigned values. We should maybe extend these tests for
  309. /// signed types too.
  310. TEST_F(OptionIntArrayTest, useInvalidType) {
  311. const uint16_t opt_code = 80;
  312. EXPECT_THROW(
  313. boost::scoped_ptr<
  314. OptionIntArray<bool> >(new OptionIntArray<bool>(Option::V6, opt_code,
  315. OptionBuffer(5))),
  316. InvalidDataType
  317. );
  318. EXPECT_THROW(
  319. boost::scoped_ptr<
  320. OptionIntArray<int64_t> >(new OptionIntArray<int64_t>(Option::V6,
  321. opt_code,
  322. OptionBuffer(10))),
  323. InvalidDataType
  324. );
  325. }
  326. TEST_F(OptionIntArrayTest, bufferToUint8V4) {
  327. bufferToIntTest8<uint8_t>(Option::V4);
  328. }
  329. TEST_F(OptionIntArrayTest, bufferToUint8V6) {
  330. bufferToIntTest8<uint8_t>(Option::V6);
  331. }
  332. TEST_F(OptionIntArrayTest, bufferToInt8V4) {
  333. bufferToIntTest8<int8_t>(Option::V4);
  334. }
  335. TEST_F(OptionIntArrayTest, bufferToInt8V6) {
  336. bufferToIntTest8<int8_t>(Option::V6);
  337. }
  338. TEST_F(OptionIntArrayTest, bufferToUint16V4) {
  339. bufferToIntTest16<uint16_t>(Option::V4);
  340. }
  341. TEST_F(OptionIntArrayTest, bufferToUint16V6) {
  342. bufferToIntTest16<uint16_t>(Option::V6);
  343. }
  344. TEST_F(OptionIntArrayTest, bufferToInt16V4) {
  345. bufferToIntTest16<int16_t>(Option::V4);
  346. }
  347. TEST_F(OptionIntArrayTest, bufferToInt16V6) {
  348. bufferToIntTest16<int16_t>(Option::V6);
  349. }
  350. TEST_F(OptionIntArrayTest, bufferToUint32V4) {
  351. bufferToIntTest32<uint32_t>(Option::V4);
  352. }
  353. TEST_F(OptionIntArrayTest, bufferToUint32V6) {
  354. bufferToIntTest32<uint32_t>(Option::V6);
  355. }
  356. TEST_F(OptionIntArrayTest, bufferToInt32V4) {
  357. bufferToIntTest32<int32_t>(Option::V4);
  358. }
  359. TEST_F(OptionIntArrayTest, bufferToInt32V6) {
  360. bufferToIntTest32<int32_t>(Option::V6);
  361. }
  362. TEST_F(OptionIntArrayTest, setValuesUint8) {
  363. setValuesTest<uint8_t>();
  364. }
  365. TEST_F(OptionIntArrayTest, setValuesInt8) {
  366. setValuesTest<int8_t>();
  367. }
  368. TEST_F(OptionIntArrayTest, setValuesUint16) {
  369. setValuesTest<uint16_t>();
  370. }
  371. TEST_F(OptionIntArrayTest, setValuesInt16) {
  372. setValuesTest<int16_t>();
  373. }
  374. TEST_F(OptionIntArrayTest, setValuesUint32) {
  375. setValuesTest<uint16_t>();
  376. }
  377. TEST_F(OptionIntArrayTest, setValuesInt32) {
  378. setValuesTest<int16_t>();
  379. }
  380. TEST_F(OptionIntArrayTest, addValuesUint8) {
  381. addValuesTest<uint8_t>();
  382. }
  383. TEST_F(OptionIntArrayTest, addValuesInt8) {
  384. addValuesTest<int8_t>();
  385. }
  386. TEST_F(OptionIntArrayTest, addValuesUint16) {
  387. addValuesTest<uint16_t>();
  388. }
  389. TEST_F(OptionIntArrayTest, addValuesInt16) {
  390. addValuesTest<int16_t>();
  391. }
  392. TEST_F(OptionIntArrayTest, addValuesUint32) {
  393. addValuesTest<uint16_t>();
  394. }
  395. TEST_F(OptionIntArrayTest, addValuesInt32) {
  396. addValuesTest<int16_t>();
  397. }
  398. // This test checks that the option is correctly converted into
  399. // the textual format.
  400. TEST_F(OptionIntArrayTest, toText) {
  401. OptionUint32Array option(Option::V4, 128);
  402. option.addValue(1);
  403. option.addValue(32);
  404. option.addValue(324);
  405. EXPECT_EQ("type=128, len=012: 1(uint32) 32(uint32) 324(uint32)",
  406. option.toText());
  407. }
  408. // This test checks that the option holding multiple uint8 values
  409. // is correctly converted to the textual format.
  410. TEST_F(OptionIntArrayTest, toTextUint8) {
  411. OptionUint8Array option(Option::V4, 128);
  412. option.addValue(1);
  413. option.addValue(7);
  414. option.addValue(15);
  415. EXPECT_EQ("type=128, len=003: 1(uint8) 7(uint8) 15(uint8)",
  416. option.toText());
  417. }
  418. } // anonymous namespace