option_definition_unittest.cc 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  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 <asiolink/io_address.h>
  16. #include <dhcp/dhcp4.h>
  17. #include <dhcp/dhcp6.h>
  18. #include <dhcp/option4_addrlst.h>
  19. #include <dhcp/option6_addrlst.h>
  20. #include <dhcp/option6_ia.h>
  21. #include <dhcp/option6_iaaddr.h>
  22. #include <dhcp/option6_int.h>
  23. #include <dhcp/option6_int_array.h>
  24. #include <dhcp/option_definition.h>
  25. #include <exceptions/exceptions.h>
  26. #include <boost/pointer_cast.hpp>
  27. #include <boost/shared_ptr.hpp>
  28. #include <gtest/gtest.h>
  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. // The purpose of this test is to verify that OptionDefinition
  44. // constructor initializes its members correctly.
  45. TEST_F(OptionDefinitionTest, constructor) {
  46. // Specify the option data type as string. This should get converted
  47. // to enum value returned by getType().
  48. OptionDefinition opt_def1("OPTION_CLIENTID", 1, "string");
  49. EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
  50. EXPECT_EQ(1, opt_def1.getCode());
  51. EXPECT_EQ(OPT_STRING_TYPE, opt_def1.getType());
  52. EXPECT_FALSE(opt_def1.getArrayType());
  53. EXPECT_NO_THROW(opt_def1.validate());
  54. // Specify the option data type as an enum value.
  55. OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
  56. OPT_EMPTY_TYPE);
  57. EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
  58. EXPECT_EQ(14, opt_def2.getCode());
  59. EXPECT_EQ(OPT_EMPTY_TYPE, opt_def2.getType());
  60. EXPECT_FALSE(opt_def2.getArrayType());
  61. EXPECT_NO_THROW(opt_def1.validate());
  62. // Check if it is possible to set that option is an array.
  63. OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
  64. OPT_IPV6_ADDRESS_TYPE,
  65. true);
  66. EXPECT_EQ("OPTION_NIS_SERVERS", opt_def3.getName());
  67. EXPECT_EQ(27, opt_def3.getCode());
  68. EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, opt_def3.getType());
  69. EXPECT_TRUE(opt_def3.getArrayType());
  70. EXPECT_NO_THROW(opt_def3.validate());
  71. // The created object is invalid if invalid data type is specified but
  72. // constructor shouldn't throw exception. The object is validated after
  73. // it has been created.
  74. EXPECT_NO_THROW(
  75. OptionDefinition opt_def4("OPTION_SERVERID",
  76. OPT_UNKNOWN_TYPE + 10,
  77. OPT_STRING_TYPE);
  78. );
  79. }
  80. // The purpose of this test is to verify that various data fields
  81. // can be specified for an option definition when this definition
  82. // is marked as 'record' and that fields can't be added if option
  83. // definition is not marked as 'record'.
  84. TEST_F(OptionDefinitionTest, addRecordField) {
  85. // We can only add fields to record if the option type has been
  86. // specified as 'record'. We try all other types but 'record'
  87. // here and expect exception to be thrown.
  88. for (int i = 0; i < OPT_UNKNOWN_TYPE; ++i) {
  89. // Do not try for 'record' type because this is the only
  90. // type for which adding record will succeed.
  91. if (i == OPT_RECORD_TYPE) {
  92. continue;
  93. }
  94. OptionDefinition opt_def("OPTION_IAADDR", 5,
  95. static_cast<OptionDataType>(i));
  96. EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
  97. }
  98. // Positive scenario starts here.
  99. OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
  100. EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  101. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  102. // It should not matter if we specify field type by its name or using enum.
  103. EXPECT_NO_THROW(opt_def.addRecordField(OPT_UINT32_TYPE));
  104. // Check what we have actually added.
  105. OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
  106. ASSERT_EQ(3, fields.size());
  107. EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, fields[0]);
  108. EXPECT_EQ(OPT_UINT32_TYPE, fields[1]);
  109. EXPECT_EQ(OPT_UINT32_TYPE, fields[2]);
  110. // Let's try some more negative scenarios: use invalid data types.
  111. EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
  112. OptionDataType invalid_type =
  113. static_cast<OptionDataType>(OPT_UNKNOWN_TYPE + 10);
  114. EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
  115. // It is bad if we use 'record' option type but don't specify
  116. // at least two fields.
  117. OptionDefinition opt_def2("OPTION_EMPTY_RECORD", 100, "record");
  118. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  119. opt_def2.addRecordField("uint8");
  120. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  121. opt_def2.addRecordField("uint32");
  122. EXPECT_NO_THROW(opt_def2.validate());
  123. }
  124. // The purpose of this test is to check that validate() function
  125. // reports errors for invalid option definitions.
  126. TEST_F(OptionDefinitionTest, validate) {
  127. // Not supported option type string is not allowed.
  128. OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
  129. EXPECT_THROW(opt_def1.validate(), MalformedOptionDefinition);
  130. // Not supported option type enum value is not allowed.
  131. OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OPT_UNKNOWN_TYPE);
  132. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  133. OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
  134. static_cast<OptionDataType>(OPT_UNKNOWN_TYPE
  135. + 2));
  136. EXPECT_THROW(opt_def3.validate(), MalformedOptionDefinition);
  137. // Empty option name is not allowed.
  138. OptionDefinition opt_def4("", D6O_CLIENTID, "string");
  139. EXPECT_THROW(opt_def4.validate(), MalformedOptionDefinition);
  140. // Option name must not contain spaces.
  141. OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
  142. EXPECT_THROW(opt_def5.validate(), MalformedOptionDefinition);
  143. // Option name must not contain spaces.
  144. OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string", true);
  145. EXPECT_THROW(opt_def6.validate(), MalformedOptionDefinition);
  146. // Having array of strings does not make sense because there is no way
  147. // to determine string's length.
  148. OptionDefinition opt_def7("OPTION_CLIENTID", D6O_CLIENTID, "string", true);
  149. EXPECT_THROW(opt_def7.validate(), MalformedOptionDefinition);
  150. // It does not make sense to have string field within the record before
  151. // other fields because there is no way to determine the length of this
  152. // string and thus there is no way to determine where the other field
  153. // begins.
  154. OptionDefinition opt_def8("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  155. "record");
  156. opt_def8.addRecordField("string");
  157. opt_def8.addRecordField("uint16");
  158. EXPECT_THROW(opt_def8.validate(), MalformedOptionDefinition);
  159. // ... but it is ok if the string value is the last one.
  160. OptionDefinition opt_def9("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  161. "record");
  162. opt_def9.addRecordField("uint8");
  163. opt_def9.addRecordField("string");
  164. }
  165. // The purpose of this test is to verify that option definition
  166. // that comprises array of IPv6 addresses will return an instance
  167. // of option with a list of IPv6 addresses.
  168. TEST_F(OptionDefinitionTest, ipv6AddressArray) {
  169. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  170. "ipv6-address", true);
  171. // Create a list of some V6 addresses.
  172. std::vector<asiolink::IOAddress> addrs;
  173. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  174. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  175. addrs.push_back(asiolink::IOAddress("::1"));
  176. addrs.push_back(asiolink::IOAddress("::2"));
  177. // Write addresses to the buffer.
  178. OptionBuffer buf(addrs.size() * asiolink::V6ADDRESS_LEN);
  179. for (int i = 0; i < addrs.size(); ++i) {
  180. asio::ip::address_v6::bytes_type addr_bytes =
  181. addrs[i].getAddress().to_v6().to_bytes();
  182. ASSERT_EQ(asiolink::V6ADDRESS_LEN, addr_bytes.size());
  183. std::copy(addr_bytes.begin(), addr_bytes.end(),
  184. buf.begin() + i * asiolink::V6ADDRESS_LEN);
  185. }
  186. // Create DHCPv6 option from this buffer. Once option is created it is
  187. // supposed to have internal list of addresses that it parses out from
  188. // the provided buffer.
  189. OptionPtr option_v6;
  190. ASSERT_NO_THROW(
  191. option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS, buf);
  192. );
  193. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
  194. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  195. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  196. ASSERT_TRUE(option_cast_v6);
  197. // Get the list of parsed addresses from the option object.
  198. std::vector<asiolink::IOAddress> addrs_returned =
  199. option_cast_v6->getAddresses();
  200. // The list of addresses must exactly match addresses that we
  201. // stored in the buffer to create the option from it.
  202. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  203. // The provided buffer's length must be a multiple of V6 address length.
  204. // Let's extend the buffer by one byte so as this condition is not
  205. // fulfilled anymore.
  206. buf.insert(buf.end(), 1, 1);
  207. // It should throw exception then.
  208. EXPECT_THROW(
  209. opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS, buf),
  210. InvalidOptionValue
  211. );
  212. }
  213. // The purpose of this test is to verify that option definition
  214. // that comprises array of IPv6 addresses will return an instance
  215. // of option with a list of IPv6 addresses. Array of IPv6 addresses
  216. // is specified as a vector of strings (each string represents single
  217. // IPv6 address).
  218. TEST_F(OptionDefinitionTest, ipv6AddressArrayTokenized) {
  219. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  220. "ipv6-address", true);
  221. // Create a vector of some V6 addresses.
  222. std::vector<asiolink::IOAddress> addrs;
  223. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  224. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  225. addrs.push_back(asiolink::IOAddress("::1"));
  226. addrs.push_back(asiolink::IOAddress("::2"));
  227. // Create a vector of strings representing addresses given above.
  228. std::vector<std::string> addrs_str;
  229. for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
  230. it != addrs.end(); ++it) {
  231. addrs_str.push_back(it->toText());
  232. }
  233. // Create DHCPv6 option using the list of IPv6 addresses given in the
  234. // string form.
  235. OptionPtr option_v6;
  236. ASSERT_NO_THROW(
  237. option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS,
  238. addrs_str);
  239. );
  240. // Non-null pointer option is supposed to be returned and it
  241. // should have Option6AddrLst type.
  242. ASSERT_TRUE(option_v6);
  243. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
  244. // Cast to the actual option type to get IPv6 addresses from it.
  245. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  246. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  247. // Check that cast was successful.
  248. ASSERT_TRUE(option_cast_v6);
  249. // Get the list of parsed addresses from the option object.
  250. std::vector<asiolink::IOAddress> addrs_returned =
  251. option_cast_v6->getAddresses();
  252. // Returned addresses must match the addresses that have been used to create
  253. // the option instance.
  254. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  255. }
  256. // The purpose of this test is to verify that option definition
  257. // that comprises array of IPv4 addresses will return an instance
  258. // of option with a list of IPv4 addresses.
  259. TEST_F(OptionDefinitionTest, ipv4AddressArray) {
  260. OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
  261. "ipv4-address", true);
  262. // Create a list of some V6 addresses.
  263. std::vector<asiolink::IOAddress> addrs;
  264. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  265. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  266. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  267. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  268. // Write addresses to the buffer.
  269. OptionBuffer buf(addrs.size() * asiolink::V4ADDRESS_LEN);
  270. for (int i = 0; i < addrs.size(); ++i) {
  271. asio::ip::address_v4::bytes_type addr_bytes =
  272. addrs[i].getAddress().to_v4().to_bytes();
  273. ASSERT_EQ(asiolink::V4ADDRESS_LEN, addr_bytes.size());
  274. std::copy(addr_bytes.begin(), addr_bytes.end(),
  275. buf.begin() + i * asiolink::V4ADDRESS_LEN);
  276. }
  277. // Create DHCPv6 option from this buffer. Once option is created it is
  278. // supposed to have internal list of addresses that it parses out from
  279. // the provided buffer.
  280. OptionPtr option_v4;
  281. ASSERT_NO_THROW(
  282. option_v4 = opt_def.optionFactory(Option::V4, DHO_NAME_SERVERS, buf)
  283. );
  284. ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
  285. // Get the list of parsed addresses from the option object.
  286. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  287. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  288. std::vector<asiolink::IOAddress> addrs_returned =
  289. option_cast_v4->getAddresses();
  290. // The list of addresses must exactly match addresses that we
  291. // stored in the buffer to create the option from it.
  292. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  293. // The provided buffer's length must be a multiple of V4 address length.
  294. // Let's extend the buffer by one byte so as this condition is not
  295. // fulfilled anymore.
  296. buf.insert(buf.end(), 1, 1);
  297. // It should throw exception then.
  298. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS, buf),
  299. InvalidOptionValue);
  300. }
  301. // The purpose of this test is to verify that option definition
  302. // that comprises array of IPv4 addresses will return an instance
  303. // of option with a list of IPv4 addresses. The array of IPv4 addresses
  304. // is specified as a vector of strings (each string represents single
  305. // IPv4 address).
  306. TEST_F(OptionDefinitionTest, ipv4AddressArrayTokenized) {
  307. OptionDefinition opt_def("OPTION_NIS_SERVERS", DHO_NIS_SERVERS,
  308. "ipv4-address", true);
  309. // Create a vector of some V6 addresses.
  310. std::vector<asiolink::IOAddress> addrs;
  311. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  312. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  313. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  314. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  315. // Create a vector of strings representing addresses given above.
  316. std::vector<std::string> addrs_str;
  317. for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
  318. it != addrs.end(); ++it) {
  319. addrs_str.push_back(it->toText());
  320. }
  321. // Create DHCPv4 option using the list of IPv4 addresses given in the
  322. // string form.
  323. OptionPtr option_v4;
  324. ASSERT_NO_THROW(
  325. option_v4 = opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS,
  326. addrs_str);
  327. );
  328. // Non-null pointer option is supposed to be returned and it
  329. // should have Option6AddrLst type.
  330. ASSERT_TRUE(option_v4);
  331. ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
  332. // Cast to the actual option type to get IPv4 addresses from it.
  333. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  334. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  335. // Check that cast was successful.
  336. ASSERT_TRUE(option_cast_v4);
  337. // Get the list of parsed addresses from the option object.
  338. std::vector<asiolink::IOAddress> addrs_returned =
  339. option_cast_v4->getAddresses();
  340. // Returned addresses must match the addresses that have been used to create
  341. // the option instance.
  342. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  343. }
  344. // The purpose of thie test is to verify that option definition for
  345. // 'empty' option can be created and that it returns 'empty' option.
  346. TEST_F(OptionDefinitionTest, empty) {
  347. OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
  348. // Create option instance and provide empty buffer as expected.
  349. OptionPtr option_v6;
  350. ASSERT_NO_THROW(
  351. option_v6 = opt_def.optionFactory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
  352. );
  353. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  354. // Expect 'empty' DHCPv6 option.
  355. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  356. EXPECT_EQ(4, option_v6->getHeaderLen());
  357. EXPECT_EQ(0, option_v6->getData().size());
  358. // Repeat the same test scenario for DHCPv4 option.
  359. OptionPtr option_v4;
  360. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, OptionBuffer()));
  361. // Expect 'empty' DHCPv4 option.
  362. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  363. EXPECT_EQ(2, option_v4->getHeaderLen());
  364. EXPECT_EQ(0, option_v4->getData().size());
  365. }
  366. // The purpose of this test is to verify that definition can be
  367. // creates for the option that holds binary data.
  368. TEST_F(OptionDefinitionTest, binary) {
  369. // Binary option is the one that is represented by the generic
  370. // Option class. In fact all options can be represented by this
  371. // class but for some of them it is just natural. The SERVERID
  372. // option consists of the option code, length and binary data so
  373. // this one was picked for this test.
  374. OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
  375. // Prepare some dummy data (serverid): 0, 1, 2 etc.
  376. OptionBuffer buf(14);
  377. for (int i = 0; i < 14; ++i) {
  378. buf[i] = i;
  379. }
  380. // Create option instance with the factory function.
  381. // If the OptionDefinition code works properly than
  382. // object of the type Option should be returned.
  383. OptionPtr option_v6;
  384. ASSERT_NO_THROW(
  385. option_v6 = opt_def.optionFactory(Option::V6, D6O_SERVERID, buf);
  386. );
  387. // Expect base option type returned.
  388. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  389. // Sanity check on universe, length and size. These are
  390. // the basic parameters identifying any option.
  391. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  392. EXPECT_EQ(4, option_v6->getHeaderLen());
  393. ASSERT_EQ(buf.size(), option_v6->getData().size());
  394. // Get the server id data from the option and compare
  395. // against reference buffer. They are expected to match.
  396. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  397. option_v6->getData().end(),
  398. buf.begin()));
  399. // Repeat the same test scenario for DHCPv4 option.
  400. OptionPtr option_v4;
  401. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, buf));
  402. // Expect 'empty' DHCPv4 option.
  403. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  404. EXPECT_EQ(2, option_v4->getHeaderLen());
  405. ASSERT_EQ(buf.size(), option_v4->getData().size());
  406. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  407. option_v6->getData().end(),
  408. buf.begin()));
  409. }
  410. // The purpose of this test is to verify that definition can be
  411. // creates for the option that holds binary data and that the
  412. // binary data can be specified in 'comma separated values'
  413. // format.
  414. TEST_F(OptionDefinitionTest, binaryTokenized) {
  415. OptionDefinition opt_def("OPTION_FOO", 1000, "binary", true);
  416. // Prepare some dummy data (serverid): 0, 1, 2 etc.
  417. OptionBuffer buf(16);
  418. for (int i = 0; i < buf.size(); ++i) {
  419. buf[i] = i;
  420. }
  421. std::vector<std::string> hex_data;
  422. hex_data.push_back("00010203");
  423. hex_data.push_back("04050607");
  424. hex_data.push_back("08090A0B0C0D0E0F");
  425. // Create option instance with the factory function.
  426. // If the OptionDefinition code works properly than
  427. // object of the type Option should be returned.
  428. OptionPtr option_v6;
  429. ASSERT_NO_THROW(
  430. option_v6 = opt_def.optionFactory(Option::V6, 1000, hex_data);
  431. );
  432. // Expect base option type returned.
  433. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  434. // Sanity check on universe, length and size. These are
  435. // the basic parameters identifying any option.
  436. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  437. EXPECT_EQ(4, option_v6->getHeaderLen());
  438. ASSERT_EQ(buf.size(), option_v6->getData().size());
  439. // Get data from the option and compare against reference buffer.
  440. // They are expected to match.
  441. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  442. option_v6->getData().end(),
  443. buf.begin()));
  444. // Repeat the same test scenario for DHCPv4 option.
  445. OptionPtr option_v4;
  446. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, hex_data));
  447. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  448. EXPECT_EQ(2, option_v4->getHeaderLen());
  449. ASSERT_EQ(buf.size(), option_v4->getData().size());
  450. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  451. option_v6->getData().end(),
  452. buf.begin()));
  453. }
  454. // The purpose of this test is to verify that definition can be created
  455. // for option that comprises record of data. In this particular test
  456. // the IA_NA option is used. This option comprises three uint32 fields.
  457. TEST_F(OptionDefinitionTest, recordIA6) {
  458. // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
  459. const int option6_ia_len = 12;
  460. // Get the factory function pointer.
  461. OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", false);
  462. // Each data field is uint32.
  463. for (int i = 0; i < 3; ++i) {
  464. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  465. }
  466. // Check the positive scenario.
  467. OptionBuffer buf(12);
  468. for (int i = 0; i < buf.size(); ++i) {
  469. buf[i] = i;
  470. }
  471. OptionPtr option_v6;
  472. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IA_NA, buf));
  473. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IA));
  474. boost::shared_ptr<Option6IA> option_cast_v6 =
  475. boost::static_pointer_cast<Option6IA>(option_v6);
  476. EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
  477. EXPECT_EQ(0x04050607, option_cast_v6->getT1());
  478. EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
  479. // This should work for DHCPv6 only, try passing invalid universe value.
  480. EXPECT_THROW(
  481. opt_def.optionFactory(Option::V4, D6O_IA_NA, OptionBuffer(option6_ia_len)),
  482. InvalidOptionValue
  483. );
  484. // The length of the buffer must be at least 12 bytes.
  485. // Check too short buffer.
  486. EXPECT_THROW(
  487. opt_def.optionFactory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
  488. InvalidOptionValue
  489. );
  490. }
  491. // The purpose of this test is to verify that definition can be created
  492. // for option that comprises record of data. In this particular test
  493. // the IAADDR option is used.
  494. TEST_F(OptionDefinitionTest, recordIAAddr6) {
  495. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  496. // valid-lifetime fields (each 4 bytes long).
  497. const int option6_iaaddr_len = 24;
  498. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  499. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  500. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  501. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  502. // Check the positive scenario.
  503. OptionPtr option_v6;
  504. asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
  505. OptionBuffer buf(asiolink::V6ADDRESS_LEN);
  506. ASSERT_TRUE(addr_v6.getAddress().is_v6());
  507. asio::ip::address_v6::bytes_type addr_bytes =
  508. addr_v6.getAddress().to_v6().to_bytes();
  509. ASSERT_EQ(asiolink::V6ADDRESS_LEN, addr_bytes.size());
  510. std::copy(addr_bytes.begin(), addr_bytes.end(), buf.begin());
  511. for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
  512. buf.push_back(i);
  513. }
  514. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR, buf));
  515. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
  516. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  517. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  518. EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
  519. EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
  520. EXPECT_EQ(0x04050607, option_cast_v6->getValid());
  521. // This should work for DHCPv6 only, try passing invalid universe value.
  522. EXPECT_THROW(
  523. opt_def.optionFactory(Option::V4, D6O_IAADDR, OptionBuffer(option6_iaaddr_len)),
  524. InvalidOptionValue
  525. );
  526. // The length of the buffer must be at least 12 bytes.
  527. // Check too short buffer.
  528. EXPECT_THROW(
  529. opt_def.optionFactory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
  530. InvalidOptionValue
  531. );
  532. }
  533. // The purpose of this test is to verify that definition can be created
  534. // for option that comprises record of data. In this particular test
  535. // the IAADDR option is used. The data for the option is speicifed as
  536. // a vector of strings. Each string carries the data for the corresponding
  537. // data field.
  538. TEST_F(OptionDefinitionTest, recordIAAddr6Tokenized) {
  539. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  540. // valid-lifetime fields (each 4 bytes long).
  541. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  542. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  543. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  544. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  545. // Check the positive scenario.
  546. std::vector<std::string> data_field_values;
  547. data_field_values.push_back("2001:0db8::ff00:0042:8329");
  548. data_field_values.push_back("1234");
  549. data_field_values.push_back("5678");
  550. OptionPtr option_v6;
  551. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR,
  552. data_field_values));
  553. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
  554. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  555. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  556. EXPECT_EQ("2001:db8::ff00:42:8329", option_cast_v6->getAddress().toText());
  557. EXPECT_EQ(1234, option_cast_v6->getPreferred());
  558. EXPECT_EQ(5678, option_cast_v6->getValid());
  559. // This should work for DHCPv6 only, try passing in\valid universe value.
  560. EXPECT_THROW(
  561. opt_def.optionFactory(Option::V4, D6O_IAADDR, data_field_values),
  562. InvalidOptionValue
  563. );
  564. }
  565. // The purpose of this test is to verify that definition for option that
  566. // comprises single uint8 value can be created and that this definition
  567. // can be used to create an option with single uint8 value.
  568. TEST_F(OptionDefinitionTest, uint8) {
  569. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  570. OptionPtr option_v6;
  571. // Try to use correct buffer length = 1 byte.
  572. ASSERT_NO_THROW(
  573. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
  574. );
  575. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
  576. // Validate the value.
  577. boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
  578. boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
  579. EXPECT_EQ(1, option_cast_v6->getValue());
  580. // Try to provide zero-length buffer. Expect exception.
  581. EXPECT_THROW(
  582. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
  583. InvalidOptionValue
  584. );
  585. // @todo Add more cases for DHCPv4
  586. }
  587. // The purpose of this test is to verify that definition for option that
  588. // comprises single uint8 value can be created and that this definition
  589. // can be used to create an option with single uint8 value.
  590. TEST_F(OptionDefinitionTest, uint8Tokenized) {
  591. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  592. OptionPtr option_v6;
  593. std::vector<std::string> values;
  594. values.push_back("123");
  595. values.push_back("456");
  596. try {
  597. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
  598. } catch (std::exception& ex) {
  599. std::cout << ex.what() << std::endl;
  600. }
  601. ASSERT_NO_THROW(
  602. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
  603. );
  604. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
  605. // Validate the value.
  606. boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
  607. boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
  608. EXPECT_EQ(123, option_cast_v6->getValue());
  609. // @todo Add more cases for DHCPv4
  610. }
  611. // The purpose of this test is to verify that definition for option that
  612. // comprises single uint16 value can be created and that this definition
  613. // can be used to create an option with single uint16 value.
  614. TEST_F(OptionDefinitionTest, uint16) {
  615. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  616. OptionPtr option_v6;
  617. // Try to use correct buffer length = 2 bytes.
  618. OptionBuffer buf;
  619. buf.push_back(1);
  620. buf.push_back(2);
  621. ASSERT_NO_THROW(
  622. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, buf);
  623. );
  624. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
  625. // Validate the value.
  626. boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
  627. boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
  628. EXPECT_EQ(0x0102, option_cast_v6->getValue());
  629. // Try to provide zero-length buffer. Expect exception.
  630. EXPECT_THROW(
  631. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
  632. InvalidOptionValue
  633. );
  634. // @todo Add more cases for DHCPv4
  635. }
  636. // The purpose of this test is to verify that definition for option that
  637. // comprises single uint16 value can be created and that this definition
  638. // can be used to create an option with single uint16 value.
  639. TEST_F(OptionDefinitionTest, uint16Tokenized) {
  640. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  641. OptionPtr option_v6;
  642. std::vector<std::string> values;
  643. values.push_back("1234");
  644. values.push_back("5678");
  645. ASSERT_NO_THROW(
  646. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, values);
  647. );
  648. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
  649. // Validate the value.
  650. boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
  651. boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
  652. EXPECT_EQ(1234, option_cast_v6->getValue());
  653. // @todo Add more cases for DHCPv4
  654. }
  655. // The purpose of this test is to verify that definition for option that
  656. // comprises single uint32 value can be created and that this definition
  657. // can be used to create an option with single uint32 value.
  658. TEST_F(OptionDefinitionTest, uint32) {
  659. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  660. OptionPtr option_v6;
  661. OptionBuffer buf;
  662. buf.push_back(1);
  663. buf.push_back(2);
  664. buf.push_back(3);
  665. buf.push_back(4);
  666. ASSERT_NO_THROW(
  667. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, buf);
  668. );
  669. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
  670. // Validate the value.
  671. boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
  672. boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
  673. EXPECT_EQ(0x01020304, option_cast_v6->getValue());
  674. // Try to provide too short buffer. Expect exception.
  675. EXPECT_THROW(
  676. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
  677. InvalidOptionValue
  678. );
  679. // @todo Add more cases for DHCPv4
  680. }
  681. // The purpose of this test is to verify that definition for option that
  682. // comprises single uint32 value can be created and that this definition
  683. // can be used to create an option with single uint32 value.
  684. TEST_F(OptionDefinitionTest, uint32Tokenized) {
  685. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  686. OptionPtr option_v6;
  687. std::vector<std::string> values;
  688. values.push_back("123456");
  689. values.push_back("789");
  690. ASSERT_NO_THROW(
  691. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, values);
  692. );
  693. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
  694. // Validate the value.
  695. boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
  696. boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
  697. EXPECT_EQ(123456, option_cast_v6->getValue());
  698. // @todo Add more cases for DHCPv4
  699. }
  700. // The purpose of this test is to verify that definition for option that
  701. // comprises array of uint16 values can be created and that this definition
  702. // can be used to create option with an array of uint16 values.
  703. TEST_F(OptionDefinitionTest, uint16Array) {
  704. // Let's define some dummy option.
  705. const uint16_t opt_code = 79;
  706. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  707. OptionPtr option_v6;
  708. // Positive scenario, initiate the buffer with length being
  709. // multiple of uint16_t size.
  710. // buffer elements will be: 0x112233.
  711. OptionBuffer buf(6);
  712. for (int i = 0; i < 6; ++i) {
  713. buf[i] = i / 2;
  714. }
  715. // Constructor should succeed because buffer has correct size.
  716. EXPECT_NO_THROW(
  717. option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
  718. );
  719. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
  720. boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
  721. boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
  722. // Get the values from the initiated options and validate.
  723. std::vector<uint16_t> values = option_cast_v6->getValues();
  724. for (int i = 0; i < values.size(); ++i) {
  725. // Expected value is calculated using on the same pattern
  726. // as the one we used to initiate buffer:
  727. // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
  728. uint16_t expected = (i << 8) | i;
  729. EXPECT_EQ(expected, values[i]);
  730. }
  731. // Provided buffer size must be greater than zero. Check if we
  732. // get exception if we provide zero-length buffer.
  733. EXPECT_THROW(
  734. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer()),
  735. InvalidOptionValue
  736. );
  737. // Buffer length must be multiple of data type size.
  738. EXPECT_THROW(
  739. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer(5)),
  740. InvalidOptionValue
  741. );
  742. }
  743. // The purpose of this test is to verify that definition for option that
  744. // comprises array of uint16 values can be created and that this definition
  745. // can be used to create option with an array of uint16 values.
  746. TEST_F(OptionDefinitionTest, uint16ArrayTokenized) {
  747. // Let's define some dummy option.
  748. const uint16_t opt_code = 79;
  749. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  750. OptionPtr option_v6;
  751. std::vector<std::string> str_values;
  752. str_values.push_back("12345");
  753. str_values.push_back("5679");
  754. str_values.push_back("12");
  755. EXPECT_NO_THROW(
  756. option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
  757. );
  758. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
  759. boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
  760. boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
  761. // Get the values from the initiated options and validate.
  762. std::vector<uint16_t> values = option_cast_v6->getValues();
  763. EXPECT_EQ(12345, values[0]);
  764. EXPECT_EQ(5679, values[1]);
  765. EXPECT_EQ(12, values[2]);
  766. }
  767. // The purpose of this test is to verify that definition for option that
  768. // comprises array of uint32 values can be created and that this definition
  769. // can be used to create option with an array of uint32 values.
  770. TEST_F(OptionDefinitionTest, uint32Array) {
  771. // Let's define some dummy option.
  772. const uint16_t opt_code = 80;
  773. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  774. OptionPtr option_v6;
  775. // Positive scenario, initiate the buffer with length being
  776. // multiple of uint16_t size.
  777. // buffer elements will be: 0x111122223333.
  778. OptionBuffer buf(12);
  779. for (int i = 0; i < buf.size(); ++i) {
  780. buf[i] = i / 4;
  781. }
  782. // Constructor should succeed because buffer has correct size.
  783. EXPECT_NO_THROW(
  784. option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
  785. );
  786. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
  787. boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
  788. boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
  789. // Get the values from the initiated options and validate.
  790. std::vector<uint32_t> values = option_cast_v6->getValues();
  791. for (int i = 0; i < values.size(); ++i) {
  792. // Expected value is calculated using on the same pattern
  793. // as the one we used to initiate buffer:
  794. // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
  795. uint32_t expected = 0x01010101 * i;
  796. EXPECT_EQ(expected, values[i]);
  797. }
  798. // Provided buffer size must be greater than zero. Check if we
  799. // get exception if we provide zero-length buffer.
  800. EXPECT_THROW(
  801. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer()),
  802. InvalidOptionValue
  803. );
  804. // Buffer length must be multiple of data type size.
  805. EXPECT_THROW(
  806. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer(5)),
  807. InvalidOptionValue
  808. );
  809. }
  810. // The purpose of this test is to verify that definition for option that
  811. // comprises array of uint32 values can be created and that this definition
  812. // can be used to create option with an array of uint32 values.
  813. TEST_F(OptionDefinitionTest, uint32ArrayTokenized) {
  814. // Let's define some dummy option.
  815. const uint16_t opt_code = 80;
  816. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  817. OptionPtr option_v6;
  818. std::vector<std::string> str_values;
  819. str_values.push_back("123456");
  820. str_values.push_back("7");
  821. str_values.push_back("256");
  822. str_values.push_back("1111");
  823. EXPECT_NO_THROW(
  824. option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
  825. );
  826. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
  827. boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
  828. boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
  829. // Get the values from the initiated options and validate.
  830. std::vector<uint32_t> values = option_cast_v6->getValues();
  831. EXPECT_EQ(123456, values[0]);
  832. EXPECT_EQ(7, values[1]);
  833. EXPECT_EQ(256, values[2]);
  834. EXPECT_EQ(1111, values[3]);
  835. }
  836. // The purpose of this test is to verify that the definition can be created
  837. // for the option that comprises string value in the UTF8 format.
  838. TEST_F(OptionDefinitionTest, utf8StringTokenized) {
  839. // Let's create some dummy option.
  840. const uint16_t opt_code = 80;
  841. OptionDefinition opt_def("OPTION_WITH_STRING", opt_code, "string");
  842. std::vector<std::string> values;
  843. values.push_back("Hello World");
  844. values.push_back("this string should not be included in the option");
  845. OptionPtr option_v6;
  846. EXPECT_NO_THROW(
  847. option_v6 = opt_def.optionFactory(Option::V6, opt_code, values);
  848. );
  849. ASSERT_TRUE(option_v6);
  850. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  851. std::vector<uint8_t> data = option_v6->getData();
  852. std::vector<uint8_t> ref_data(values[0].c_str(), values[0].c_str()
  853. + values[0].length());
  854. EXPECT_TRUE(std::equal(ref_data.begin(), ref_data.end(), data.begin()));
  855. }
  856. // The purpose of this test is to check that non-integer data type can't
  857. // be used for factoryInteger function.
  858. TEST_F(OptionDefinitionTest, integerInvalidType) {
  859. // The template function factoryInteger<> accepts integer values only
  860. // as template typename. Here we try passing different type and
  861. // see if it rejects it.
  862. OptionBuffer buf(1);
  863. EXPECT_THROW(
  864. OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE,
  865. buf.begin(), buf.end()),
  866. isc::dhcp::InvalidDataType
  867. );
  868. }
  869. // The purpose of this test is to verify that helper methods
  870. // haveIA6Format and haveIAAddr6Format can be used to determine
  871. // IA_NA and IAADDR option formats.
  872. TEST_F(OptionDefinitionTest, recognizeFormat) {
  873. // IA_NA option format.
  874. OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
  875. for (int i = 0; i < 3; ++i) {
  876. opt_def1.addRecordField("uint32");
  877. }
  878. EXPECT_TRUE(opt_def1.haveIA6Format());
  879. // Create non-matching format to check that this function does not
  880. // return 'true' all the time.
  881. OptionDefinition opt_def2("OPTION_IA_NA", D6O_IA_NA, "uint16");
  882. EXPECT_FALSE(opt_def2.haveIA6Format());
  883. // IAADDR option format.
  884. OptionDefinition opt_def3("OPTION_IAADDR", D6O_IAADDR, "record");
  885. opt_def3.addRecordField("ipv6-address");
  886. opt_def3.addRecordField("uint32");
  887. opt_def3.addRecordField("uint32");
  888. EXPECT_TRUE(opt_def3.haveIAAddr6Format());
  889. // Create non-matching format to check that this function does not
  890. // return 'true' all the time.
  891. OptionDefinition opt_def4("OPTION_IAADDR", D6O_IAADDR, "uint32", true);
  892. EXPECT_FALSE(opt_def4.haveIAAddr6Format());
  893. }
  894. } // anonymous namespace