option_definition_unittest.cc 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. // Copyright (C) 2012-2014 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/option_custom.h>
  23. #include <dhcp/option_definition.h>
  24. #include <dhcp/option_int.h>
  25. #include <dhcp/option_int_array.h>
  26. #include <dhcp/option_string.h>
  27. #include <exceptions/exceptions.h>
  28. #include <boost/pointer_cast.hpp>
  29. #include <boost/shared_ptr.hpp>
  30. #include <gtest/gtest.h>
  31. using namespace std;
  32. using namespace isc;
  33. using namespace isc::dhcp;
  34. using namespace isc::util;
  35. namespace {
  36. /// @brief OptionDefinition test class.
  37. ///
  38. /// This class does not do anything useful but we keep
  39. /// it around for the future.
  40. class OptionDefinitionTest : public ::testing::Test {
  41. public:
  42. // @brief Constructor.
  43. OptionDefinitionTest() { }
  44. };
  45. // The purpose of this test is to verify that OptionDefinition
  46. // constructor initializes its members correctly.
  47. TEST_F(OptionDefinitionTest, constructor) {
  48. // Specify the option data type as string. This should get converted
  49. // to enum value returned by getType().
  50. OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "string");
  51. EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
  52. EXPECT_EQ(1, opt_def1.getCode());
  53. EXPECT_EQ(OPT_STRING_TYPE, opt_def1.getType());
  54. EXPECT_FALSE(opt_def1.getArrayType());
  55. EXPECT_TRUE(opt_def1.getEncapsulatedSpace().empty());
  56. EXPECT_NO_THROW(opt_def1.validate());
  57. // Specify the option data type as an enum value.
  58. OptionDefinition opt_def2("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT,
  59. OPT_EMPTY_TYPE);
  60. EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
  61. EXPECT_EQ(14, opt_def2.getCode());
  62. EXPECT_EQ(OPT_EMPTY_TYPE, opt_def2.getType());
  63. EXPECT_FALSE(opt_def2.getArrayType());
  64. EXPECT_TRUE(opt_def2.getEncapsulatedSpace().empty());
  65. EXPECT_NO_THROW(opt_def2.validate());
  66. // Specify encapsulated option space name and option data type
  67. // as enum value.
  68. OptionDefinition opt_def3("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
  69. OPT_UINT32_TYPE, "isc");
  70. EXPECT_EQ("OPTION_VENDOR_OPTS", opt_def3.getName());
  71. EXPECT_EQ(D6O_VENDOR_OPTS, opt_def3.getCode());
  72. EXPECT_EQ(OPT_UINT32_TYPE, opt_def3.getType());
  73. EXPECT_FALSE(opt_def3.getArrayType());
  74. EXPECT_EQ("isc", opt_def3.getEncapsulatedSpace());
  75. EXPECT_NO_THROW(opt_def3.validate());
  76. // Specify encapsulated option space name and option data type
  77. // as string value.
  78. OptionDefinition opt_def4("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
  79. "uint32", "isc");
  80. EXPECT_EQ("OPTION_VENDOR_OPTS", opt_def4.getName());
  81. EXPECT_EQ(D6O_VENDOR_OPTS, opt_def4.getCode());
  82. EXPECT_EQ(OPT_UINT32_TYPE, opt_def4.getType());
  83. EXPECT_FALSE(opt_def4.getArrayType());
  84. EXPECT_EQ("isc", opt_def4.getEncapsulatedSpace());
  85. EXPECT_NO_THROW(opt_def4.validate());
  86. // Check if it is possible to set that option is an array.
  87. OptionDefinition opt_def5("OPTION_NIS_SERVERS", 27,
  88. OPT_IPV6_ADDRESS_TYPE,
  89. true);
  90. EXPECT_EQ("OPTION_NIS_SERVERS", opt_def5.getName());
  91. EXPECT_EQ(27, opt_def5.getCode());
  92. EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, opt_def5.getType());
  93. EXPECT_TRUE(opt_def5.getArrayType());
  94. EXPECT_NO_THROW(opt_def5.validate());
  95. // The created object is invalid if invalid data type is specified but
  96. // constructor shouldn't throw exception. The object is validated after
  97. // it has been created.
  98. EXPECT_NO_THROW(
  99. OptionDefinition opt_def6("OPTION_SERVERID",
  100. OPT_UNKNOWN_TYPE + 10,
  101. OPT_STRING_TYPE);
  102. );
  103. }
  104. // This test checks that the copy constructor works properly.
  105. TEST_F(OptionDefinitionTest, copyConstructor) {
  106. OptionDefinition opt_def("option-foo", 27, "record", true);
  107. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  108. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  109. OptionDefinition opt_def_copy(opt_def);
  110. EXPECT_EQ("option-foo", opt_def_copy.getName());
  111. EXPECT_EQ(27, opt_def_copy.getCode());
  112. EXPECT_TRUE(opt_def_copy.getArrayType());
  113. EXPECT_TRUE(opt_def_copy.getEncapsulatedSpace().empty());
  114. const OptionDefinition::RecordFieldsCollection fields =
  115. opt_def_copy.getRecordFields();
  116. ASSERT_EQ(2, fields.size());
  117. EXPECT_EQ(OPT_UINT16_TYPE, fields[0]);
  118. EXPECT_EQ(OPT_STRING_TYPE, fields[1]);
  119. }
  120. // This test checks that two option definitions may be compared fot equality.
  121. TEST_F(OptionDefinitionTest, equality) {
  122. // Equal definitions.
  123. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  124. == OptionDefinition("option-foo", 5, "uint16", false));
  125. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  126. != OptionDefinition("option-foo", 5, "uint16", false));
  127. // Differ by name.
  128. EXPECT_FALSE(OptionDefinition("option-bar", 5, "uint16", false)
  129. == OptionDefinition("option-foo", 5, "uint16", false));
  130. EXPECT_TRUE(OptionDefinition("option-bar", 5, "uint16", false)
  131. != OptionDefinition("option-foo", 5, "uint16", false));
  132. // Differ by option code.
  133. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  134. == OptionDefinition("option-foo", 6, "uint16", false));
  135. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  136. != OptionDefinition("option-foo", 6, "uint16", false));
  137. // Differ by type of the data.
  138. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  139. == OptionDefinition("option-foo", 5, "uint32", false));
  140. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  141. != OptionDefinition("option-foo", 5, "uint32", false));
  142. // Differ by array-type property.
  143. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  144. == OptionDefinition("option-foo", 5, "uint16", true));
  145. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  146. != OptionDefinition("option-foo", 5, "uint16", true));
  147. // Differ by record fields.
  148. OptionDefinition def1("option-foo", 5, "record");
  149. OptionDefinition def2("option-foo", 5, "record");
  150. // There are no record fields specified yet, so initially they have
  151. // to be equal.
  152. ASSERT_TRUE(def1 == def2);
  153. ASSERT_FALSE(def1 != def2);
  154. // Add some record fields.
  155. ASSERT_NO_THROW(def1.addRecordField("uint16"));
  156. ASSERT_NO_THROW(def2.addRecordField("uint16"));
  157. // Definitions should still remain equal.
  158. ASSERT_TRUE(def1 == def2);
  159. ASSERT_FALSE(def1 != def2);
  160. // Add additional record field to one of the definitions but not the
  161. // other. They should now be unequal.
  162. ASSERT_NO_THROW(def1.addRecordField("string"));
  163. ASSERT_FALSE(def1 == def2);
  164. ASSERT_TRUE(def1 != def2);
  165. // Add the same record field to the other definition. They should now
  166. // be equal again.
  167. ASSERT_NO_THROW(def2.addRecordField("string"));
  168. EXPECT_TRUE(def1 == def2);
  169. EXPECT_FALSE(def1 != def2);
  170. }
  171. // The purpose of this test is to verify that various data fields
  172. // can be specified for an option definition when this definition
  173. // is marked as 'record' and that fields can't be added if option
  174. // definition is not marked as 'record'.
  175. TEST_F(OptionDefinitionTest, addRecordField) {
  176. // We can only add fields to record if the option type has been
  177. // specified as 'record'. We try all other types but 'record'
  178. // here and expect exception to be thrown.
  179. for (int i = 0; i < OPT_UNKNOWN_TYPE; ++i) {
  180. // Do not try for 'record' type because this is the only
  181. // type for which adding record will succeed.
  182. if (i == OPT_RECORD_TYPE) {
  183. continue;
  184. }
  185. OptionDefinition opt_def("OPTION_IAADDR", 5,
  186. static_cast<OptionDataType>(i));
  187. EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
  188. }
  189. // Positive scenario starts here.
  190. OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
  191. EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  192. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  193. // It should not matter if we specify field type by its name or using enum.
  194. EXPECT_NO_THROW(opt_def.addRecordField(OPT_UINT32_TYPE));
  195. // Check what we have actually added.
  196. OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
  197. ASSERT_EQ(3, fields.size());
  198. EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, fields[0]);
  199. EXPECT_EQ(OPT_UINT32_TYPE, fields[1]);
  200. EXPECT_EQ(OPT_UINT32_TYPE, fields[2]);
  201. // Let's try some more negative scenarios: use invalid data types.
  202. EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
  203. OptionDataType invalid_type =
  204. static_cast<OptionDataType>(OPT_UNKNOWN_TYPE + 10);
  205. EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
  206. // It is bad if we use 'record' option type but don't specify
  207. // at least two fields.
  208. OptionDefinition opt_def2("OPTION_EMPTY_RECORD", 100, "record");
  209. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  210. opt_def2.addRecordField("uint8");
  211. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  212. opt_def2.addRecordField("uint32");
  213. EXPECT_NO_THROW(opt_def2.validate());
  214. }
  215. // The purpose of this test is to check that validate() function
  216. // reports errors for invalid option definitions.
  217. TEST_F(OptionDefinitionTest, validate) {
  218. // Not supported option type string is not allowed.
  219. OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
  220. EXPECT_THROW(opt_def1.validate(), MalformedOptionDefinition);
  221. // Not supported option type enum value is not allowed.
  222. OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OPT_UNKNOWN_TYPE);
  223. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  224. OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
  225. static_cast<OptionDataType>(OPT_UNKNOWN_TYPE
  226. + 2));
  227. EXPECT_THROW(opt_def3.validate(), MalformedOptionDefinition);
  228. // Empty option name is not allowed.
  229. OptionDefinition opt_def4("", D6O_CLIENTID, "string");
  230. EXPECT_THROW(opt_def4.validate(), MalformedOptionDefinition);
  231. // Option name must not contain spaces.
  232. OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
  233. EXPECT_THROW(opt_def5.validate(), MalformedOptionDefinition);
  234. // Option name must not contain spaces.
  235. OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string");
  236. EXPECT_THROW(opt_def6.validate(), MalformedOptionDefinition);
  237. // Option name may contain lower case letters.
  238. OptionDefinition opt_def7("option_clientid", D6O_CLIENTID, "string");
  239. EXPECT_NO_THROW(opt_def7.validate());
  240. // Using digits in option name is legal.
  241. OptionDefinition opt_def8("option_123", D6O_CLIENTID, "string");
  242. EXPECT_NO_THROW(opt_def8.validate());
  243. // Using hyphen is legal.
  244. OptionDefinition opt_def9("option-clientid", D6O_CLIENTID, "string");
  245. EXPECT_NO_THROW(opt_def9.validate());
  246. // Using hyphen or undescore at the beginning or at the end
  247. // of the option name is not allowed.
  248. OptionDefinition opt_def10("-option-clientid", D6O_CLIENTID, "string");
  249. EXPECT_THROW(opt_def10.validate(), MalformedOptionDefinition);
  250. OptionDefinition opt_def11("_option-clientid", D6O_CLIENTID, "string");
  251. EXPECT_THROW(opt_def11.validate(), MalformedOptionDefinition);
  252. OptionDefinition opt_def12("option-clientid_", D6O_CLIENTID, "string");
  253. EXPECT_THROW(opt_def12.validate(), MalformedOptionDefinition);
  254. OptionDefinition opt_def13("option-clientid-", D6O_CLIENTID, "string");
  255. EXPECT_THROW(opt_def13.validate(), MalformedOptionDefinition);
  256. // Having array of strings does not make sense because there is no way
  257. // to determine string's length.
  258. OptionDefinition opt_def14("OPTION_CLIENTID", D6O_CLIENTID, "string", true);
  259. EXPECT_THROW(opt_def14.validate(), MalformedOptionDefinition);
  260. // It does not make sense to have string field within the record before
  261. // other fields because there is no way to determine the length of this
  262. // string and thus there is no way to determine where the other field
  263. // begins.
  264. OptionDefinition opt_def15("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  265. "record");
  266. opt_def15.addRecordField("string");
  267. opt_def15.addRecordField("uint16");
  268. EXPECT_THROW(opt_def15.validate(), MalformedOptionDefinition);
  269. // ... but it is ok if the string value is the last one.
  270. OptionDefinition opt_def16("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  271. "record");
  272. opt_def16.addRecordField("uint8");
  273. opt_def16.addRecordField("string");
  274. // Check invalid encapsulated option space name.
  275. OptionDefinition opt_def17("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
  276. "uint32", "invalid%space%name");
  277. EXPECT_THROW(opt_def17.validate(), MalformedOptionDefinition);
  278. }
  279. // The purpose of this test is to verify that option definition
  280. // that comprises array of IPv6 addresses will return an instance
  281. // of option with a list of IPv6 addresses.
  282. TEST_F(OptionDefinitionTest, ipv6AddressArray) {
  283. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  284. "ipv6-address", true);
  285. // Create a list of some V6 addresses.
  286. std::vector<asiolink::IOAddress> addrs;
  287. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  288. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  289. addrs.push_back(asiolink::IOAddress("::1"));
  290. addrs.push_back(asiolink::IOAddress("::2"));
  291. // Write addresses to the buffer.
  292. OptionBuffer buf(addrs.size() * asiolink::V6ADDRESS_LEN);
  293. for (int i = 0; i < addrs.size(); ++i) {
  294. const std::vector<uint8_t>& vec = addrs[i].toBytes();
  295. ASSERT_EQ(asiolink::V6ADDRESS_LEN, vec.size());
  296. std::copy(vec.begin(), vec.end(),
  297. buf.begin() + i * asiolink::V6ADDRESS_LEN);
  298. }
  299. // Create DHCPv6 option from this buffer. Once option is created it is
  300. // supposed to have internal list of addresses that it parses out from
  301. // the provided buffer.
  302. OptionPtr option_v6;
  303. ASSERT_NO_THROW(
  304. option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS, buf);
  305. );
  306. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
  307. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  308. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  309. ASSERT_TRUE(option_cast_v6);
  310. // Get the list of parsed addresses from the option object.
  311. std::vector<asiolink::IOAddress> addrs_returned =
  312. option_cast_v6->getAddresses();
  313. // The list of addresses must exactly match addresses that we
  314. // stored in the buffer to create the option from it.
  315. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  316. // The provided buffer's length must be a multiple of V6 address length.
  317. // Let's extend the buffer by one byte so as this condition is not
  318. // fulfilled anymore.
  319. buf.insert(buf.end(), 1, 1);
  320. // It should throw exception then.
  321. EXPECT_THROW(
  322. opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS, buf),
  323. InvalidOptionValue
  324. );
  325. }
  326. // The purpose of this test is to verify that option definition
  327. // that comprises array of IPv6 addresses will return an instance
  328. // of option with a list of IPv6 addresses. Array of IPv6 addresses
  329. // is specified as a vector of strings (each string represents single
  330. // IPv6 address).
  331. TEST_F(OptionDefinitionTest, ipv6AddressArrayTokenized) {
  332. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  333. "ipv6-address", true);
  334. // Create a vector of some V6 addresses.
  335. std::vector<asiolink::IOAddress> addrs;
  336. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  337. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  338. addrs.push_back(asiolink::IOAddress("::1"));
  339. addrs.push_back(asiolink::IOAddress("::2"));
  340. // Create a vector of strings representing addresses given above.
  341. std::vector<std::string> addrs_str;
  342. for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
  343. it != addrs.end(); ++it) {
  344. addrs_str.push_back(it->toText());
  345. }
  346. // Create DHCPv6 option using the list of IPv6 addresses given in the
  347. // string form.
  348. OptionPtr option_v6;
  349. ASSERT_NO_THROW(
  350. option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS,
  351. addrs_str);
  352. );
  353. // Non-null pointer option is supposed to be returned and it
  354. // should have Option6AddrLst type.
  355. ASSERT_TRUE(option_v6);
  356. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6AddrLst));
  357. // Cast to the actual option type to get IPv6 addresses from it.
  358. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  359. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  360. // Check that cast was successful.
  361. ASSERT_TRUE(option_cast_v6);
  362. // Get the list of parsed addresses from the option object.
  363. std::vector<asiolink::IOAddress> addrs_returned =
  364. option_cast_v6->getAddresses();
  365. // Returned addresses must match the addresses that have been used to create
  366. // the option instance.
  367. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  368. }
  369. // The purpose of this test is to verify that option definition
  370. // that comprises array of IPv4 addresses will return an instance
  371. // of option with a list of IPv4 addresses.
  372. TEST_F(OptionDefinitionTest, ipv4AddressArray) {
  373. OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
  374. "ipv4-address", true);
  375. // Create a list of some V6 addresses.
  376. std::vector<asiolink::IOAddress> addrs;
  377. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  378. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  379. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  380. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  381. // Write addresses to the buffer.
  382. OptionBuffer buf(addrs.size() * asiolink::V4ADDRESS_LEN);
  383. for (int i = 0; i < addrs.size(); ++i) {
  384. const std::vector<uint8_t> vec = addrs[i].toBytes();
  385. ASSERT_EQ(asiolink::V4ADDRESS_LEN, vec.size());
  386. std::copy(vec.begin(), vec.end(),
  387. buf.begin() + i * asiolink::V4ADDRESS_LEN);
  388. }
  389. // Create DHCPv6 option from this buffer. Once option is created it is
  390. // supposed to have internal list of addresses that it parses out from
  391. // the provided buffer.
  392. OptionPtr option_v4;
  393. ASSERT_NO_THROW(
  394. option_v4 = opt_def.optionFactory(Option::V4, DHO_NAME_SERVERS, buf)
  395. );
  396. ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
  397. // Get the list of parsed addresses from the option object.
  398. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  399. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  400. std::vector<asiolink::IOAddress> addrs_returned =
  401. option_cast_v4->getAddresses();
  402. // The list of addresses must exactly match addresses that we
  403. // stored in the buffer to create the option from it.
  404. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  405. // The provided buffer's length must be a multiple of V4 address length.
  406. // Let's extend the buffer by one byte so as this condition is not
  407. // fulfilled anymore.
  408. buf.insert(buf.end(), 1, 1);
  409. // It should throw exception then.
  410. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS, buf),
  411. InvalidOptionValue);
  412. }
  413. // The purpose of this test is to verify that option definition
  414. // that comprises array of IPv4 addresses will return an instance
  415. // of option with a list of IPv4 addresses. The array of IPv4 addresses
  416. // is specified as a vector of strings (each string represents single
  417. // IPv4 address).
  418. TEST_F(OptionDefinitionTest, ipv4AddressArrayTokenized) {
  419. OptionDefinition opt_def("OPTION_NIS_SERVERS", DHO_NIS_SERVERS,
  420. "ipv4-address", true);
  421. // Create a vector of some V6 addresses.
  422. std::vector<asiolink::IOAddress> addrs;
  423. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  424. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  425. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  426. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  427. // Create a vector of strings representing addresses given above.
  428. std::vector<std::string> addrs_str;
  429. for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
  430. it != addrs.end(); ++it) {
  431. addrs_str.push_back(it->toText());
  432. }
  433. // Create DHCPv4 option using the list of IPv4 addresses given in the
  434. // string form.
  435. OptionPtr option_v4;
  436. ASSERT_NO_THROW(
  437. option_v4 = opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS,
  438. addrs_str);
  439. );
  440. // Non-null pointer option is supposed to be returned and it
  441. // should have Option6AddrLst type.
  442. ASSERT_TRUE(option_v4);
  443. ASSERT_TRUE(typeid(*option_v4) == typeid(Option4AddrLst));
  444. // Cast to the actual option type to get IPv4 addresses from it.
  445. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  446. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  447. // Check that cast was successful.
  448. ASSERT_TRUE(option_cast_v4);
  449. // Get the list of parsed addresses from the option object.
  450. std::vector<asiolink::IOAddress> addrs_returned =
  451. option_cast_v4->getAddresses();
  452. // Returned addresses must match the addresses that have been used to create
  453. // the option instance.
  454. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  455. }
  456. // The purpose of this test is to verify that option definition for
  457. // 'empty' option can be created and that it returns 'empty' option.
  458. TEST_F(OptionDefinitionTest, empty) {
  459. OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
  460. // Create option instance and provide empty buffer as expected.
  461. OptionPtr option_v6;
  462. ASSERT_NO_THROW(
  463. option_v6 = opt_def.optionFactory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
  464. );
  465. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  466. // Expect 'empty' DHCPv6 option.
  467. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  468. EXPECT_EQ(4, option_v6->getHeaderLen());
  469. EXPECT_EQ(0, option_v6->getData().size());
  470. // Repeat the same test scenario for DHCPv4 option.
  471. OptionPtr option_v4;
  472. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, OptionBuffer()));
  473. // Expect 'empty' DHCPv4 option.
  474. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  475. EXPECT_EQ(2, option_v4->getHeaderLen());
  476. EXPECT_EQ(0, option_v4->getData().size());
  477. }
  478. // The purpose of this test is to verify that when the empty option encapsulates
  479. // some option space, an instance of the OptionCustom is returned and its
  480. // suboptions are decoded.
  481. TEST_F(OptionDefinitionTest, emptyWithSuboptions) {
  482. // Create an instance of the 'empty' option definition. This option
  483. // encapsulates 'option-foo-space' so when we create a new option
  484. // with this definition the OptionCustom should be returned. The
  485. // Option Custom is generic option which support variety of formats
  486. // and supports decoding suboptions.
  487. OptionDefinition opt_def("option-foo", 1024, "empty", "option-foo-space");
  488. // Define a suboption.
  489. const uint8_t subopt_data[] = {
  490. 0x04, 0x01, // Option code 1025
  491. 0x00, 0x04, // Option len = 4
  492. 0x01, 0x02, 0x03, 0x04 // Option data
  493. };
  494. // Create an option, having option code 1024 from the definition. Pass
  495. // the option buffer containing suboption.
  496. OptionPtr option_v6;
  497. ASSERT_NO_THROW(
  498. option_v6 = opt_def.optionFactory(Option::V6, 1024,
  499. OptionBuffer(subopt_data,
  500. subopt_data +
  501. sizeof(subopt_data)))
  502. );
  503. // Returned option should be of the OptionCustom type.
  504. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionCustom));
  505. // Sanity-check length, universe etc.
  506. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  507. EXPECT_EQ(4, option_v6->getHeaderLen());
  508. // This option should have one suboption with the code of 1025.
  509. OptionPtr subopt_v6 = option_v6->getOption(1025);
  510. EXPECT_TRUE(subopt_v6);
  511. // Check that this suboption holds valid data.
  512. EXPECT_EQ(1025, subopt_v6->getType());
  513. EXPECT_EQ(Option::V6, subopt_v6->getUniverse());
  514. EXPECT_EQ(0, memcmp(&subopt_v6->getData()[0], subopt_data + 4, 4));
  515. // @todo consider having a similar test for V4.
  516. }
  517. // The purpose of this test is to verify that definition can be
  518. // creates for the option that holds binary data.
  519. TEST_F(OptionDefinitionTest, binary) {
  520. // Binary option is the one that is represented by the generic
  521. // Option class. In fact all options can be represented by this
  522. // class but for some of them it is just natural. The SERVERID
  523. // option consists of the option code, length and binary data so
  524. // this one was picked for this test.
  525. OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
  526. // Prepare some dummy data (serverid): 0, 1, 2 etc.
  527. OptionBuffer buf(14);
  528. for (int i = 0; i < 14; ++i) {
  529. buf[i] = i;
  530. }
  531. // Create option instance with the factory function.
  532. // If the OptionDefinition code works properly than
  533. // object of the type Option should be returned.
  534. OptionPtr option_v6;
  535. ASSERT_NO_THROW(
  536. option_v6 = opt_def.optionFactory(Option::V6, D6O_SERVERID, buf);
  537. );
  538. // Expect base option type returned.
  539. ASSERT_TRUE(typeid(*option_v6) == typeid(Option));
  540. // Sanity check on universe, length and size. These are
  541. // the basic parameters identifying any option.
  542. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  543. EXPECT_EQ(4, option_v6->getHeaderLen());
  544. ASSERT_EQ(buf.size(), option_v6->getData().size());
  545. // Get the server id data from the option and compare
  546. // against reference buffer. They are expected to match.
  547. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  548. option_v6->getData().end(),
  549. buf.begin()));
  550. // Repeat the same test scenario for DHCPv4 option.
  551. OptionPtr option_v4;
  552. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, buf));
  553. // Expect 'empty' DHCPv4 option.
  554. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  555. EXPECT_EQ(2, option_v4->getHeaderLen());
  556. ASSERT_EQ(buf.size(), option_v4->getData().size());
  557. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  558. option_v6->getData().end(),
  559. buf.begin()));
  560. }
  561. // The purpose of this test is to verify that definition can be created
  562. // for option that comprises record of data. In this particular test
  563. // the IA_NA option is used. This option comprises three uint32 fields.
  564. TEST_F(OptionDefinitionTest, recordIA6) {
  565. // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
  566. const int option6_ia_len = 12;
  567. // Get the factory function pointer.
  568. OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", false);
  569. // Each data field is uint32.
  570. for (int i = 0; i < 3; ++i) {
  571. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  572. }
  573. // Check the positive scenario.
  574. OptionBuffer buf(12);
  575. for (int i = 0; i < buf.size(); ++i) {
  576. buf[i] = i;
  577. }
  578. OptionPtr option_v6;
  579. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IA_NA, buf));
  580. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IA));
  581. boost::shared_ptr<Option6IA> option_cast_v6 =
  582. boost::static_pointer_cast<Option6IA>(option_v6);
  583. EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
  584. EXPECT_EQ(0x04050607, option_cast_v6->getT1());
  585. EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
  586. // The length of the buffer must be at least 12 bytes.
  587. // Check too short buffer.
  588. EXPECT_THROW(
  589. opt_def.optionFactory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
  590. InvalidOptionValue
  591. );
  592. }
  593. // The purpose of this test is to verify that definition can be created
  594. // for option that comprises record of data. In this particular test
  595. // the IAADDR option is used.
  596. TEST_F(OptionDefinitionTest, recordIAAddr6) {
  597. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  598. // valid-lifetime fields (each 4 bytes long).
  599. const int option6_iaaddr_len = 24;
  600. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  601. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  602. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  603. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  604. // Check the positive scenario.
  605. OptionPtr option_v6;
  606. asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
  607. OptionBuffer buf(asiolink::V6ADDRESS_LEN);
  608. ASSERT_TRUE(addr_v6.isV6());
  609. const std::vector<uint8_t>& vec = addr_v6.toBytes();
  610. ASSERT_EQ(asiolink::V6ADDRESS_LEN, vec.size());
  611. std::copy(vec.begin(), vec.end(), buf.begin());
  612. for (int i = 0; i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN; ++i) {
  613. buf.push_back(i);
  614. }
  615. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR, buf));
  616. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
  617. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  618. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  619. EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
  620. EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
  621. EXPECT_EQ(0x04050607, option_cast_v6->getValid());
  622. // The length of the buffer must be at least 12 bytes.
  623. // Check too short buffer.
  624. EXPECT_THROW(
  625. opt_def.optionFactory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
  626. InvalidOptionValue
  627. );
  628. }
  629. // The purpose of this test is to verify that definition can be created
  630. // for option that comprises record of data. In this particular test
  631. // the IAADDR option is used. The data for the option is speicifed as
  632. // a vector of strings. Each string carries the data for the corresponding
  633. // data field.
  634. TEST_F(OptionDefinitionTest, recordIAAddr6Tokenized) {
  635. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  636. // valid-lifetime fields (each 4 bytes long).
  637. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  638. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  639. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  640. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  641. // Check the positive scenario.
  642. std::vector<std::string> data_field_values;
  643. data_field_values.push_back("2001:0db8::ff00:0042:8329");
  644. data_field_values.push_back("1234");
  645. data_field_values.push_back("5678");
  646. OptionPtr option_v6;
  647. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR,
  648. data_field_values));
  649. ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IAAddr));
  650. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  651. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  652. EXPECT_EQ("2001:db8::ff00:42:8329", option_cast_v6->getAddress().toText());
  653. EXPECT_EQ(1234, option_cast_v6->getPreferred());
  654. EXPECT_EQ(5678, option_cast_v6->getValid());
  655. }
  656. // The purpose of this test is to verify that the definition for option
  657. // that comprises a boolean value can be created and that this definition
  658. // can be used to create and option with a single boolean value.
  659. TEST_F(OptionDefinitionTest, boolValue) {
  660. // The IP Forwarding option comprises one boolean value.
  661. OptionDefinition opt_def("ip-forwarding", DHO_IP_FORWARDING,
  662. "boolean");
  663. OptionPtr option_v4;
  664. // Use an option buffer which holds one value of 1 (true).
  665. ASSERT_NO_THROW(
  666. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  667. OptionBuffer(1, 1));
  668. );
  669. ASSERT_TRUE(typeid(*option_v4) == typeid(OptionCustom));
  670. // Validate parsed value in the received option.
  671. boost::shared_ptr<OptionCustom> option_cast_v4 =
  672. boost::static_pointer_cast<OptionCustom>(option_v4);
  673. EXPECT_TRUE(option_cast_v4->readBoolean());
  674. // Repeat the test above, but set the value to 0 (false).
  675. ASSERT_NO_THROW(
  676. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  677. OptionBuffer(1, 0));
  678. );
  679. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  680. EXPECT_FALSE(option_cast_v4->readBoolean());
  681. // Try to provide zero-length buffer. Expect exception.
  682. EXPECT_THROW(
  683. opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING, OptionBuffer()),
  684. InvalidOptionValue
  685. );
  686. }
  687. // The purpose of this test is to verify that definition for option that
  688. // comprises single boolean value can be created and that this definition
  689. // can be used to create an option holding a single boolean value. The
  690. // boolean value is converted from a string which is expected to hold
  691. // the following values: "true", "false", "1" or "0". For all other
  692. // values exception should be thrown.
  693. TEST_F(OptionDefinitionTest, boolTokenized) {
  694. OptionDefinition opt_def("ip-forwarding", DHO_IP_FORWARDING, "boolean");
  695. OptionPtr option_v4;
  696. std::vector<std::string> values;
  697. // Specify a value for the option instance being created.
  698. values.push_back("true");
  699. ASSERT_NO_THROW(
  700. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  701. values);
  702. );
  703. ASSERT_TRUE(typeid(*option_v4) == typeid(OptionCustom));
  704. // Validate the value.
  705. OptionCustomPtr option_cast_v4 =
  706. boost::static_pointer_cast<OptionCustom>(option_v4);
  707. EXPECT_TRUE(option_cast_v4->readBoolean());
  708. // Repeat the test but for "false" value this time.
  709. values[0] = "false";
  710. ASSERT_NO_THROW(
  711. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  712. values);
  713. );
  714. ASSERT_TRUE(typeid(*option_v4) == typeid(OptionCustom));
  715. // Validate the value.
  716. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  717. EXPECT_FALSE(option_cast_v4->readBoolean());
  718. // Check if that will work for numeric values.
  719. values[0] = "0";
  720. ASSERT_NO_THROW(
  721. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  722. values);
  723. );
  724. ASSERT_TRUE(typeid(*option_v4) == typeid(OptionCustom));
  725. // Validate the value.
  726. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  727. EXPECT_FALSE(option_cast_v4->readBoolean());
  728. // Swap numeric values and test if it works for "true" case.
  729. values[0] = "1";
  730. ASSERT_NO_THROW(
  731. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  732. values);
  733. );
  734. ASSERT_TRUE(typeid(*option_v4) == typeid(OptionCustom));
  735. // Validate the value.
  736. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  737. EXPECT_TRUE(option_cast_v4->readBoolean());
  738. // A conversion of non-numeric value to boolean should fail if
  739. // this value is neither "true" nor "false".
  740. values[0] = "garbage";
  741. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING, values),
  742. isc::dhcp::BadDataTypeCast);
  743. // A conversion of numeric value to boolean should fail if this value
  744. // is neither "0" nor "1".
  745. values[0] = "2";
  746. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING, values),
  747. isc::dhcp::BadDataTypeCast);
  748. }
  749. // The purpose of this test is to verify that definition for option that
  750. // comprises single uint8 value can be created and that this definition
  751. // can be used to create an option with single uint8 value.
  752. TEST_F(OptionDefinitionTest, uint8) {
  753. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  754. OptionPtr option_v6;
  755. // Try to use correct buffer length = 1 byte.
  756. ASSERT_NO_THROW(
  757. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE,
  758. OptionBuffer(1, 1));
  759. );
  760. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint8_t>));
  761. // Validate the value.
  762. boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
  763. boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
  764. EXPECT_EQ(1, option_cast_v6->getValue());
  765. // Try to provide zero-length buffer. Expect exception.
  766. EXPECT_THROW(
  767. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
  768. InvalidOptionValue
  769. );
  770. // @todo Add more cases for DHCPv4
  771. }
  772. // The purpose of this test is to verify that definition for option that
  773. // comprises single uint8 value can be created and that this definition
  774. // can be used to create an option with single uint8 value.
  775. TEST_F(OptionDefinitionTest, uint8Tokenized) {
  776. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  777. OptionPtr option_v6;
  778. std::vector<std::string> values;
  779. values.push_back("123");
  780. values.push_back("456");
  781. ASSERT_NO_THROW(
  782. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
  783. );
  784. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint8_t>));
  785. // Validate the value.
  786. boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
  787. boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
  788. EXPECT_EQ(123, option_cast_v6->getValue());
  789. // @todo Add more cases for DHCPv4
  790. }
  791. // The purpose of this test is to verify that definition for option that
  792. // comprises single uint16 value can be created and that this definition
  793. // can be used to create an option with single uint16 value.
  794. TEST_F(OptionDefinitionTest, uint16) {
  795. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  796. OptionPtr option_v6;
  797. // Try to use correct buffer length = 2 bytes.
  798. OptionBuffer buf;
  799. buf.push_back(1);
  800. buf.push_back(2);
  801. ASSERT_NO_THROW(
  802. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, buf);
  803. );
  804. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint16_t>));
  805. // Validate the value.
  806. boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
  807. boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
  808. EXPECT_EQ(0x0102, option_cast_v6->getValue());
  809. // Try to provide zero-length buffer. Expect exception.
  810. EXPECT_THROW(
  811. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
  812. InvalidOptionValue
  813. );
  814. // @todo Add more cases for DHCPv4
  815. }
  816. // The purpose of this test is to verify that definition for option that
  817. // comprises single uint16 value can be created and that this definition
  818. // can be used to create an option with single uint16 value.
  819. TEST_F(OptionDefinitionTest, uint16Tokenized) {
  820. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  821. OptionPtr option_v6;
  822. std::vector<std::string> values;
  823. values.push_back("1234");
  824. values.push_back("5678");
  825. ASSERT_NO_THROW(
  826. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, values);
  827. );
  828. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint16_t>));
  829. // Validate the value.
  830. boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
  831. boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
  832. EXPECT_EQ(1234, option_cast_v6->getValue());
  833. // @todo Add more cases for DHCPv4
  834. }
  835. // The purpose of this test is to verify that definition for option that
  836. // comprises single uint32 value can be created and that this definition
  837. // can be used to create an option with single uint32 value.
  838. TEST_F(OptionDefinitionTest, uint32) {
  839. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  840. OptionPtr option_v6;
  841. OptionBuffer buf;
  842. buf.push_back(1);
  843. buf.push_back(2);
  844. buf.push_back(3);
  845. buf.push_back(4);
  846. ASSERT_NO_THROW(
  847. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, buf);
  848. );
  849. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint32_t>));
  850. // Validate the value.
  851. boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
  852. boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
  853. EXPECT_EQ(0x01020304, option_cast_v6->getValue());
  854. // Try to provide too short buffer. Expect exception.
  855. EXPECT_THROW(
  856. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
  857. InvalidOptionValue
  858. );
  859. // @todo Add more cases for DHCPv4
  860. }
  861. // The purpose of this test is to verify that definition for option that
  862. // comprises single uint32 value can be created and that this definition
  863. // can be used to create an option with single uint32 value.
  864. TEST_F(OptionDefinitionTest, uint32Tokenized) {
  865. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  866. OptionPtr option_v6;
  867. std::vector<std::string> values;
  868. values.push_back("123456");
  869. values.push_back("789");
  870. ASSERT_NO_THROW(
  871. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, values);
  872. );
  873. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint32_t>));
  874. // Validate the value.
  875. boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
  876. boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
  877. EXPECT_EQ(123456, option_cast_v6->getValue());
  878. // @todo Add more cases for DHCPv4
  879. }
  880. // The purpose of this test is to verify that definition for option that
  881. // comprises array of uint16 values can be created and that this definition
  882. // can be used to create option with an array of uint16 values.
  883. TEST_F(OptionDefinitionTest, uint16Array) {
  884. // Let's define some dummy option.
  885. const uint16_t opt_code = 79;
  886. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  887. OptionPtr option_v6;
  888. // Positive scenario, initiate the buffer with length being
  889. // multiple of uint16_t size.
  890. // buffer elements will be: 0x112233.
  891. OptionBuffer buf(6);
  892. for (int i = 0; i < 6; ++i) {
  893. buf[i] = i / 2;
  894. }
  895. // Constructor should succeed because buffer has correct size.
  896. EXPECT_NO_THROW(
  897. option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
  898. );
  899. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint16_t>));
  900. boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
  901. boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
  902. // Get the values from the initiated options and validate.
  903. std::vector<uint16_t> values = option_cast_v6->getValues();
  904. for (int i = 0; i < values.size(); ++i) {
  905. // Expected value is calculated using on the same pattern
  906. // as the one we used to initiate buffer:
  907. // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
  908. uint16_t expected = (i << 8) | i;
  909. EXPECT_EQ(expected, values[i]);
  910. }
  911. // Provided buffer size must be greater than zero. Check if we
  912. // get exception if we provide zero-length buffer.
  913. EXPECT_THROW(
  914. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer()),
  915. InvalidOptionValue
  916. );
  917. // Buffer length must be multiple of data type size.
  918. EXPECT_THROW(
  919. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer(5)),
  920. InvalidOptionValue
  921. );
  922. }
  923. // The purpose of this test is to verify that definition for option that
  924. // comprises array of uint16 values can be created and that this definition
  925. // can be used to create option with an array of uint16 values.
  926. TEST_F(OptionDefinitionTest, uint16ArrayTokenized) {
  927. // Let's define some dummy option.
  928. const uint16_t opt_code = 79;
  929. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  930. OptionPtr option_v6;
  931. std::vector<std::string> str_values;
  932. str_values.push_back("12345");
  933. str_values.push_back("5679");
  934. str_values.push_back("12");
  935. EXPECT_NO_THROW(
  936. option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
  937. );
  938. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint16_t>));
  939. boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
  940. boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
  941. // Get the values from the initiated options and validate.
  942. std::vector<uint16_t> values = option_cast_v6->getValues();
  943. EXPECT_EQ(12345, values[0]);
  944. EXPECT_EQ(5679, values[1]);
  945. EXPECT_EQ(12, values[2]);
  946. }
  947. // The purpose of this test is to verify that definition for option that
  948. // comprises array of uint32 values can be created and that this definition
  949. // can be used to create option with an array of uint32 values.
  950. TEST_F(OptionDefinitionTest, uint32Array) {
  951. // Let's define some dummy option.
  952. const uint16_t opt_code = 80;
  953. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  954. OptionPtr option_v6;
  955. // Positive scenario, initiate the buffer with length being
  956. // multiple of uint16_t size.
  957. // buffer elements will be: 0x111122223333.
  958. OptionBuffer buf(12);
  959. for (int i = 0; i < buf.size(); ++i) {
  960. buf[i] = i / 4;
  961. }
  962. // Constructor should succeed because buffer has correct size.
  963. EXPECT_NO_THROW(
  964. option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
  965. );
  966. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint32_t>));
  967. boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
  968. boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
  969. // Get the values from the initiated options and validate.
  970. std::vector<uint32_t> values = option_cast_v6->getValues();
  971. for (int i = 0; i < values.size(); ++i) {
  972. // Expected value is calculated using on the same pattern
  973. // as the one we used to initiate buffer:
  974. // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
  975. uint32_t expected = 0x01010101 * i;
  976. EXPECT_EQ(expected, values[i]);
  977. }
  978. // Provided buffer size must be greater than zero. Check if we
  979. // get exception if we provide zero-length buffer.
  980. EXPECT_THROW(
  981. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer()),
  982. InvalidOptionValue
  983. );
  984. // Buffer length must be multiple of data type size.
  985. EXPECT_THROW(
  986. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer(5)),
  987. InvalidOptionValue
  988. );
  989. }
  990. // The purpose of this test is to verify that definition for option that
  991. // comprises array of uint32 values can be created and that this definition
  992. // can be used to create option with an array of uint32 values.
  993. TEST_F(OptionDefinitionTest, uint32ArrayTokenized) {
  994. // Let's define some dummy option.
  995. const uint16_t opt_code = 80;
  996. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  997. OptionPtr option_v6;
  998. std::vector<std::string> str_values;
  999. str_values.push_back("123456");
  1000. str_values.push_back("7");
  1001. str_values.push_back("256");
  1002. str_values.push_back("1111");
  1003. EXPECT_NO_THROW(
  1004. option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
  1005. );
  1006. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint32_t>));
  1007. boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
  1008. boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
  1009. // Get the values from the initiated options and validate.
  1010. std::vector<uint32_t> values = option_cast_v6->getValues();
  1011. EXPECT_EQ(123456, values[0]);
  1012. EXPECT_EQ(7, values[1]);
  1013. EXPECT_EQ(256, values[2]);
  1014. EXPECT_EQ(1111, values[3]);
  1015. }
  1016. // The purpose of this test is to verify that the definition can be created
  1017. // for the option that comprises string value in the UTF8 format.
  1018. TEST_F(OptionDefinitionTest, utf8StringTokenized) {
  1019. // Let's create some dummy option.
  1020. const uint16_t opt_code = 80;
  1021. OptionDefinition opt_def("OPTION_WITH_STRING", opt_code, "string");
  1022. std::vector<std::string> values;
  1023. values.push_back("Hello World");
  1024. values.push_back("this string should not be included in the option");
  1025. OptionPtr option_v6;
  1026. EXPECT_NO_THROW(
  1027. option_v6 = opt_def.optionFactory(Option::V6, opt_code, values);
  1028. );
  1029. ASSERT_TRUE(option_v6);
  1030. ASSERT_TRUE(typeid(*option_v6) == typeid(OptionString));
  1031. OptionStringPtr option_v6_string =
  1032. boost::static_pointer_cast<OptionString>(option_v6);
  1033. EXPECT_TRUE(values[0] == option_v6_string->getValue());
  1034. }
  1035. // The purpose of this test is to check that non-integer data type can't
  1036. // be used for factoryInteger function.
  1037. TEST_F(OptionDefinitionTest, integerInvalidType) {
  1038. // The template function factoryInteger<> accepts integer values only
  1039. // as template typename. Here we try passing different type and
  1040. // see if it rejects it.
  1041. OptionBuffer buf(1);
  1042. EXPECT_THROW(
  1043. OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, "dhcp6",
  1044. buf.begin(), buf.end(), NULL),
  1045. isc::dhcp::InvalidDataType
  1046. );
  1047. }
  1048. // The purpose of this test is to verify that helper methods
  1049. // haveIA6Format and haveIAAddr6Format can be used to determine
  1050. // IA_NA and IAADDR option formats.
  1051. TEST_F(OptionDefinitionTest, haveIAFormat) {
  1052. // IA_NA option format.
  1053. OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
  1054. for (int i = 0; i < 3; ++i) {
  1055. opt_def1.addRecordField("uint32");
  1056. }
  1057. EXPECT_TRUE(opt_def1.haveIA6Format());
  1058. // Create non-matching format to check that this function does not
  1059. // return 'true' all the time.
  1060. OptionDefinition opt_def2("OPTION_IA_NA", D6O_IA_NA, "uint16");
  1061. EXPECT_FALSE(opt_def2.haveIA6Format());
  1062. // IAADDR option format.
  1063. OptionDefinition opt_def3("OPTION_IAADDR", D6O_IAADDR, "record");
  1064. opt_def3.addRecordField("ipv6-address");
  1065. opt_def3.addRecordField("uint32");
  1066. opt_def3.addRecordField("uint32");
  1067. EXPECT_TRUE(opt_def3.haveIAAddr6Format());
  1068. // Create non-matching format to check that this function does not
  1069. // return 'true' all the time.
  1070. OptionDefinition opt_def4("OPTION_IAADDR", D6O_IAADDR, "uint32", true);
  1071. EXPECT_FALSE(opt_def4.haveIAAddr6Format());
  1072. }
  1073. // This test verifies that haveClientFqdnFormat function recognizes that option
  1074. // definition describes the format of DHCPv6 Client Fqdn Option Format.
  1075. TEST_F(OptionDefinitionTest, haveClientFqdnFormat) {
  1076. OptionDefinition opt_def("OPTION_CLIENT_FQDN", D6O_CLIENT_FQDN, "record");
  1077. opt_def.addRecordField("uint8");
  1078. opt_def.addRecordField("fqdn");
  1079. EXPECT_TRUE(opt_def.haveClientFqdnFormat());
  1080. // Create option format which is not matching the Client FQDN option format
  1081. // to verify that tested function does dont always return true.
  1082. OptionDefinition opt_def_invalid("OPTION_CLIENT_FQDN", D6O_CLIENT_FQDN,
  1083. "uint8");
  1084. EXPECT_FALSE(opt_def_invalid.haveClientFqdnFormat());
  1085. }
  1086. } // anonymous namespace