option_definition_unittest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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;
  144. for (int i = 0; i < addrs.size(); ++i) {
  145. unsigned char* data = addrs[i].getAddress().to_v6().to_bytes().data();
  146. // @todo Are there any sanity checks needed here on this raw pointer?
  147. buf.insert(buf.end(), data, data + asiolink::V6ADDRESS_LEN);
  148. }
  149. // Create DHCPv6 option from this buffer. Once option is created it is
  150. // supposed to have internal list of addresses that it parses out from
  151. // the provided buffer.
  152. OptionPtr option_v6;
  153. ASSERT_NO_THROW(
  154. option_v6 = factory(Option::V6, D6O_NIS_SERVERS, buf);
  155. );
  156. ASSERT_EQ(typeid(*option_v6), typeid(Option6AddrLst));
  157. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  158. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  159. ASSERT_TRUE(option_cast_v6);
  160. // Get the list of parsed addresses from the option object.
  161. std::vector<asiolink::IOAddress> addrs_returned =
  162. option_cast_v6->getAddresses();
  163. // The list of addresses must exactly match addresses that we
  164. // stored in the buffer to create the option from it.
  165. EXPECT_EQ(addrs, addrs_returned);
  166. // The provided buffer's length must be a multiple of V6 address length.
  167. // Let's extend the buffer by one byte so as this condition is not
  168. // fulfilled anymore.
  169. buf.insert(buf.end(), 1, 1);
  170. // It should throw exception then.
  171. EXPECT_THROW(
  172. factory(Option::V6, D6O_NIS_SERVERS, buf),
  173. isc::OutOfRange
  174. );
  175. }
  176. TEST_F(OptionDefinitionTest, factoryAddrList4) {
  177. OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
  178. "ipv4-address", true);
  179. Option::Factory* factory(NULL);
  180. EXPECT_NO_THROW(factory = opt_def.getFactory());
  181. ASSERT_TRUE(factory != NULL);
  182. // Create a list of some V6 addresses.
  183. std::vector<asiolink::IOAddress> addrs;
  184. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  185. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  186. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  187. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  188. // Write addresses to the buffer.
  189. OptionBuffer buf;
  190. for (int i = 0; i < addrs.size(); ++i) {
  191. unsigned char* data = addrs[i].getAddress().to_v4().to_bytes().data();
  192. // @todo Are there any sanity checks needed here on this raw pointer?
  193. buf.insert(buf.end(), data, data + asiolink::V4ADDRESS_LEN);
  194. }
  195. // Create DHCPv6 option from this buffer. Once option is created it is
  196. // supposed to have internal list of addresses that it parses out from
  197. // the provided buffer.
  198. OptionPtr option_v4;
  199. ASSERT_NO_THROW(
  200. option_v4 = factory(Option::V4, DHO_NAME_SERVERS, buf)
  201. );
  202. ASSERT_EQ(typeid(*option_v4), typeid(Option4AddrLst));
  203. // Get the list of parsed addresses from the option object.
  204. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  205. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  206. std::vector<asiolink::IOAddress> addrs_returned =
  207. option_cast_v4->getAddresses();
  208. // The list of addresses must exactly match addresses that we
  209. // stored in the buffer to create the option from it.
  210. EXPECT_EQ(addrs, addrs_returned);
  211. // The provided buffer's length must be a multiple of V4 address length.
  212. // Let's extend the buffer by one byte so as this condition is not
  213. // fulfilled anymore.
  214. buf.insert(buf.end(), 1, 1);
  215. // It should throw exception then.
  216. EXPECT_THROW(factory(Option::V4, DHO_NIS_SERVERS, buf), isc::OutOfRange);
  217. }
  218. TEST_F(OptionDefinitionTest, factoryEmpty) {
  219. OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
  220. Option::Factory* factory(NULL);
  221. EXPECT_NO_THROW(factory = opt_def.getFactory());
  222. ASSERT_TRUE(factory != NULL);
  223. // Create option instance and provide empty buffer as expected.
  224. OptionPtr option_v6;
  225. ASSERT_NO_THROW(
  226. option_v6 = factory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
  227. );
  228. ASSERT_EQ(typeid(*option_v6), typeid(Option));
  229. // Expect 'empty' DHCPv6 option.
  230. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  231. EXPECT_EQ(4, option_v6->getHeaderLen());
  232. EXPECT_EQ(0, option_v6->getData().size());
  233. // Repeat the same test scenario for DHCPv4 option.
  234. EXPECT_THROW(factory(Option::V4, 214, OptionBuffer(2)),isc::BadValue);
  235. OptionPtr option_v4;
  236. ASSERT_NO_THROW(option_v4 = factory(Option::V4, 214, OptionBuffer()));
  237. // Expect 'empty' DHCPv4 option.
  238. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  239. EXPECT_EQ(2, option_v4->getHeaderLen());
  240. EXPECT_EQ(0, option_v4->getData().size());
  241. // This factory produces empty option (consisting of option type
  242. // and length). Attempt to provide some data in the buffer should
  243. // result in exception.
  244. EXPECT_THROW(factory(Option::V6, D6O_RAPID_COMMIT,OptionBuffer(2)),isc::BadValue);
  245. }
  246. TEST_F(OptionDefinitionTest, factoryIA6) {
  247. // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
  248. const int option6_ia_len = 12;
  249. // Get the factory function pointer.
  250. OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", true);
  251. // Each data field is uint32.
  252. for (int i = 0; i < 3; ++i) {
  253. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  254. }
  255. Option::Factory* factory(NULL);
  256. EXPECT_NO_THROW(factory = opt_def.getFactory());
  257. ASSERT_TRUE(factory != NULL);
  258. // Check the positive scenario.
  259. OptionBuffer buf(12);
  260. for (int i = 0; i < buf.size(); ++i) {
  261. buf[i] = i;
  262. }
  263. OptionPtr option_v6;
  264. ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IA_NA, buf));
  265. ASSERT_EQ(typeid(*option_v6), typeid(Option6IA));
  266. boost::shared_ptr<Option6IA> option_cast_v6 =
  267. boost::static_pointer_cast<Option6IA>(option_v6);
  268. EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
  269. EXPECT_EQ(0x04050607, option_cast_v6->getT1());
  270. EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
  271. // This should work for DHCPv6 only, try passing invalid universe value.
  272. EXPECT_THROW(
  273. factory(Option::V4, D6O_IA_NA, OptionBuffer(option6_ia_len)),
  274. isc::BadValue
  275. );
  276. // The length of the buffer must be 12 bytes.
  277. // Check too short buffer.
  278. EXPECT_THROW(
  279. factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
  280. isc::OutOfRange
  281. );
  282. // Check too long buffer.
  283. EXPECT_THROW(
  284. factory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len + 1)),
  285. isc::OutOfRange
  286. );
  287. }
  288. TEST_F(OptionDefinitionTest, factoryIAAddr6) {
  289. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  290. // valid-lifetime fields (each 4 bytes long).
  291. const int option6_iaaddr_len = 24;
  292. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  293. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  294. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  295. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  296. Option::Factory* factory(NULL);
  297. EXPECT_NO_THROW(factory = opt_def.getFactory());
  298. ASSERT_TRUE(factory != NULL);
  299. // Check the positive scenario.
  300. OptionPtr option_v6;
  301. asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
  302. ASSERT_TRUE(addr_v6.getAddress().is_v6());
  303. unsigned char* addr_bytes_v6 = addr_v6.getAddress().to_v6().to_bytes().data();
  304. ASSERT_TRUE(addr_bytes_v6 != NULL);
  305. OptionBuffer buf;
  306. buf.insert(buf.end(), addr_bytes_v6, addr_bytes_v6 + asiolink::V6ADDRESS_LEN);
  307. for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
  308. buf.push_back(i);
  309. }
  310. // ASSERT_NO_THROW(option_v6 = factory(Option::V6, D6O_IAADDR, buf));
  311. try {
  312. option_v6 = factory(Option::V6, D6O_IAADDR, buf);
  313. } catch (const Exception& e) {
  314. std::cout << e.what() << std::endl;
  315. }
  316. ASSERT_EQ(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_EQ(typeid(*option_v6), typeid(Option6Int<uint8_t>)); // Validate the value.
  359. boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
  360. boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
  361. EXPECT_EQ(1, option_cast_v6->getValue());
  362. // Try to provide too large buffer. Expect exception.
  363. EXPECT_THROW(
  364. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer(3)),
  365. isc::OutOfRange
  366. );
  367. // Try to provide zero-length buffer. Expect exception.
  368. EXPECT_THROW(
  369. option_v6 = factory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
  370. isc::OutOfRange
  371. );
  372. // @todo Add more cases for DHCPv4
  373. }
  374. TEST_F(OptionDefinitionTest, factoryUint16) {
  375. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  376. Option::Factory* factory(NULL);
  377. EXPECT_NO_THROW(factory = opt_def.getFactory());
  378. ASSERT_TRUE(factory != NULL);
  379. OptionPtr option_v6;
  380. // Try to use correct buffer length = 2 bytes.
  381. OptionBuffer buf;
  382. buf.push_back(1);
  383. buf.push_back(2);
  384. ASSERT_NO_THROW(
  385. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, buf);
  386. );
  387. ASSERT_EQ(typeid(*option_v6), typeid(Option6Int<uint16_t>));
  388. // Validate the value.
  389. boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
  390. boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
  391. EXPECT_EQ(0x0102, option_cast_v6->getValue());
  392. // Try to provide too large buffer. Expect exception.
  393. EXPECT_THROW(
  394. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(3)),
  395. isc::OutOfRange
  396. );
  397. // Try to provide zero-length buffer. Expect exception.
  398. EXPECT_THROW(
  399. option_v6 = factory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
  400. isc::OutOfRange
  401. );
  402. // @todo Add more cases for DHCPv4
  403. }
  404. TEST_F(OptionDefinitionTest, factoryUint32) {
  405. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  406. Option::Factory* factory(NULL);
  407. EXPECT_NO_THROW(factory = opt_def.getFactory());
  408. ASSERT_TRUE(factory != NULL);
  409. OptionPtr option_v6;
  410. OptionBuffer buf;
  411. buf.push_back(1);
  412. buf.push_back(2);
  413. buf.push_back(3);
  414. buf.push_back(4);
  415. ASSERT_NO_THROW(
  416. option_v6 = factory(Option::V6, D6O_CLT_TIME, buf);
  417. );
  418. ASSERT_EQ(typeid(*option_v6), typeid(Option6Int<uint32_t>));
  419. // Validate the value.
  420. boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
  421. boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
  422. EXPECT_EQ(0x01020304, option_cast_v6->getValue());
  423. // Try to provide too large buffer. Expect exception.
  424. EXPECT_THROW(
  425. option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(5)),
  426. isc::OutOfRange
  427. );
  428. // Try to provide zero-length buffer. Expect exception.
  429. EXPECT_THROW(
  430. option_v6 = factory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
  431. isc::OutOfRange
  432. );
  433. // @todo Add more cases for DHCPv4
  434. }
  435. TEST_F(OptionDefinitionTest, factoryUint16Array) {
  436. // Let's define some dummy option.
  437. const uint16_t opt_code = 79;
  438. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  439. Option::Factory* factory(NULL);
  440. EXPECT_NO_THROW(factory = opt_def.getFactory());
  441. ASSERT_TRUE(factory != NULL);
  442. OptionPtr option_v6;
  443. // Positive scenario, initiate the buffer with length being
  444. // multiple of uint16_t size.
  445. // buffer elements will be: 0x112233.
  446. OptionBuffer buf(6);
  447. for (int i = 0; i < 6; ++i) {
  448. buf[i] = i / 2;
  449. }
  450. // Constructor should succeed because buffer has correct size.
  451. EXPECT_NO_THROW(
  452. option_v6 = factory(Option::V6, opt_code, buf);
  453. );
  454. ASSERT_EQ(typeid(*option_v6), typeid(Option6IntArray<uint16_t>));
  455. boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
  456. boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
  457. // Get the values from the initiated options and validate.
  458. std::vector<uint16_t> values = option_cast_v6->getValues();
  459. for (int i = 0; i < values.size(); ++i) {
  460. // Expected value is calculated using on the same pattern
  461. // as the one we used to initiate buffer:
  462. // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
  463. uint16_t expected = (i << 8) | i;
  464. EXPECT_EQ(expected, values[i]);
  465. }
  466. // Provided buffer size must be greater than zero. Check if we
  467. // get exception if we provide zero-length buffer.
  468. EXPECT_THROW(
  469. option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
  470. isc::OutOfRange
  471. );
  472. // Buffer length must be multiple of data type size.
  473. EXPECT_THROW(
  474. option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
  475. isc::OutOfRange
  476. );
  477. }
  478. TEST_F(OptionDefinitionTest, factoryUint32Array) {
  479. // Let's define some dummy option.
  480. const uint16_t opt_code = 80;
  481. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  482. Option::Factory* factory(NULL);
  483. EXPECT_NO_THROW(factory = opt_def.getFactory());
  484. ASSERT_TRUE(factory != NULL);
  485. OptionPtr option_v6;
  486. // Positive scenario, initiate the buffer with length being
  487. // multiple of uint16_t size.
  488. // buffer elements will be: 0x111122223333.
  489. OptionBuffer buf(12);
  490. for (int i = 0; i < buf.size(); ++i) {
  491. buf[i] = i / 4;
  492. }
  493. // Constructor should succeed because buffer has correct size.
  494. EXPECT_NO_THROW(
  495. option_v6 = factory(Option::V6, opt_code, buf);
  496. );
  497. ASSERT_EQ(typeid(*option_v6), typeid(Option6IntArray<uint32_t>));
  498. boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
  499. boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
  500. // Get the values from the initiated options and validate.
  501. std::vector<uint32_t> values = option_cast_v6->getValues();
  502. for (int i = 0; i < values.size(); ++i) {
  503. // Expected value is calculated using on the same pattern
  504. // as the one we used to initiate buffer:
  505. // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
  506. uint32_t expected = 0x01010101 * i;
  507. EXPECT_EQ(expected, values[i]);
  508. }
  509. // Provided buffer size must be greater than zero. Check if we
  510. // get exception if we provide zero-length buffer.
  511. EXPECT_THROW(
  512. option_v6 = factory(Option::V6, opt_code, OptionBuffer()),
  513. isc::OutOfRange
  514. );
  515. // Buffer length must be multiple of data type size.
  516. EXPECT_THROW(
  517. option_v6 = factory(Option::V6, opt_code, OptionBuffer(5)),
  518. isc::OutOfRange
  519. );
  520. }
  521. } // anonymous namespace