option_definition_unittest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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 <exceptions/exceptions.h>
  16. #include <asiolink/io_address.h>
  17. #include <dhcp/dhcp4.h>
  18. #include <dhcp/dhcp6.h>
  19. #include <dhcp/option4_addrlst.h>
  20. #include <dhcp/option6_addrlst.h>
  21. #include <dhcp/option6_ia.h>
  22. #include <dhcp/option6_iaaddr.h>
  23. #include <dhcp/option6_int.h>
  24. #include <dhcp/option6_int_array.h>
  25. #include <dhcp/option_definition.h>
  26. #include <gtest/gtest.h>
  27. #include <boost/shared_ptr.hpp>
  28. #include <boost/pointer_cast.hpp>
  29. using namespace std;
  30. using namespace isc;
  31. using namespace isc::dhcp;
  32. using namespace isc::util;
  33. namespace {
  34. /// @brief OptionDefinition test class.
  35. ///
  36. /// This class does not do anything useful but we keep
  37. /// it around for the future.
  38. class OptionDefinitionTest : public ::testing::Test {
  39. public:
  40. // @brief Constructor.
  41. OptionDefinitionTest() { }
  42. };
  43. TEST_F(OptionDefinitionTest, constructor) {
  44. // Specify the option data type as string. This should get converted
  45. // to enum value returned by getType().
  46. OptionDefinition opt_def1("OPTION_CLIENTID", 1, "string");
  47. EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
  48. EXPECT_EQ(1, opt_def1.getCode());
  49. EXPECT_EQ(OptionDefinition::STRING_TYPE, opt_def1.getType());
  50. EXPECT_FALSE(opt_def1.getArrayType());
  51. EXPECT_NO_THROW(opt_def1.validate());
  52. // Specify the option data type as an enum value.
  53. OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
  54. OptionDefinition::EMPTY_TYPE);
  55. EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
  56. EXPECT_EQ(14, opt_def2.getCode());
  57. EXPECT_EQ(OptionDefinition::EMPTY_TYPE, opt_def2.getType());
  58. EXPECT_FALSE(opt_def2.getArrayType());
  59. EXPECT_NO_THROW(opt_def1.validate());
  60. // Check if it is possible to set that option is an array.
  61. OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
  62. OptionDefinition::IPV6_ADDRESS_TYPE,
  63. true);
  64. EXPECT_EQ("OPTION_NIS_SERVERS", opt_def3.getName());
  65. EXPECT_EQ(27, opt_def3.getCode());
  66. EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, opt_def3.getType());
  67. EXPECT_TRUE(opt_def3.getArrayType());
  68. EXPECT_NO_THROW(opt_def3.validate());
  69. // The created object is invalid if invalid data type is specified but
  70. // constructor shouldn't throw exception. The object is validated after
  71. // it has been created.
  72. EXPECT_NO_THROW(
  73. OptionDefinition opt_def4("OPTION_SERVERID",
  74. OptionDefinition::UNKNOWN_TYPE + 10,
  75. OptionDefinition::STRING_TYPE);
  76. );
  77. }
  78. TEST_F(OptionDefinitionTest, addRecordField) {
  79. // We can only add fields to record if the option type has been
  80. // specified as 'record'. We try all other types but 'record'
  81. // here and expect exception to be thrown.
  82. for (int i = 0; i < OptionDefinition::UNKNOWN_TYPE; ++i) {
  83. // Do not try for 'record' type because this is the only
  84. // type for which adding record will succeed.
  85. if (i == OptionDefinition::RECORD_TYPE) {
  86. continue;
  87. }
  88. OptionDefinition opt_def("OPTION_IAADDR", 5,
  89. static_cast<OptionDefinition::DataType>(i));
  90. EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
  91. }
  92. // Positive scenario starts here.
  93. OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
  94. EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  95. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  96. // It should not matter if we specify field type by its name or using enum.
  97. EXPECT_NO_THROW(opt_def.addRecordField(OptionDefinition::UINT32_TYPE));
  98. // Check what we have actually added.
  99. OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
  100. ASSERT_EQ(3, fields.size());
  101. EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, fields[0]);
  102. EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[1]);
  103. EXPECT_EQ(OptionDefinition::UINT32_TYPE, fields[2]);
  104. // Let's try some more negative scenarios: use invalid data types.
  105. EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
  106. OptionDefinition::DataType invalid_type =
  107. static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE + 10);
  108. EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
  109. }
  110. TEST_F(OptionDefinitionTest, validate) {
  111. // Not supported option type string is not allowed.
  112. OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
  113. EXPECT_THROW(opt_def1.validate(), isc::OutOfRange);
  114. // Not supported option type enum value is not allowed.
  115. OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OptionDefinition::UNKNOWN_TYPE);
  116. EXPECT_THROW(opt_def2.validate(), isc::OutOfRange);
  117. OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
  118. static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE
  119. + 2));
  120. EXPECT_THROW(opt_def3.validate(), isc::OutOfRange);
  121. // Empty option name is not allowed.
  122. OptionDefinition opt_def4("", D6O_CLIENTID, "string");
  123. EXPECT_THROW(opt_def4.validate(), isc::BadValue);
  124. // Option name must not contain spaces.
  125. OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
  126. EXPECT_THROW(opt_def5.validate(), isc::BadValue);
  127. OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string");
  128. EXPECT_THROW(opt_def6.validate(), isc::BadValue);
  129. }
  130. TEST_F(OptionDefinitionTest, factoryAddrList6) {
  131. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  132. "ipv6-address", true);
  133. Option::Factory* factory(NULL);
  134. EXPECT_NO_THROW(factory = opt_def.getFactory());
  135. ASSERT_TRUE(factory != NULL);
  136. // Create a list of some V6 addresses.
  137. std::vector<asiolink::IOAddress> addrs;
  138. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  139. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  140. addrs.push_back(asiolink::IOAddress("::1"));
  141. addrs.push_back(asiolink::IOAddress("::2"));
  142. // Write addresses to the buffer.
  143. OptionBuffer buf(addrs.size() * asiolink::V6ADDRESS_LEN);
  144. for (int i = 0; i < addrs.size(); ++i) {
  145. asio::ip::address_v6::bytes_type addr_bytes =
  146. addrs[i].getAddress().to_v6().to_bytes();
  147. ASSERT_EQ(asiolink::V6ADDRESS_LEN, addr_bytes.size());
  148. std::copy(addr_bytes.begin(), addr_bytes.end(),
  149. buf.begin() + i * asiolink::V6ADDRESS_LEN);
  150. }
  151. // Create DHCPv6 option from this buffer. Once option is created it is
  152. // supposed to have internal list of addresses that it parses out from
  153. // the provided buffer.
  154. OptionPtr option_v6;
  155. ASSERT_NO_THROW(
  156. option_v6 = factory(Option::V6, D6O_NIS_SERVERS, buf);
  157. );
  158. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
  159. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  160. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  161. ASSERT_TRUE(option_cast_v6);
  162. // Get the list of parsed addresses from the option object.
  163. std::vector<asiolink::IOAddress> addrs_returned =
  164. option_cast_v6->getAddresses();
  165. // The list of addresses must exactly match addresses that we
  166. // stored in the buffer to create the option from it.
  167. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  168. // The provided buffer's length must be a multiple of V6 address length.
  169. // Let's extend the buffer by one byte so as this condition is not
  170. // fulfilled anymore.
  171. buf.insert(buf.end(), 1, 1);
  172. // It should throw exception then.
  173. EXPECT_THROW(
  174. factory(Option::V6, D6O_NIS_SERVERS, buf),
  175. isc::OutOfRange
  176. );
  177. }
  178. TEST_F(OptionDefinitionTest, factoryAddrList4) {
  179. OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
  180. "ipv4-address", true);
  181. Option::Factory* factory(NULL);
  182. EXPECT_NO_THROW(factory = opt_def.getFactory());
  183. ASSERT_TRUE(factory != NULL);
  184. // Create a list of some V6 addresses.
  185. std::vector<asiolink::IOAddress> addrs;
  186. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  187. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  188. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  189. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  190. // Write addresses to the buffer.
  191. OptionBuffer buf(addrs.size() * asiolink::V4ADDRESS_LEN);
  192. for (int i = 0; i < addrs.size(); ++i) {
  193. asio::ip::address_v4::bytes_type addr_bytes =
  194. addrs[i].getAddress().to_v4().to_bytes();
  195. ASSERT_EQ(asiolink::V4ADDRESS_LEN, addr_bytes.size());
  196. std::copy(addr_bytes.begin(), addr_bytes.end(),
  197. buf.begin() + i * asiolink::V4ADDRESS_LEN);
  198. }
  199. // Create DHCPv6 option from this buffer. Once option is created it is
  200. // supposed to have internal list of addresses that it parses out from
  201. // the provided buffer.
  202. OptionPtr option_v4;
  203. ASSERT_NO_THROW(
  204. option_v4 = factory(Option::V4, DHO_NAME_SERVERS, buf)
  205. );
  206. ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
  207. // Get the list of parsed addresses from the option object.
  208. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  209. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  210. std::vector<asiolink::IOAddress> addrs_returned =
  211. option_cast_v4->getAddresses();
  212. // The list of addresses must exactly match addresses that we
  213. // stored in the buffer to create the option from it.
  214. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  215. // The provided buffer's length must be a multiple of V4 address length.
  216. // Let's extend the buffer by one byte so as this condition is not
  217. // fulfilled anymore.
  218. buf.insert(buf.end(), 1, 1);
  219. // It should throw exception then.
  220. EXPECT_THROW(factory(Option::V4, DHO_NIS_SERVERS, buf), isc::OutOfRange);
  221. }
  222. TEST_F(OptionDefinitionTest, factoryEmpty) {
  223. OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
  224. Option::Factory* factory(NULL);
  225. EXPECT_NO_THROW(factory = opt_def.getFactory());
  226. ASSERT_TRUE(factory != NULL);
  227. // Create option instance and provide empty buffer as expected.
  228. OptionPtr option_v6;
  229. ASSERT_NO_THROW(
  230. option_v6 = factory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
  231. );
  232. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  233. // Expect 'empty' DHCPv6 option.
  234. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  235. EXPECT_EQ(4, option_v6->getHeaderLen());
  236. EXPECT_EQ(0, option_v6->getData().size());
  237. // Repeat the same test scenario for DHCPv4 option.
  238. EXPECT_THROW(factory(Option::V4, 214, OptionBuffer(2)),isc::BadValue);
  239. OptionPtr option_v4;
  240. ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, OptionBuffer()));
  241. // Expect 'empty' DHCPv4 option.
  242. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  243. EXPECT_EQ(2, option_v4->getHeaderLen());
  244. EXPECT_EQ(0, option_v4->getData().size());
  245. // This factory produces empty option (consisting of option type
  246. // and length). Attempt to provide some data in the buffer should
  247. // result in exception.
  248. EXPECT_THROW(factory(Option::V6, D6O_RAPID_COMMIT,OptionBuffer(2)),isc::BadValue);
  249. }
  250. TEST_F(OptionDefinitionTest, factoryIA6) {
  251. // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
  252. const int option6_ia_len = 12;
  253. // Get the factory function pointer.
  254. OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", true);
  255. // Each data field is uint32.
  256. for (int i = 0; i < 3; ++i) {
  257. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  258. }
  259. Option::Factory* factory(NULL);
  260. EXPECT_NO_THROW(factory = opt_def.getFactory());
  261. ASSERT_TRUE(factory != NULL);
  262. // Check the positive scenario.
  263. OptionBuffer buf(12);
  264. for (int i = 0; i < buf.size(); ++i) {
  265. buf[i] = i;
  266. }
  267. OptionPtr option_v6;
  268. ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IA_NA, buf));
  269. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IA));
  270. boost::shared_ptr<Option6IA> option_cast_v6 =
  271. boost::static_pointer_cast<Option6IA>(option_v6);
  272. EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
  273. EXPECT_EQ(0x04050607, option_cast_v6->getT1());
  274. EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
  275. // This should work for DHCPv6 only, try passing invalid universe value.
  276. EXPECT_THROW(
  277. factory(Option::V4, D6O_IA_NA, OptionBuffer(option6_ia_len)),
  278. isc::BadValue
  279. );
  280. // The length of the buffer must be 12 bytes.
  281. // Check too short buffer.
  282. EXPECT_THROW(
  283. factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
  284. isc::OutOfRange
  285. );
  286. // Check too long buffer.
  287. EXPECT_THROW(
  288. factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len + 1)),
  289. isc::OutOfRange
  290. );
  291. }
  292. TEST_F(OptionDefinitionTest, factoryIAAddr6) {
  293. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  294. // valid-lifetime fields (each 4 bytes long).
  295. const int option6_iaaddr_len = 24;
  296. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  297. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  298. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  299. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  300. Option::Factory* factory(NULL);
  301. EXPECT_NO_THROW(factory = opt_def.getFactory());
  302. ASSERT_TRUE(factory != NULL);
  303. // Check the positive scenario.
  304. OptionPtr option_v6;
  305. asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
  306. OptionBuffer buf(asiolink::V6ADDRESS_LEN);
  307. ASSERT_TRUE(addr_v6.getAddress().is_v6());
  308. asio::ip::address_v6::bytes_type addr_bytes =
  309. addr_v6.getAddress().to_v6().to_bytes();
  310. ASSERT_EQ(asiolink::V6ADDRESS_LEN, addr_bytes.size());
  311. std::copy(addr_bytes.begin(), addr_bytes.end(), buf.begin());
  312. for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
  313. buf.push_back(i);
  314. }
  315. ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IAADDR, buf));
  316. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
  317. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  318. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  319. EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
  320. EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
  321. EXPECT_EQ(0x04050607, option_cast_v6->getValid());
  322. // This should work for DHCPv6 only, try passing invalid universe value.
  323. EXPECT_THROW(
  324. factory(Option::V4, D6O_IAADDR, OptionBuffer(option6_iaaddr_len)),
  325. isc::BadValue
  326. );
  327. // The length of the buffer must be 12 bytes.
  328. // Check too short buffer.
  329. EXPECT_THROW(
  330. factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
  331. isc::OutOfRange
  332. );
  333. // Check too long buffer.
  334. EXPECT_THROW(
  335. factory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len + 1)),
  336. isc::OutOfRange
  337. );
  338. }
  339. TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
  340. // The template function factoryInteger<> accepts integer values only
  341. // as template typename. Here we try passing different type and
  342. // see if it rejects it.
  343. EXPECT_THROW(
  344. OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, OptionBuffer(1)),
  345. isc::dhcp::InvalidDataType
  346. );
  347. }
  348. TEST_F(OptionDefinitionTest, factoryUint8) {
  349. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  350. Option::Factory* factory(NULL);
  351. EXPECT_NO_THROW(factory = opt_def.getFactory());
  352. ASSERT_TRUE(factory != NULL);
  353. OptionPtr option_v6;
  354. // Try to use correct buffer length = 1 byte.
  355. ASSERT_NO_THROW(
  356. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
  357. );
  358. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
  359. // Validate the value.
  360. boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
  361. boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
  362. EXPECT_EQ(1, option_cast_v6->getValue());
  363. // Try to provide too large buffer. Expect exception.
  364. EXPECT_THROW(
  365. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(3)),
  366. isc::OutOfRange
  367. );
  368. // Try to provide zero-length buffer. Expect exception.
  369. EXPECT_THROW(
  370. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
  371. isc::OutOfRange
  372. );
  373. // @todo Add more cases for DHCPv4
  374. }
  375. TEST_F(OptionDefinitionTest, factoryUint16) {
  376. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  377. Option::Factory* factory(NULL);
  378. EXPECT_NO_THROW(factory = opt_def.getFactory());
  379. ASSERT_TRUE(factory != NULL);
  380. OptionPtr option_v6;
  381. // Try to use correct buffer length = 2 bytes.
  382. OptionBuffer buf;
  383. buf.push_back(1);
  384. buf.push_back(2);
  385. ASSERT_NO_THROW(
  386. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, buf);
  387. );
  388. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
  389. // Validate the value.
  390. boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
  391. boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
  392. EXPECT_EQ(0x0102, option_cast_v6->getValue());
  393. // Try to provide too large buffer. Expect exception.
  394. EXPECT_THROW(
  395. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(3)),
  396. isc::OutOfRange
  397. );
  398. // Try to provide zero-length buffer. Expect exception.
  399. EXPECT_THROW(
  400. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
  401. isc::OutOfRange
  402. );
  403. // @todo Add more cases for DHCPv4
  404. }
  405. TEST_F(OptionDefinitionTest, factoryUint32) {
  406. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  407. Option::Factory* factory(NULL);
  408. EXPECT_NO_THROW(factory = opt_def.getFactory());
  409. ASSERT_TRUE(factory != NULL);
  410. OptionPtr option_v6;
  411. OptionBuffer buf;
  412. buf.push_back(1);
  413. buf.push_back(2);
  414. buf.push_back(3);
  415. buf.push_back(4);
  416. ASSERT_NO_THROW(
  417. option_v6 = factory(Option::V6, D6O_CLT_TIME, buf);
  418. );
  419. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
  420. // Validate the value.
  421. boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
  422. boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
  423. EXPECT_EQ(0x01020304, option_cast_v6->getValue());
  424. // Try to provide too large buffer. Expect exception.
  425. EXPECT_THROW(
  426. option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(5)),
  427. isc::OutOfRange
  428. );
  429. // Try to provide zero-length buffer. Expect exception.
  430. EXPECT_THROW(
  431. option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
  432. isc::OutOfRange
  433. );
  434. // @todo Add more cases for DHCPv4
  435. }
  436. TEST_F(OptionDefinitionTest, factoryUint16Array) {
  437. // Let's define some dummy option.
  438. const uint16_t opt_code = 79;
  439. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  440. Option::Factory* factory(NULL);
  441. EXPECT_NO_THROW(factory = opt_def.getFactory());
  442. ASSERT_TRUE(factory != NULL);
  443. OptionPtr option_v6;
  444. // Positive scenario, initiate the buffer with length being
  445. // multiple of uint16_t size.
  446. // buffer elements will be: 0x112233.
  447. OptionBuffer buf(6);
  448. for (int i = 0; i < 6; ++i) {
  449. buf[i] = i / 2;
  450. }
  451. // Constructor should succeed because buffer has correct size.
  452. EXPECT_NO_THROW(
  453. option_v6 = factory(Option::V6, opt_code, buf);
  454. );
  455. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
  456. boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
  457. boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
  458. // Get the values from the initiated options and validate.
  459. std::vector<uint16_t> values = option_cast_v6->getValues();
  460. for (int i = 0; i < values.size(); ++i) {
  461. // Expected value is calculated using on the same pattern
  462. // as the one we used to initiate buffer:
  463. // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
  464. uint16_t expected = (i << 8) | i;
  465. EXPECT_EQ(expected, values[i]);
  466. }
  467. // Provided buffer size must be greater than zero. Check if we
  468. // get exception if we provide zero-length buffer.
  469. EXPECT_THROW(
  470. option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
  471. isc::OutOfRange
  472. );
  473. // Buffer length must be multiple of data type size.
  474. EXPECT_THROW(
  475. option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
  476. isc::OutOfRange
  477. );
  478. }
  479. TEST_F(OptionDefinitionTest, factoryUint32Array) {
  480. // Let's define some dummy option.
  481. const uint16_t opt_code = 80;
  482. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  483. Option::Factory* factory(NULL);
  484. EXPECT_NO_THROW(factory = opt_def.getFactory());
  485. ASSERT_TRUE(factory != NULL);
  486. OptionPtr option_v6;
  487. // Positive scenario, initiate the buffer with length being
  488. // multiple of uint16_t size.
  489. // buffer elements will be: 0x111122223333.
  490. OptionBuffer buf(12);
  491. for (int i = 0; i < buf.size(); ++i) {
  492. buf[i] = i / 4;
  493. }
  494. // Constructor should succeed because buffer has correct size.
  495. EXPECT_NO_THROW(
  496. option_v6 = factory(Option::V6, opt_code, buf);
  497. );
  498. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
  499. boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
  500. boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
  501. // Get the values from the initiated options and validate.
  502. std::vector<uint32_t> values = option_cast_v6->getValues();
  503. for (int i = 0; i < values.size(); ++i) {
  504. // Expected value is calculated using on the same pattern
  505. // as the one we used to initiate buffer:
  506. // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
  507. uint32_t expected = 0x01010101 * i;
  508. EXPECT_EQ(expected, values[i]);
  509. }
  510. // Provided buffer size must be greater than zero. Check if we
  511. // get exception if we provide zero-length buffer.
  512. EXPECT_THROW(
  513. option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
  514. isc::OutOfRange
  515. );
  516. // Buffer length must be multiple of data type size.
  517. EXPECT_THROW(
  518. option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
  519. isc::OutOfRange
  520. );
  521. }
  522. TEST_F(OptionDefinitionTest, recognizeFormat) {
  523. // IA_NA option format.
  524. OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
  525. for (int i = 0; i < 3; ++i) {
  526. opt_def1.addRecordField("uint32");
  527. }
  528. EXPECT_TRUE(opt_def1.haveIA6Format());
  529. // Create non-matching format to check that this function does not
  530. // return 'true' all the time.
  531. OptionDefinition opt_def2("OPTION_IA_NA", D6O_IA_NA, "uint16");
  532. EXPECT_FALSE(opt_def2.haveIA6Format());
  533. // IAADDR option format.
  534. OptionDefinition opt_def3("OPTION_IAADDR", D6O_IAADDR, "record");
  535. opt_def3.addRecordField("ipv6-address");
  536. opt_def3.addRecordField("uint32");
  537. opt_def3.addRecordField("uint32");
  538. EXPECT_TRUE(opt_def3.haveIAAddr6Format());
  539. // Create non-matching format to check that this function does not
  540. // return 'true' all the time.
  541. OptionDefinition opt_def4("OPTION_IAADDR", D6O_IAADDR, "uint32", true);
  542. EXPECT_FALSE(opt_def4.haveIAAddr6Format());
  543. }
  544. } // anonymous namespace