option_definition_unittest.cc 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729
  1. // Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/io_address.h>
  8. #include <dhcp/dhcp4.h>
  9. #include <dhcp/dhcp6.h>
  10. #include <dhcp/option4_addrlst.h>
  11. #include <dhcp/option6_addrlst.h>
  12. #include <dhcp/option6_ia.h>
  13. #include <dhcp/option6_iaaddr.h>
  14. #include <dhcp/option_custom.h>
  15. #include <dhcp/option_definition.h>
  16. #include <dhcp/option_int.h>
  17. #include <dhcp/option_int_array.h>
  18. #include <dhcp/option_string.h>
  19. #include <dhcp/option_opaque_data_tuples.h>
  20. #include <exceptions/exceptions.h>
  21. #include <boost/pointer_cast.hpp>
  22. #include <boost/shared_ptr.hpp>
  23. #include <gtest/gtest.h>
  24. using namespace std;
  25. using namespace isc;
  26. using namespace isc::dhcp;
  27. using namespace isc::util;
  28. namespace {
  29. /// @brief OptionDefinition test class.
  30. ///
  31. /// This class does not do anything useful but we keep
  32. /// it around for the future.
  33. class OptionDefinitionTest : public ::testing::Test {
  34. public:
  35. // @brief Constructor.
  36. OptionDefinitionTest() { }
  37. };
  38. // The purpose of this test is to verify that OptionDefinition
  39. // constructor initializes its members correctly.
  40. TEST_F(OptionDefinitionTest, constructor) {
  41. // Specify the option data type as string. This should get converted
  42. // to enum value returned by getType().
  43. OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "string");
  44. EXPECT_EQ("OPTION_CLIENTID", opt_def1.getName());
  45. EXPECT_EQ(1, opt_def1.getCode());
  46. EXPECT_EQ(OPT_STRING_TYPE, opt_def1.getType());
  47. EXPECT_FALSE(opt_def1.getArrayType());
  48. EXPECT_TRUE(opt_def1.getEncapsulatedSpace().empty());
  49. EXPECT_NO_THROW(opt_def1.validate());
  50. // Specify the option data type as an enum value.
  51. OptionDefinition opt_def2("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT,
  52. OPT_EMPTY_TYPE);
  53. EXPECT_EQ("OPTION_RAPID_COMMIT", opt_def2.getName());
  54. EXPECT_EQ(14, opt_def2.getCode());
  55. EXPECT_EQ(OPT_EMPTY_TYPE, opt_def2.getType());
  56. EXPECT_FALSE(opt_def2.getArrayType());
  57. EXPECT_TRUE(opt_def2.getEncapsulatedSpace().empty());
  58. EXPECT_NO_THROW(opt_def2.validate());
  59. // Specify encapsulated option space name and option data type
  60. // as enum value.
  61. OptionDefinition opt_def3("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
  62. OPT_UINT32_TYPE, "isc");
  63. EXPECT_EQ("OPTION_VENDOR_OPTS", opt_def3.getName());
  64. EXPECT_EQ(D6O_VENDOR_OPTS, opt_def3.getCode());
  65. EXPECT_EQ(OPT_UINT32_TYPE, opt_def3.getType());
  66. EXPECT_FALSE(opt_def3.getArrayType());
  67. EXPECT_EQ("isc", opt_def3.getEncapsulatedSpace());
  68. EXPECT_NO_THROW(opt_def3.validate());
  69. // Specify encapsulated option space name and option data type
  70. // as string value.
  71. OptionDefinition opt_def4("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
  72. "uint32", "isc");
  73. EXPECT_EQ("OPTION_VENDOR_OPTS", opt_def4.getName());
  74. EXPECT_EQ(D6O_VENDOR_OPTS, opt_def4.getCode());
  75. EXPECT_EQ(OPT_UINT32_TYPE, opt_def4.getType());
  76. EXPECT_FALSE(opt_def4.getArrayType());
  77. EXPECT_EQ("isc", opt_def4.getEncapsulatedSpace());
  78. EXPECT_NO_THROW(opt_def4.validate());
  79. // Check if it is possible to set that option is an array.
  80. OptionDefinition opt_def5("OPTION_NIS_SERVERS", 27,
  81. OPT_IPV6_ADDRESS_TYPE,
  82. true);
  83. EXPECT_EQ("OPTION_NIS_SERVERS", opt_def5.getName());
  84. EXPECT_EQ(27, opt_def5.getCode());
  85. EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, opt_def5.getType());
  86. EXPECT_TRUE(opt_def5.getArrayType());
  87. EXPECT_NO_THROW(opt_def5.validate());
  88. // The created object is invalid if invalid data type is specified but
  89. // constructor shouldn't throw exception. The object is validated after
  90. // it has been created.
  91. EXPECT_NO_THROW(
  92. OptionDefinition opt_def6("OPTION_SERVERID",
  93. OPT_UNKNOWN_TYPE + 10,
  94. OPT_STRING_TYPE);
  95. );
  96. }
  97. // This test checks that the copy constructor works properly.
  98. TEST_F(OptionDefinitionTest, copyConstructor) {
  99. OptionDefinition opt_def("option-foo", 27, "record", true);
  100. ASSERT_NO_THROW(opt_def.addRecordField("uint16"));
  101. ASSERT_NO_THROW(opt_def.addRecordField("string"));
  102. OptionDefinition opt_def_copy(opt_def);
  103. EXPECT_EQ("option-foo", opt_def_copy.getName());
  104. EXPECT_EQ(27, opt_def_copy.getCode());
  105. EXPECT_TRUE(opt_def_copy.getArrayType());
  106. EXPECT_TRUE(opt_def_copy.getEncapsulatedSpace().empty());
  107. ASSERT_EQ(OPT_RECORD_TYPE, opt_def_copy.getType());
  108. const OptionDefinition::RecordFieldsCollection fields =
  109. opt_def_copy.getRecordFields();
  110. ASSERT_EQ(2, fields.size());
  111. EXPECT_EQ(OPT_UINT16_TYPE, fields[0]);
  112. EXPECT_EQ(OPT_STRING_TYPE, fields[1]);
  113. // Let's make another test to check if encapsulated option space is
  114. // copied properly.
  115. OptionDefinition opt_def2("option-bar", 30, "uint32", "isc");
  116. OptionDefinition opt_def_copy2(opt_def2);
  117. EXPECT_EQ("option-bar", opt_def_copy2.getName());
  118. EXPECT_EQ(30, opt_def_copy2.getCode());
  119. EXPECT_FALSE(opt_def_copy2.getArrayType());
  120. EXPECT_EQ(OPT_UINT32_TYPE, opt_def_copy2.getType());
  121. EXPECT_EQ("isc", opt_def_copy2.getEncapsulatedSpace());
  122. }
  123. // This test checks that two option definitions may be compared for equality.
  124. TEST_F(OptionDefinitionTest, equality) {
  125. // Equal definitions.
  126. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  127. == OptionDefinition("option-foo", 5, "uint16", false));
  128. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  129. != OptionDefinition("option-foo", 5, "uint16", false));
  130. // Differ by name.
  131. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  132. == OptionDefinition("option-foobar", 5, "uint16", false));
  133. EXPECT_FALSE(OptionDefinition("option-bar", 5, "uint16", false)
  134. == OptionDefinition("option-foo", 5, "uint16", false));
  135. EXPECT_TRUE(OptionDefinition("option-bar", 5, "uint16", false)
  136. != OptionDefinition("option-foo", 5, "uint16", false));
  137. // Differ by option code.
  138. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  139. == OptionDefinition("option-foo", 6, "uint16", false));
  140. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  141. != OptionDefinition("option-foo", 6, "uint16", false));
  142. // Differ by type of the data.
  143. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  144. == OptionDefinition("option-foo", 5, "uint32", false));
  145. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  146. != OptionDefinition("option-foo", 5, "uint32", false));
  147. // Differ by array-type property.
  148. EXPECT_FALSE(OptionDefinition("option-foo", 5, "uint16", false)
  149. == OptionDefinition("option-foo", 5, "uint16", true));
  150. EXPECT_TRUE(OptionDefinition("option-foo", 5, "uint16", false)
  151. != OptionDefinition("option-foo", 5, "uint16", true));
  152. // Differ by record fields.
  153. OptionDefinition def1("option-foo", 5, "record");
  154. OptionDefinition def2("option-foo", 5, "record");
  155. // There are no record fields specified yet, so initially they have
  156. // to be equal.
  157. ASSERT_TRUE(def1 == def2);
  158. ASSERT_FALSE(def1 != def2);
  159. // Add some record fields.
  160. ASSERT_NO_THROW(def1.addRecordField("uint16"));
  161. ASSERT_NO_THROW(def2.addRecordField("uint16"));
  162. // Definitions should still remain equal.
  163. ASSERT_TRUE(def1 == def2);
  164. ASSERT_FALSE(def1 != def2);
  165. // Add additional record field to one of the definitions but not the
  166. // other. They should now be unequal.
  167. ASSERT_NO_THROW(def1.addRecordField("string"));
  168. ASSERT_FALSE(def1 == def2);
  169. ASSERT_TRUE(def1 != def2);
  170. // Add the same record field to the other definition. They should now
  171. // be equal again.
  172. ASSERT_NO_THROW(def2.addRecordField("string"));
  173. EXPECT_TRUE(def1 == def2);
  174. EXPECT_FALSE(def1 != def2);
  175. }
  176. // The purpose of this test is to verify that various data fields
  177. // can be specified for an option definition when this definition
  178. // is marked as 'record' and that fields can't be added if option
  179. // definition is not marked as 'record'.
  180. TEST_F(OptionDefinitionTest, addRecordField) {
  181. // We can only add fields to record if the option type has been
  182. // specified as 'record'. We try all other types but 'record'
  183. // here and expect exception to be thrown.
  184. for (int i = 0; i < OPT_UNKNOWN_TYPE; ++i) {
  185. // Do not try for 'record' type because this is the only
  186. // type for which adding record will succeed.
  187. if (i == OPT_RECORD_TYPE) {
  188. continue;
  189. }
  190. OptionDefinition opt_def("OPTION_IAADDR", 5,
  191. static_cast<OptionDataType>(i));
  192. EXPECT_THROW(opt_def.addRecordField("uint8"), isc::InvalidOperation);
  193. }
  194. // Positive scenario starts here.
  195. OptionDefinition opt_def("OPTION_IAADDR", 5, "record");
  196. EXPECT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  197. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  198. // It should not matter if we specify field type by its name or using enum.
  199. EXPECT_NO_THROW(opt_def.addRecordField(OPT_UINT32_TYPE));
  200. // Check what we have actually added.
  201. OptionDefinition::RecordFieldsCollection fields = opt_def.getRecordFields();
  202. ASSERT_EQ(3, fields.size());
  203. EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, fields[0]);
  204. EXPECT_EQ(OPT_UINT32_TYPE, fields[1]);
  205. EXPECT_EQ(OPT_UINT32_TYPE, fields[2]);
  206. // Let's try some more negative scenarios: use invalid data types.
  207. EXPECT_THROW(opt_def.addRecordField("unknown_type_xyz"), isc::BadValue);
  208. OptionDataType invalid_type =
  209. static_cast<OptionDataType>(OPT_UNKNOWN_TYPE + 10);
  210. EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
  211. // It is bad if we use 'record' option type but don't specify
  212. // at least two fields.
  213. OptionDefinition opt_def2("OPTION_EMPTY_RECORD", 100, "record");
  214. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  215. opt_def2.addRecordField("uint8");
  216. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  217. opt_def2.addRecordField("uint32");
  218. EXPECT_NO_THROW(opt_def2.validate());
  219. }
  220. // The purpose of this test is to check that validate() function
  221. // reports errors for invalid option definitions.
  222. TEST_F(OptionDefinitionTest, validate) {
  223. // Not supported option type string is not allowed.
  224. OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
  225. EXPECT_THROW(opt_def1.validate(), MalformedOptionDefinition);
  226. // Not supported option type enum value is not allowed.
  227. OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OPT_UNKNOWN_TYPE);
  228. EXPECT_THROW(opt_def2.validate(), MalformedOptionDefinition);
  229. OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
  230. static_cast<OptionDataType>(OPT_UNKNOWN_TYPE
  231. + 2));
  232. EXPECT_THROW(opt_def3.validate(), MalformedOptionDefinition);
  233. // Empty option name is not allowed.
  234. OptionDefinition opt_def4("", D6O_CLIENTID, "string");
  235. EXPECT_THROW(opt_def4.validate(), MalformedOptionDefinition);
  236. // Option name must not contain spaces.
  237. OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
  238. EXPECT_THROW(opt_def5.validate(), MalformedOptionDefinition);
  239. // Option name must not contain spaces.
  240. OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string");
  241. EXPECT_THROW(opt_def6.validate(), MalformedOptionDefinition);
  242. // Option name may contain lower case letters.
  243. OptionDefinition opt_def7("option_clientid", D6O_CLIENTID, "string");
  244. EXPECT_NO_THROW(opt_def7.validate());
  245. // Using digits in option name is legal.
  246. OptionDefinition opt_def8("option_123", D6O_CLIENTID, "string");
  247. EXPECT_NO_THROW(opt_def8.validate());
  248. // Using hyphen is legal.
  249. OptionDefinition opt_def9("option-clientid", D6O_CLIENTID, "string");
  250. EXPECT_NO_THROW(opt_def9.validate());
  251. // Using hyphen or underscore at the beginning or at the end
  252. // of the option name is not allowed.
  253. OptionDefinition opt_def10("-option-clientid", D6O_CLIENTID, "string");
  254. EXPECT_THROW(opt_def10.validate(), MalformedOptionDefinition);
  255. OptionDefinition opt_def11("_option-clientid", D6O_CLIENTID, "string");
  256. EXPECT_THROW(opt_def11.validate(), MalformedOptionDefinition);
  257. OptionDefinition opt_def12("option-clientid_", D6O_CLIENTID, "string");
  258. EXPECT_THROW(opt_def12.validate(), MalformedOptionDefinition);
  259. OptionDefinition opt_def13("option-clientid-", D6O_CLIENTID, "string");
  260. EXPECT_THROW(opt_def13.validate(), MalformedOptionDefinition);
  261. // Having array of strings does not make sense because there is no way
  262. // to determine string's length.
  263. OptionDefinition opt_def14("OPTION_CLIENTID", D6O_CLIENTID, "string", true);
  264. EXPECT_THROW(opt_def14.validate(), MalformedOptionDefinition);
  265. // It does not make sense to have string field within the record before
  266. // other fields because there is no way to determine the length of this
  267. // string and thus there is no way to determine where the other field
  268. // begins.
  269. OptionDefinition opt_def15("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  270. "record");
  271. opt_def15.addRecordField("string");
  272. opt_def15.addRecordField("uint16");
  273. EXPECT_THROW(opt_def15.validate(), MalformedOptionDefinition);
  274. // ... but it is ok if the string value is the last one.
  275. OptionDefinition opt_def16("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  276. "record");
  277. opt_def16.addRecordField("uint8");
  278. opt_def16.addRecordField("string");
  279. EXPECT_NO_THROW(opt_def16.validate());
  280. // ... at least if it is not an array.
  281. OptionDefinition opt_def17("OPTION_STATUS_CODE", D6O_STATUS_CODE,
  282. "record", true);
  283. opt_def17.addRecordField("uint8");
  284. opt_def17.addRecordField("string");
  285. EXPECT_THROW(opt_def17.validate(), MalformedOptionDefinition);
  286. // Check invalid encapsulated option space name.
  287. OptionDefinition opt_def18("OPTION_VENDOR_OPTS", D6O_VENDOR_OPTS,
  288. "uint32", "invalid%space%name");
  289. EXPECT_THROW(opt_def18.validate(), MalformedOptionDefinition);
  290. }
  291. // The purpose of this test is to verify that option definition
  292. // that comprises array of IPv6 addresses will return an instance
  293. // of option with a list of IPv6 addresses.
  294. TEST_F(OptionDefinitionTest, ipv6AddressArray) {
  295. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  296. "ipv6-address", true);
  297. // Create a list of some V6 addresses.
  298. std::vector<asiolink::IOAddress> addrs;
  299. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  300. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  301. addrs.push_back(asiolink::IOAddress("::1"));
  302. addrs.push_back(asiolink::IOAddress("::2"));
  303. // Write addresses to the buffer.
  304. OptionBuffer buf(addrs.size() * asiolink::V6ADDRESS_LEN);
  305. for (size_t i = 0; i < addrs.size(); ++i) {
  306. const std::vector<uint8_t>& vec = addrs[i].toBytes();
  307. ASSERT_EQ(asiolink::V6ADDRESS_LEN, vec.size());
  308. std::copy(vec.begin(), vec.end(),
  309. buf.begin() + i * asiolink::V6ADDRESS_LEN);
  310. }
  311. // Create DHCPv6 option from this buffer. Once option is created it is
  312. // supposed to have internal list of addresses that it parses out from
  313. // the provided buffer.
  314. OptionPtr option_v6;
  315. ASSERT_NO_THROW(
  316. option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS, buf);
  317. );
  318. const Option* optptr = option_v6.get();
  319. ASSERT_TRUE(optptr);
  320. ASSERT_TRUE(typeid(*optptr) == typeid(Option6AddrLst));
  321. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  322. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  323. ASSERT_TRUE(option_cast_v6);
  324. // Get the list of parsed addresses from the option object.
  325. std::vector<asiolink::IOAddress> addrs_returned =
  326. option_cast_v6->getAddresses();
  327. // The list of addresses must exactly match addresses that we
  328. // stored in the buffer to create the option from it.
  329. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  330. // The provided buffer's length must be a multiple of V6 address length.
  331. // Let's extend the buffer by one byte so as this condition is not
  332. // fulfilled anymore.
  333. buf.insert(buf.end(), 1, 1);
  334. // It should throw exception then.
  335. EXPECT_THROW(
  336. opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS, buf),
  337. InvalidOptionValue
  338. );
  339. }
  340. // The purpose of this test is to verify that option definition
  341. // that comprises array of IPv6 addresses will return an instance
  342. // of option with a list of IPv6 addresses. Array of IPv6 addresses
  343. // is specified as a vector of strings (each string represents single
  344. // IPv6 address).
  345. TEST_F(OptionDefinitionTest, ipv6AddressArrayTokenized) {
  346. OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,
  347. "ipv6-address", true);
  348. // Create a vector of some V6 addresses.
  349. std::vector<asiolink::IOAddress> addrs;
  350. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:8329"));
  351. addrs.push_back(asiolink::IOAddress("2001:0db8::ff00:0042:2319"));
  352. addrs.push_back(asiolink::IOAddress("::1"));
  353. addrs.push_back(asiolink::IOAddress("::2"));
  354. // Create a vector of strings representing addresses given above.
  355. std::vector<std::string> addrs_str;
  356. for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
  357. it != addrs.end(); ++it) {
  358. addrs_str.push_back(it->toText());
  359. }
  360. // Create DHCPv6 option using the list of IPv6 addresses given in the
  361. // string form.
  362. OptionPtr option_v6;
  363. ASSERT_NO_THROW(
  364. option_v6 = opt_def.optionFactory(Option::V6, D6O_NIS_SERVERS,
  365. addrs_str);
  366. );
  367. // Non-null pointer option is supposed to be returned and it
  368. // should have Option6AddrLst type.
  369. ASSERT_TRUE(option_v6);
  370. const Option* optptr = option_v6.get();
  371. ASSERT_TRUE(optptr);
  372. ASSERT_TRUE(typeid(*optptr) == typeid(Option6AddrLst));
  373. // Cast to the actual option type to get IPv6 addresses from it.
  374. boost::shared_ptr<Option6AddrLst> option_cast_v6 =
  375. boost::static_pointer_cast<Option6AddrLst>(option_v6);
  376. // Check that cast was successful.
  377. ASSERT_TRUE(option_cast_v6);
  378. // Get the list of parsed addresses from the option object.
  379. std::vector<asiolink::IOAddress> addrs_returned =
  380. option_cast_v6->getAddresses();
  381. // Returned addresses must match the addresses that have been used to create
  382. // the option instance.
  383. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  384. }
  385. // The purpose of this test is to verify that option definition
  386. // that comprises array of IPv4 addresses will return an instance
  387. // of option with a list of IPv4 addresses.
  388. TEST_F(OptionDefinitionTest, ipv4AddressArray) {
  389. OptionDefinition opt_def("OPTION_NAME_SERVERS", D6O_NIS_SERVERS,
  390. "ipv4-address", true);
  391. // Create a list of some V6 addresses.
  392. std::vector<asiolink::IOAddress> addrs;
  393. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  394. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  395. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  396. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  397. // Write addresses to the buffer.
  398. OptionBuffer buf(addrs.size() * asiolink::V4ADDRESS_LEN);
  399. for (size_t i = 0; i < addrs.size(); ++i) {
  400. const std::vector<uint8_t> vec = addrs[i].toBytes();
  401. ASSERT_EQ(asiolink::V4ADDRESS_LEN, vec.size());
  402. std::copy(vec.begin(), vec.end(),
  403. buf.begin() + i * asiolink::V4ADDRESS_LEN);
  404. }
  405. // Create DHCPv6 option from this buffer. Once option is created it is
  406. // supposed to have internal list of addresses that it parses out from
  407. // the provided buffer.
  408. OptionPtr option_v4;
  409. ASSERT_NO_THROW(
  410. option_v4 = opt_def.optionFactory(Option::V4, DHO_NAME_SERVERS, buf)
  411. );
  412. const Option* optptr = option_v4.get();
  413. ASSERT_TRUE(optptr);
  414. ASSERT_TRUE(typeid(*optptr) == typeid(Option4AddrLst));
  415. // Get the list of parsed addresses from the option object.
  416. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  417. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  418. std::vector<asiolink::IOAddress> addrs_returned =
  419. option_cast_v4->getAddresses();
  420. // The list of addresses must exactly match addresses that we
  421. // stored in the buffer to create the option from it.
  422. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  423. // The provided buffer's length must be a multiple of V4 address length.
  424. // Let's extend the buffer by one byte so as this condition is not
  425. // fulfilled anymore.
  426. buf.insert(buf.end(), 1, 1);
  427. // It should throw exception then.
  428. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS, buf),
  429. InvalidOptionValue);
  430. }
  431. // The purpose of this test is to verify that option definition
  432. // that comprises array of IPv4 addresses will return an instance
  433. // of option with a list of IPv4 addresses. The array of IPv4 addresses
  434. // is specified as a vector of strings (each string represents single
  435. // IPv4 address).
  436. TEST_F(OptionDefinitionTest, ipv4AddressArrayTokenized) {
  437. OptionDefinition opt_def("OPTION_NIS_SERVERS", DHO_NIS_SERVERS,
  438. "ipv4-address", true);
  439. // Create a vector of some V6 addresses.
  440. std::vector<asiolink::IOAddress> addrs;
  441. addrs.push_back(asiolink::IOAddress("192.168.0.1"));
  442. addrs.push_back(asiolink::IOAddress("172.16.1.1"));
  443. addrs.push_back(asiolink::IOAddress("127.0.0.1"));
  444. addrs.push_back(asiolink::IOAddress("213.41.23.12"));
  445. // Create a vector of strings representing addresses given above.
  446. std::vector<std::string> addrs_str;
  447. for (std::vector<asiolink::IOAddress>::const_iterator it = addrs.begin();
  448. it != addrs.end(); ++it) {
  449. addrs_str.push_back(it->toText());
  450. }
  451. // Create DHCPv4 option using the list of IPv4 addresses given in the
  452. // string form.
  453. OptionPtr option_v4;
  454. ASSERT_NO_THROW(
  455. option_v4 = opt_def.optionFactory(Option::V4, DHO_NIS_SERVERS,
  456. addrs_str);
  457. );
  458. // Non-null pointer option is supposed to be returned and it
  459. // should have Option6AddrLst type.
  460. ASSERT_TRUE(option_v4);
  461. const Option* optptr = option_v4.get();
  462. ASSERT_TRUE(optptr);
  463. ASSERT_TRUE(typeid(*optptr) == typeid(Option4AddrLst));
  464. // Cast to the actual option type to get IPv4 addresses from it.
  465. boost::shared_ptr<Option4AddrLst> option_cast_v4 =
  466. boost::static_pointer_cast<Option4AddrLst>(option_v4);
  467. // Check that cast was successful.
  468. ASSERT_TRUE(option_cast_v4);
  469. // Get the list of parsed addresses from the option object.
  470. std::vector<asiolink::IOAddress> addrs_returned =
  471. option_cast_v4->getAddresses();
  472. // Returned addresses must match the addresses that have been used to create
  473. // the option instance.
  474. EXPECT_TRUE(std::equal(addrs.begin(), addrs.end(), addrs_returned.begin()));
  475. }
  476. // The purpose of this test is to verify that option definition for
  477. // 'empty' option can be created and that it returns 'empty' option.
  478. TEST_F(OptionDefinitionTest, empty) {
  479. OptionDefinition opt_def("OPTION_RAPID_COMMIT", D6O_RAPID_COMMIT, "empty");
  480. // Create option instance and provide empty buffer as expected.
  481. OptionPtr option_v6;
  482. ASSERT_NO_THROW(
  483. option_v6 = opt_def.optionFactory(Option::V6, D6O_RAPID_COMMIT, OptionBuffer())
  484. );
  485. const Option* optptr = option_v6.get();
  486. ASSERT_TRUE(optptr);
  487. ASSERT_TRUE(typeid(*optptr) == typeid(Option));
  488. // Expect 'empty' DHCPv6 option.
  489. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  490. EXPECT_EQ(4, option_v6->getHeaderLen());
  491. EXPECT_EQ(0, option_v6->getData().size());
  492. // Repeat the same test scenario for DHCPv4 option.
  493. OptionPtr option_v4;
  494. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, OptionBuffer()));
  495. // Expect 'empty' DHCPv4 option.
  496. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  497. EXPECT_EQ(2, option_v4->getHeaderLen());
  498. EXPECT_EQ(0, option_v4->getData().size());
  499. }
  500. // The purpose of this test is to verify that when the empty option encapsulates
  501. // some option space, an instance of the OptionCustom is returned and its
  502. // suboptions are decoded.
  503. TEST_F(OptionDefinitionTest, emptyWithSuboptions) {
  504. // Create an instance of the 'empty' option definition. This option
  505. // encapsulates 'option-foo-space' so when we create a new option
  506. // with this definition the OptionCustom should be returned. The
  507. // Option Custom is generic option which support variety of formats
  508. // and supports decoding suboptions.
  509. OptionDefinition opt_def("option-foo", 1024, "empty", "option-foo-space");
  510. // Define a suboption.
  511. const uint8_t subopt_data[] = {
  512. 0x04, 0x01, // Option code 1025
  513. 0x00, 0x04, // Option len = 4
  514. 0x01, 0x02, 0x03, 0x04 // Option data
  515. };
  516. // Create an option, having option code 1024 from the definition. Pass
  517. // the option buffer containing suboption.
  518. OptionPtr option_v6;
  519. ASSERT_NO_THROW(
  520. option_v6 = opt_def.optionFactory(Option::V6, 1024,
  521. OptionBuffer(subopt_data,
  522. subopt_data +
  523. sizeof(subopt_data)))
  524. );
  525. // Returned option should be of the OptionCustom type.
  526. const Option* optptr = option_v6.get();
  527. ASSERT_TRUE(optptr);
  528. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  529. // Sanity-check length, universe etc.
  530. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  531. EXPECT_EQ(4, option_v6->getHeaderLen());
  532. // This option should have one suboption with the code of 1025.
  533. OptionPtr subopt_v6 = option_v6->getOption(1025);
  534. EXPECT_TRUE(subopt_v6);
  535. // Check that this suboption holds valid data.
  536. EXPECT_EQ(1025, subopt_v6->getType());
  537. EXPECT_EQ(Option::V6, subopt_v6->getUniverse());
  538. EXPECT_EQ(0, memcmp(&subopt_v6->getData()[0], subopt_data + 4, 4));
  539. // @todo consider having a similar test for V4.
  540. }
  541. // The purpose of this test is to verify that definition can be
  542. // creates for the option that holds binary data.
  543. TEST_F(OptionDefinitionTest, binary) {
  544. // Binary option is the one that is represented by the generic
  545. // Option class. In fact all options can be represented by this
  546. // class but for some of them it is just natural. The SERVERID
  547. // option consists of the option code, length and binary data so
  548. // this one was picked for this test.
  549. OptionDefinition opt_def("OPTION_SERVERID", D6O_SERVERID, "binary");
  550. // Prepare some dummy data (serverid): 0, 1, 2 etc.
  551. OptionBuffer buf(14);
  552. for (unsigned i = 0; i < 14; ++i) {
  553. buf[i] = i;
  554. }
  555. // Create option instance with the factory function.
  556. // If the OptionDefinition code works properly than
  557. // object of the type Option should be returned.
  558. OptionPtr option_v6;
  559. ASSERT_NO_THROW(
  560. option_v6 = opt_def.optionFactory(Option::V6, D6O_SERVERID, buf);
  561. );
  562. // Expect base option type returned.
  563. const Option* optptr = option_v6.get();
  564. ASSERT_TRUE(optptr);
  565. ASSERT_TRUE(typeid(*optptr) == typeid(Option));
  566. // Sanity check on universe, length and size. These are
  567. // the basic parameters identifying any option.
  568. EXPECT_EQ(Option::V6, option_v6->getUniverse());
  569. EXPECT_EQ(4, option_v6->getHeaderLen());
  570. ASSERT_EQ(buf.size(), option_v6->getData().size());
  571. // Get the server id data from the option and compare
  572. // against reference buffer. They are expected to match.
  573. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  574. option_v6->getData().end(),
  575. buf.begin()));
  576. // Repeat the same test scenario for DHCPv4 option.
  577. OptionPtr option_v4;
  578. ASSERT_NO_THROW(option_v4 = opt_def.optionFactory(Option::V4, 214, buf));
  579. // Expect 'empty' DHCPv4 option.
  580. EXPECT_EQ(Option::V4, option_v4->getUniverse());
  581. EXPECT_EQ(2, option_v4->getHeaderLen());
  582. ASSERT_EQ(buf.size(), option_v4->getData().size());
  583. EXPECT_TRUE(std::equal(option_v6->getData().begin(),
  584. option_v6->getData().end(),
  585. buf.begin()));
  586. }
  587. // The purpose of this test is to verify that definition can be created
  588. // for option that comprises record of data. In this particular test
  589. // the IA_NA option is used. This option comprises three uint32 fields.
  590. TEST_F(OptionDefinitionTest, recordIA6) {
  591. // This option consists of IAID, T1 and T2 fields (each 4 bytes long).
  592. const int option6_ia_len = 12;
  593. // Get the factory function pointer.
  594. OptionDefinition opt_def("OPTION_IA_NA", D6O_IA_NA, "record", false);
  595. // Each data field is uint32.
  596. for (int i = 0; i < 3; ++i) {
  597. EXPECT_NO_THROW(opt_def.addRecordField("uint32"));
  598. }
  599. // Check the positive scenario.
  600. OptionBuffer buf(12);
  601. for (size_t i = 0; i < buf.size(); ++i) {
  602. buf[i] = i;
  603. }
  604. OptionPtr option_v6;
  605. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IA_NA, buf));
  606. const Option* optptr = option_v6.get();
  607. ASSERT_TRUE(optptr);
  608. ASSERT_TRUE(typeid(*optptr) == typeid(Option6IA));
  609. boost::shared_ptr<Option6IA> option_cast_v6 =
  610. boost::static_pointer_cast<Option6IA>(option_v6);
  611. EXPECT_EQ(0x00010203, option_cast_v6->getIAID());
  612. EXPECT_EQ(0x04050607, option_cast_v6->getT1());
  613. EXPECT_EQ(0x08090A0B, option_cast_v6->getT2());
  614. // The length of the buffer must be at least 12 bytes.
  615. // Check too short buffer.
  616. EXPECT_THROW(
  617. opt_def.optionFactory(Option::V6, D6O_IA_NA, OptionBuffer(option6_ia_len - 1)),
  618. InvalidOptionValue
  619. );
  620. }
  621. // The purpose of this test is to verify that definition can be created
  622. // for option that comprises record of data. In this particular test
  623. // the IAADDR option is used.
  624. TEST_F(OptionDefinitionTest, recordIAAddr6) {
  625. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  626. // valid-lifetime fields (each 4 bytes long).
  627. const int option6_iaaddr_len = 24;
  628. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  629. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  630. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  631. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  632. // Check the positive scenario.
  633. OptionPtr option_v6;
  634. asiolink::IOAddress addr_v6("2001:0db8::ff00:0042:8329");
  635. OptionBuffer buf(asiolink::V6ADDRESS_LEN);
  636. ASSERT_TRUE(addr_v6.isV6());
  637. const std::vector<uint8_t>& vec = addr_v6.toBytes();
  638. ASSERT_EQ(asiolink::V6ADDRESS_LEN, vec.size());
  639. std::copy(vec.begin(), vec.end(), buf.begin());
  640. for (unsigned i = 0;
  641. i < option6_iaaddr_len - asiolink::V6ADDRESS_LEN;
  642. ++i) {
  643. buf.push_back(i);
  644. }
  645. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR, buf));
  646. const Option* optptr = option_v6.get();
  647. ASSERT_TRUE(optptr);
  648. ASSERT_TRUE(typeid(*optptr) == typeid(Option6IAAddr));
  649. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  650. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  651. EXPECT_EQ(addr_v6, option_cast_v6->getAddress());
  652. EXPECT_EQ(0x00010203, option_cast_v6->getPreferred());
  653. EXPECT_EQ(0x04050607, option_cast_v6->getValid());
  654. // The length of the buffer must be at least 12 bytes.
  655. // Check too short buffer.
  656. EXPECT_THROW(
  657. opt_def.optionFactory(Option::V6, D6O_IAADDR, OptionBuffer(option6_iaaddr_len - 1)),
  658. InvalidOptionValue
  659. );
  660. }
  661. // The purpose of this test is to verify that definition can be created
  662. // for option that comprises record of data. In this particular test
  663. // the IAADDR option is used. The data for the option is specified as
  664. // a vector of strings. Each string carries the data for the corresponding
  665. // data field.
  666. TEST_F(OptionDefinitionTest, recordIAAddr6Tokenized) {
  667. // This option consists of IPV6 Address (16 bytes) and preferred-lifetime and
  668. // valid-lifetime fields (each 4 bytes long).
  669. OptionDefinition opt_def("OPTION_IAADDR", D6O_IAADDR, "record");
  670. ASSERT_NO_THROW(opt_def.addRecordField("ipv6-address"));
  671. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  672. ASSERT_NO_THROW(opt_def.addRecordField("uint32"));
  673. // Check the positive scenario.
  674. std::vector<std::string> data_field_values;
  675. data_field_values.push_back("2001:0db8::ff00:0042:8329");
  676. data_field_values.push_back("1234");
  677. data_field_values.push_back("5678");
  678. OptionPtr option_v6;
  679. ASSERT_NO_THROW(option_v6 = opt_def.optionFactory(Option::V6, D6O_IAADDR,
  680. data_field_values));
  681. const Option* optptr = option_v6.get();
  682. ASSERT_TRUE(optptr);
  683. ASSERT_TRUE(typeid(*optptr) == typeid(Option6IAAddr));
  684. boost::shared_ptr<Option6IAAddr> option_cast_v6 =
  685. boost::static_pointer_cast<Option6IAAddr>(option_v6);
  686. EXPECT_EQ("2001:db8::ff00:42:8329", option_cast_v6->getAddress().toText());
  687. EXPECT_EQ(1234, option_cast_v6->getPreferred());
  688. EXPECT_EQ(5678, option_cast_v6->getValid());
  689. }
  690. // The purpose of this test is to verify that the definition for option
  691. // that comprises a boolean value can be created and that this definition
  692. // can be used to create and option with a single boolean value.
  693. TEST_F(OptionDefinitionTest, boolValue) {
  694. // The IP Forwarding option comprises one boolean value.
  695. OptionDefinition opt_def("ip-forwarding", DHO_IP_FORWARDING,
  696. "boolean");
  697. OptionPtr option_v4;
  698. // Use an option buffer which holds one value of 1 (true).
  699. ASSERT_NO_THROW(
  700. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  701. OptionBuffer(1, 1));
  702. );
  703. const Option* optptr = option_v4.get();
  704. ASSERT_TRUE(optptr);
  705. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  706. // Validate parsed value in the received option.
  707. boost::shared_ptr<OptionCustom> option_cast_v4 =
  708. boost::static_pointer_cast<OptionCustom>(option_v4);
  709. EXPECT_TRUE(option_cast_v4->readBoolean());
  710. // Repeat the test above, but set the value to 0 (false).
  711. ASSERT_NO_THROW(
  712. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  713. OptionBuffer(1, 0));
  714. );
  715. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  716. EXPECT_FALSE(option_cast_v4->readBoolean());
  717. // Try to provide zero-length buffer. Expect exception.
  718. EXPECT_THROW(
  719. opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING, OptionBuffer()),
  720. InvalidOptionValue
  721. );
  722. }
  723. // The purpose of this test is to verify that definition for option that
  724. // comprises single boolean value can be created and that this definition
  725. // can be used to create an option holding a single boolean value. The
  726. // boolean value is converted from a string which is expected to hold
  727. // the following values: "true", "false", "1" or "0". For all other
  728. // values exception should be thrown.
  729. TEST_F(OptionDefinitionTest, boolTokenized) {
  730. OptionDefinition opt_def("ip-forwarding", DHO_IP_FORWARDING, "boolean");
  731. OptionPtr option_v4;
  732. std::vector<std::string> values;
  733. // Specify a value for the option instance being created.
  734. values.push_back("true");
  735. ASSERT_NO_THROW(
  736. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  737. values);
  738. );
  739. const Option* optptr = option_v4.get();
  740. ASSERT_TRUE(optptr);
  741. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  742. // Validate the value.
  743. OptionCustomPtr option_cast_v4 =
  744. boost::static_pointer_cast<OptionCustom>(option_v4);
  745. EXPECT_TRUE(option_cast_v4->readBoolean());
  746. // Repeat the test but for "false" value this time.
  747. values[0] = "false";
  748. ASSERT_NO_THROW(
  749. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  750. values);
  751. );
  752. optptr = option_v4.get();
  753. ASSERT_TRUE(optptr);
  754. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  755. // Validate the value.
  756. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  757. EXPECT_FALSE(option_cast_v4->readBoolean());
  758. // Check if that will work for numeric values.
  759. values[0] = "0";
  760. ASSERT_NO_THROW(
  761. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  762. values);
  763. );
  764. optptr = option_v4.get();
  765. ASSERT_TRUE(optptr);
  766. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  767. // Validate the value.
  768. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  769. EXPECT_FALSE(option_cast_v4->readBoolean());
  770. // Swap numeric values and test if it works for "true" case.
  771. values[0] = "1";
  772. ASSERT_NO_THROW(
  773. option_v4 = opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING,
  774. values);
  775. );
  776. optptr = option_v4.get();
  777. ASSERT_TRUE(optptr);
  778. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  779. // Validate the value.
  780. option_cast_v4 = boost::static_pointer_cast<OptionCustom>(option_v4);
  781. EXPECT_TRUE(option_cast_v4->readBoolean());
  782. // A conversion of non-numeric value to boolean should fail if
  783. // this value is neither "true" nor "false".
  784. values[0] = "garbage";
  785. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING, values),
  786. isc::dhcp::BadDataTypeCast);
  787. // A conversion of numeric value to boolean should fail if this value
  788. // is neither "0" nor "1".
  789. values[0] = "2";
  790. EXPECT_THROW(opt_def.optionFactory(Option::V4, DHO_IP_FORWARDING, values),
  791. isc::dhcp::BadDataTypeCast);
  792. }
  793. // The purpose of this test is to verify that definition for option that
  794. // comprises single uint8 value can be created and that this definition
  795. // can be used to create an option with single uint8 value.
  796. TEST_F(OptionDefinitionTest, uint8) {
  797. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  798. OptionPtr option_v6;
  799. // Try to use correct buffer length = 1 byte.
  800. ASSERT_NO_THROW(
  801. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE,
  802. OptionBuffer(1, 1));
  803. );
  804. const Option* optptr = option_v6.get();
  805. ASSERT_TRUE(optptr);
  806. ASSERT_TRUE(typeid(*optptr) == typeid(OptionInt<uint8_t>));
  807. // Validate the value.
  808. boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
  809. boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
  810. EXPECT_EQ(1, option_cast_v6->getValue());
  811. // Try to provide zero-length buffer. Expect exception.
  812. EXPECT_THROW(
  813. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, OptionBuffer()),
  814. InvalidOptionValue
  815. );
  816. // @todo Add more cases for DHCPv4
  817. }
  818. // The purpose of this test is to verify that definition for option that
  819. // comprises single uint8 value can be created and that this definition
  820. // can be used to create an option with single uint8 value.
  821. TEST_F(OptionDefinitionTest, uint8Tokenized) {
  822. OptionDefinition opt_def("OPTION_PREFERENCE", D6O_PREFERENCE, "uint8");
  823. OptionPtr option_v6;
  824. std::vector<std::string> values;
  825. values.push_back("123");
  826. values.push_back("456");
  827. ASSERT_NO_THROW(
  828. option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
  829. );
  830. const Option* optptr = option_v6.get();
  831. ASSERT_TRUE(optptr);
  832. ASSERT_TRUE(typeid(*optptr) == typeid(OptionInt<uint8_t>));
  833. // Validate the value.
  834. boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
  835. boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
  836. EXPECT_EQ(123, option_cast_v6->getValue());
  837. // @todo Add more cases for DHCPv4
  838. }
  839. // The purpose of this test is to verify that definition for option that
  840. // comprises single uint16 value can be created and that this definition
  841. // can be used to create an option with single uint16 value.
  842. TEST_F(OptionDefinitionTest, uint16) {
  843. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  844. OptionPtr option_v6;
  845. // Try to use correct buffer length = 2 bytes.
  846. OptionBuffer buf;
  847. buf.push_back(1);
  848. buf.push_back(2);
  849. ASSERT_NO_THROW(
  850. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, buf);
  851. );
  852. const Option* optptr = option_v6.get();
  853. ASSERT_TRUE(optptr);
  854. ASSERT_TRUE(typeid(*optptr) == typeid(OptionInt<uint16_t>));
  855. // Validate the value.
  856. boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
  857. boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
  858. EXPECT_EQ(0x0102, option_cast_v6->getValue());
  859. // Try to provide zero-length buffer. Expect exception.
  860. EXPECT_THROW(
  861. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, OptionBuffer(1)),
  862. InvalidOptionValue
  863. );
  864. // @todo Add more cases for DHCPv4
  865. }
  866. // The purpose of this test is to verify that definition for option that
  867. // comprises single uint16 value can be created and that this definition
  868. // can be used to create an option with single uint16 value.
  869. TEST_F(OptionDefinitionTest, uint16Tokenized) {
  870. OptionDefinition opt_def("OPTION_ELAPSED_TIME", D6O_ELAPSED_TIME, "uint16");
  871. OptionPtr option_v6;
  872. std::vector<std::string> values;
  873. values.push_back("1234");
  874. values.push_back("5678");
  875. ASSERT_NO_THROW(
  876. option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, values);
  877. );
  878. const Option* optptr = option_v6.get();
  879. ASSERT_TRUE(optptr);
  880. ASSERT_TRUE(typeid(*optptr) == typeid(OptionInt<uint16_t>));
  881. // Validate the value.
  882. boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
  883. boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
  884. EXPECT_EQ(1234, option_cast_v6->getValue());
  885. // @todo Add more cases for DHCPv4
  886. }
  887. // The purpose of this test is to verify that definition for option that
  888. // comprises single uint32 value can be created and that this definition
  889. // can be used to create an option with single uint32 value.
  890. TEST_F(OptionDefinitionTest, uint32) {
  891. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  892. OptionPtr option_v6;
  893. OptionBuffer buf;
  894. buf.push_back(1);
  895. buf.push_back(2);
  896. buf.push_back(3);
  897. buf.push_back(4);
  898. ASSERT_NO_THROW(
  899. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, buf);
  900. );
  901. const Option* optptr = option_v6.get();
  902. ASSERT_TRUE(optptr);
  903. ASSERT_TRUE(typeid(*optptr) == typeid(OptionInt<uint32_t>));
  904. // Validate the value.
  905. boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
  906. boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
  907. EXPECT_EQ(0x01020304, option_cast_v6->getValue());
  908. // Try to provide too short buffer. Expect exception.
  909. EXPECT_THROW(
  910. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, OptionBuffer(2)),
  911. InvalidOptionValue
  912. );
  913. // @todo Add more cases for DHCPv4
  914. }
  915. // The purpose of this test is to verify that definition for option that
  916. // comprises single uint32 value can be created and that this definition
  917. // can be used to create an option with single uint32 value.
  918. TEST_F(OptionDefinitionTest, uint32Tokenized) {
  919. OptionDefinition opt_def("OPTION_CLT_TIME", D6O_CLT_TIME, "uint32");
  920. OptionPtr option_v6;
  921. std::vector<std::string> values;
  922. values.push_back("123456");
  923. values.push_back("789");
  924. ASSERT_NO_THROW(
  925. option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, values);
  926. );
  927. const Option* optptr = option_v6.get();
  928. ASSERT_TRUE(optptr);
  929. ASSERT_TRUE(typeid(*optptr) == typeid(OptionInt<uint32_t>));
  930. // Validate the value.
  931. boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
  932. boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
  933. EXPECT_EQ(123456, option_cast_v6->getValue());
  934. // @todo Add more cases for DHCPv4
  935. }
  936. // The purpose of this test is to verify that definition for option that
  937. // comprises array of uint16 values can be created and that this definition
  938. // can be used to create option with an array of uint16 values.
  939. TEST_F(OptionDefinitionTest, uint16Array) {
  940. // Let's define some dummy option.
  941. const uint16_t opt_code = 79;
  942. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  943. OptionPtr option_v6;
  944. // Positive scenario, initiate the buffer with length being
  945. // multiple of uint16_t size.
  946. // buffer elements will be: 0x112233.
  947. OptionBuffer buf(6);
  948. for (unsigned i = 0; i < 6; ++i) {
  949. buf[i] = i / 2;
  950. }
  951. // Constructor should succeed because buffer has correct size.
  952. EXPECT_NO_THROW(
  953. option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
  954. );
  955. const Option* optptr = option_v6.get();
  956. ASSERT_TRUE(optptr);
  957. ASSERT_TRUE(typeid(*optptr) == typeid(OptionIntArray<uint16_t>));
  958. boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
  959. boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
  960. // Get the values from the initiated options and validate.
  961. std::vector<uint16_t> values = option_cast_v6->getValues();
  962. for (size_t i = 0; i < values.size(); ++i) {
  963. // Expected value is calculated using on the same pattern
  964. // as the one we used to initiate buffer:
  965. // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
  966. uint16_t expected = (i << 8) | i;
  967. EXPECT_EQ(expected, values[i]);
  968. }
  969. // Provided buffer size must be greater than zero. Check if we
  970. // get exception if we provide zero-length buffer.
  971. EXPECT_THROW(
  972. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer()),
  973. InvalidOptionValue
  974. );
  975. // Buffer length must be multiple of data type size.
  976. EXPECT_THROW(
  977. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer(5)),
  978. InvalidOptionValue
  979. );
  980. }
  981. // The purpose of this test is to verify that definition for option that
  982. // comprises array of uint16 values can be created and that this definition
  983. // can be used to create option with an array of uint16 values.
  984. TEST_F(OptionDefinitionTest, uint16ArrayTokenized) {
  985. // Let's define some dummy option.
  986. const uint16_t opt_code = 79;
  987. OptionDefinition opt_def("OPTION_UINT16_ARRAY", opt_code, "uint16", true);
  988. OptionPtr option_v6;
  989. std::vector<std::string> str_values;
  990. str_values.push_back("12345");
  991. str_values.push_back("5679");
  992. str_values.push_back("12");
  993. EXPECT_NO_THROW(
  994. option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
  995. );
  996. const Option* optptr = option_v6.get();
  997. ASSERT_TRUE(optptr);
  998. ASSERT_TRUE(typeid(*optptr) == typeid(OptionIntArray<uint16_t>));
  999. boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
  1000. boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
  1001. // Get the values from the initiated options and validate.
  1002. std::vector<uint16_t> values = option_cast_v6->getValues();
  1003. EXPECT_EQ(12345, values[0]);
  1004. EXPECT_EQ(5679, values[1]);
  1005. EXPECT_EQ(12, values[2]);
  1006. }
  1007. // The purpose of this test is to verify that definition for option that
  1008. // comprises array of uint32 values can be created and that this definition
  1009. // can be used to create option with an array of uint32 values.
  1010. TEST_F(OptionDefinitionTest, uint32Array) {
  1011. // Let's define some dummy option.
  1012. const uint16_t opt_code = 80;
  1013. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  1014. OptionPtr option_v6;
  1015. // Positive scenario, initiate the buffer with length being
  1016. // multiple of uint16_t size.
  1017. // buffer elements will be: 0x111122223333.
  1018. OptionBuffer buf(12);
  1019. for (size_t i = 0; i < buf.size(); ++i) {
  1020. buf[i] = i / 4;
  1021. }
  1022. // Constructor should succeed because buffer has correct size.
  1023. EXPECT_NO_THROW(
  1024. option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
  1025. );
  1026. const Option* optptr = option_v6.get();
  1027. ASSERT_TRUE(optptr);
  1028. ASSERT_TRUE(typeid(*optptr) == typeid(OptionIntArray<uint32_t>));
  1029. boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
  1030. boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
  1031. // Get the values from the initiated options and validate.
  1032. std::vector<uint32_t> values = option_cast_v6->getValues();
  1033. for (size_t i = 0; i < values.size(); ++i) {
  1034. // Expected value is calculated using on the same pattern
  1035. // as the one we used to initiate buffer:
  1036. // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
  1037. uint32_t expected = 0x01010101 * i;
  1038. EXPECT_EQ(expected, values[i]);
  1039. }
  1040. // Provided buffer size must be greater than zero. Check if we
  1041. // get exception if we provide zero-length buffer.
  1042. EXPECT_THROW(
  1043. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer()),
  1044. InvalidOptionValue
  1045. );
  1046. // Buffer length must be multiple of data type size.
  1047. EXPECT_THROW(
  1048. option_v6 = opt_def.optionFactory(Option::V6, opt_code, OptionBuffer(5)),
  1049. InvalidOptionValue
  1050. );
  1051. }
  1052. // The purpose of this test is to verify that definition for option that
  1053. // comprises array of uint32 values can be created and that this definition
  1054. // can be used to create option with an array of uint32 values.
  1055. TEST_F(OptionDefinitionTest, uint32ArrayTokenized) {
  1056. // Let's define some dummy option.
  1057. const uint16_t opt_code = 80;
  1058. OptionDefinition opt_def("OPTION_UINT32_ARRAY", opt_code, "uint32", true);
  1059. OptionPtr option_v6;
  1060. std::vector<std::string> str_values;
  1061. str_values.push_back("123456");
  1062. // Try with hexadecimal
  1063. str_values.push_back("0x7");
  1064. str_values.push_back("256");
  1065. str_values.push_back("1111");
  1066. EXPECT_NO_THROW(
  1067. option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
  1068. );
  1069. const Option* optptr = option_v6.get();
  1070. ASSERT_TRUE(optptr);
  1071. ASSERT_TRUE(typeid(*optptr) == typeid(OptionIntArray<uint32_t>));
  1072. boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
  1073. boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
  1074. // Get the values from the initiated options and validate.
  1075. std::vector<uint32_t> values = option_cast_v6->getValues();
  1076. EXPECT_EQ(123456, values[0]);
  1077. EXPECT_EQ(7, values[1]);
  1078. EXPECT_EQ(256, values[2]);
  1079. EXPECT_EQ(1111, values[3]);
  1080. }
  1081. // The purpose of this test is to verify that the definition can be created
  1082. // for the option that comprises string value in the UTF8 format.
  1083. TEST_F(OptionDefinitionTest, utf8StringTokenized) {
  1084. // Let's create some dummy option.
  1085. const uint16_t opt_code = 80;
  1086. OptionDefinition opt_def("OPTION_WITH_STRING", opt_code, "string");
  1087. std::vector<std::string> values;
  1088. values.push_back("Hello World");
  1089. values.push_back("this string should not be included in the option");
  1090. OptionPtr option_v6;
  1091. EXPECT_NO_THROW(
  1092. option_v6 = opt_def.optionFactory(Option::V6, opt_code, values);
  1093. );
  1094. ASSERT_TRUE(option_v6);
  1095. const Option* optptr = option_v6.get();
  1096. ASSERT_TRUE(optptr);
  1097. ASSERT_TRUE(typeid(*optptr) == typeid(OptionString));
  1098. OptionStringPtr option_v6_string =
  1099. boost::static_pointer_cast<OptionString>(option_v6);
  1100. EXPECT_TRUE(values[0] == option_v6_string->getValue());
  1101. }
  1102. // The purpose of this test is to check that non-integer data type can't
  1103. // be used for factoryInteger function.
  1104. TEST_F(OptionDefinitionTest, integerInvalidType) {
  1105. // The template function factoryInteger<> accepts integer values only
  1106. // as template typename. Here we try passing different type and
  1107. // see if it rejects it.
  1108. OptionBuffer buf(1);
  1109. EXPECT_THROW(
  1110. OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, DHCP6_OPTION_SPACE,
  1111. buf.begin(), buf.end()),
  1112. isc::dhcp::InvalidDataType
  1113. );
  1114. }
  1115. // The purpose of this test is to verify that helper methods
  1116. // haveIA6Format and haveIAAddr6Format can be used to determine
  1117. // IA_NA and IAADDR option formats.
  1118. TEST_F(OptionDefinitionTest, haveIAFormat) {
  1119. // IA_NA option format.
  1120. OptionDefinition opt_def1("OPTION_IA_NA", D6O_IA_NA, "record");
  1121. for (int i = 0; i < 3; ++i) {
  1122. opt_def1.addRecordField("uint32");
  1123. }
  1124. EXPECT_TRUE(opt_def1.haveIA6Format());
  1125. // Create non-matching format to check that this function does not
  1126. // return 'true' all the time.
  1127. OptionDefinition opt_def2("OPTION_IA_NA", D6O_IA_NA, "uint16");
  1128. EXPECT_FALSE(opt_def2.haveIA6Format());
  1129. // IAADDR option format.
  1130. OptionDefinition opt_def3("OPTION_IAADDR", D6O_IAADDR, "record");
  1131. opt_def3.addRecordField("ipv6-address");
  1132. opt_def3.addRecordField("uint32");
  1133. opt_def3.addRecordField("uint32");
  1134. EXPECT_TRUE(opt_def3.haveIAAddr6Format());
  1135. // Create non-matching format to check that this function does not
  1136. // return 'true' all the time.
  1137. OptionDefinition opt_def4("OPTION_IAADDR", D6O_IAADDR, "uint32", true);
  1138. EXPECT_FALSE(opt_def4.haveIAAddr6Format());
  1139. }
  1140. // This test verifies that haveClientFqdnFormat function recognizes that option
  1141. // definition describes the format of DHCPv6 Client Fqdn Option Format.
  1142. TEST_F(OptionDefinitionTest, haveClientFqdnFormat) {
  1143. OptionDefinition opt_def("OPTION_CLIENT_FQDN", D6O_CLIENT_FQDN, "record");
  1144. opt_def.addRecordField("uint8");
  1145. opt_def.addRecordField("fqdn");
  1146. EXPECT_TRUE(opt_def.haveClientFqdnFormat());
  1147. // Create option format which is not matching the Client FQDN option format
  1148. // to verify that tested function does dont always return true.
  1149. OptionDefinition opt_def_invalid("OPTION_CLIENT_FQDN", D6O_CLIENT_FQDN,
  1150. "uint8");
  1151. EXPECT_FALSE(opt_def_invalid.haveClientFqdnFormat());
  1152. }
  1153. // This test verifies that a definition of an option with a single IPv6
  1154. // prefix can be created and used to create an instance of the option.
  1155. TEST_F(OptionDefinitionTest, prefix) {
  1156. OptionDefinition opt_def("option-prefix", 1000, "ipv6-prefix");
  1157. // Create a buffer holding a prefix.
  1158. OptionBuffer buf;
  1159. buf.push_back(32);
  1160. buf.push_back(0x30);
  1161. buf.push_back(0x00);
  1162. buf.resize(5);
  1163. OptionPtr option_v6;
  1164. // Create an instance of this option from the definition.
  1165. ASSERT_NO_THROW(
  1166. option_v6 = opt_def.optionFactory(Option::V6, 1000, buf);
  1167. );
  1168. // Make sure that the returned option class is correct.
  1169. const Option* optptr = option_v6.get();
  1170. ASSERT_TRUE(optptr);
  1171. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1172. // Validate the value.
  1173. OptionCustomPtr option_cast_v6 =
  1174. boost::dynamic_pointer_cast<OptionCustom>(option_v6);
  1175. ASSERT_EQ(1, option_cast_v6->getDataFieldsNum());
  1176. PrefixTuple prefix = option_cast_v6->readPrefix();
  1177. EXPECT_EQ(32, prefix.first.asUnsigned());
  1178. EXPECT_EQ("3000::", prefix.second.toText());
  1179. }
  1180. // This test verifies that a definition of an option with a single IPv6
  1181. // prefix can be created and that the instance of this option can be
  1182. // created by specifying the prefix in the textual format.
  1183. TEST_F(OptionDefinitionTest, prefixTokenized) {
  1184. OptionDefinition opt_def("option-prefix", 1000, "ipv6-prefix");
  1185. OptionPtr option_v6;
  1186. // Specify a single prefix.
  1187. std::vector<std::string> values(1, "2001:db8:1::/64");
  1188. // Create an instance of the option using the definition.
  1189. ASSERT_NO_THROW(
  1190. option_v6 = opt_def.optionFactory(Option::V6, 1000, values);
  1191. );
  1192. // Make sure that the returned option class is correct.
  1193. const Option* optptr = option_v6.get();
  1194. ASSERT_TRUE(optptr);
  1195. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1196. // Validate the value.
  1197. OptionCustomPtr option_cast_v6 =
  1198. boost::dynamic_pointer_cast<OptionCustom>(option_v6);
  1199. ASSERT_EQ(1, option_cast_v6->getDataFieldsNum());
  1200. PrefixTuple prefix = option_cast_v6->readPrefix();
  1201. EXPECT_EQ(64, prefix.first.asUnsigned());
  1202. EXPECT_EQ("2001:db8:1::", prefix.second.toText());
  1203. }
  1204. // This test verifies that a definition of an option with an array
  1205. // of IPv6 prefixes can be created and that the instance of this
  1206. // option can be created by specifying multiple prefixes in the
  1207. // textual format.
  1208. TEST_F(OptionDefinitionTest, prefixArrayTokenized) {
  1209. OptionDefinition opt_def("option-prefix", 1000, "ipv6-prefix", true);
  1210. OptionPtr option_v6;
  1211. // Specify 3 prefixes
  1212. std::vector<std::string> values;
  1213. values.push_back("2001:db8:1:: /64");
  1214. values.push_back("3000::/ 32");
  1215. values.push_back("3001:1:: / 48");
  1216. // Create an instance of an option using the definition.
  1217. ASSERT_NO_THROW(
  1218. option_v6 = opt_def.optionFactory(Option::V6, 1000, values);
  1219. );
  1220. // Make sure that the option class returned is correct.
  1221. const Option* optptr = option_v6.get();
  1222. ASSERT_TRUE(optptr);
  1223. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1224. OptionCustomPtr option_cast_v6 =
  1225. boost::dynamic_pointer_cast<OptionCustom>(option_v6);
  1226. // There should be 3 prefixes in this option.
  1227. ASSERT_EQ(3, option_cast_v6->getDataFieldsNum());
  1228. ASSERT_NO_THROW({
  1229. PrefixTuple prefix0 = option_cast_v6->readPrefix(0);
  1230. EXPECT_EQ(64, prefix0.first.asUnsigned());
  1231. EXPECT_EQ("2001:db8:1::", prefix0.second.toText());
  1232. });
  1233. ASSERT_NO_THROW({
  1234. PrefixTuple prefix1 = option_cast_v6->readPrefix(1);
  1235. EXPECT_EQ(32, prefix1.first.asUnsigned());
  1236. EXPECT_EQ("3000::", prefix1.second.toText());
  1237. });
  1238. ASSERT_NO_THROW({
  1239. PrefixTuple prefix2 = option_cast_v6->readPrefix(2);
  1240. EXPECT_EQ(48, prefix2.first.asUnsigned());
  1241. EXPECT_EQ("3001:1::", prefix2.second.toText());
  1242. });
  1243. }
  1244. // This test verifies that a definition of an option with a single PSID
  1245. // value can be created and used to create an instance of the option.
  1246. TEST_F(OptionDefinitionTest, psid) {
  1247. OptionDefinition opt_def("option-psid", 1000, "psid");
  1248. OptionPtr option_v6;
  1249. // Create a buffer holding PSID.
  1250. OptionBuffer buf;
  1251. buf.push_back(6);
  1252. buf.push_back(0x4);
  1253. buf.push_back(0x0);
  1254. // Create an instance of this option from the definition.
  1255. ASSERT_NO_THROW(
  1256. option_v6 = opt_def.optionFactory(Option::V6, 1000, buf);
  1257. );
  1258. // Make sure that the returned option class is correct.
  1259. const Option* optptr = option_v6.get();
  1260. ASSERT_TRUE(optptr);
  1261. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1262. // Validate the value.
  1263. OptionCustomPtr option_cast_v6 =
  1264. boost::dynamic_pointer_cast<OptionCustom>(option_v6);
  1265. ASSERT_EQ(1, option_cast_v6->getDataFieldsNum());
  1266. PSIDTuple psid = option_cast_v6->readPsid();
  1267. EXPECT_EQ(6, psid.first.asUnsigned());
  1268. EXPECT_EQ(1, psid.second.asUint16());
  1269. }
  1270. // This test verifies that a definition of an option with a single PSID
  1271. // value can be created and that the instance of this option can be
  1272. // created by specifying PSID length and value in the textual format.
  1273. TEST_F(OptionDefinitionTest, psidTokenized) {
  1274. OptionDefinition opt_def("option-psid", 1000, "psid");
  1275. OptionPtr option_v6;
  1276. // Specify a single PSID with a length of 6 and value of 3.
  1277. std::vector<std::string> values(1, "3 / 6");
  1278. // Create an instance of the option using the definition.
  1279. ASSERT_NO_THROW(
  1280. option_v6 = opt_def.optionFactory(Option::V6, 1000, values);
  1281. );
  1282. // Make sure that the returned option class is correct.
  1283. const Option* optptr = option_v6.get();
  1284. ASSERT_TRUE(optptr);
  1285. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1286. // Validate the value.
  1287. OptionCustomPtr option_cast_v6 =
  1288. boost::dynamic_pointer_cast<OptionCustom>(option_v6);
  1289. ASSERT_EQ(1, option_cast_v6->getDataFieldsNum());
  1290. PSIDTuple psid = option_cast_v6->readPsid();
  1291. EXPECT_EQ(6, psid.first.asUnsigned());
  1292. EXPECT_EQ(3, psid.second.asUint16());
  1293. }
  1294. // This test verifies that a definition of an option with an array
  1295. // of PSIDs can be created and that the instance of this option can be
  1296. // created by specifying multiple PSIDs in the textual format.
  1297. TEST_F(OptionDefinitionTest, psidArrayTokenized) {
  1298. OptionDefinition opt_def("option-psid", 1000, "psid", true);
  1299. OptionPtr option_v6;
  1300. // Specify 3 PSIDs.
  1301. std::vector<std::string> values;
  1302. values.push_back("3 / 6");
  1303. values.push_back("0/1");
  1304. values.push_back("7 / 3");
  1305. // Create an instance of an option using the definition.
  1306. ASSERT_NO_THROW(
  1307. option_v6 = opt_def.optionFactory(Option::V6, 1000, values);
  1308. );
  1309. // Make sure that the option class returned is correct.
  1310. const Option* optptr = option_v6.get();
  1311. ASSERT_TRUE(optptr);
  1312. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1313. OptionCustomPtr option_cast_v6 =
  1314. boost::dynamic_pointer_cast<OptionCustom>(option_v6);
  1315. // There should be 3 PSIDs in this option.
  1316. ASSERT_EQ(3, option_cast_v6->getDataFieldsNum());
  1317. // Check their values.
  1318. PSIDTuple psid0;
  1319. PSIDTuple psid1;
  1320. PSIDTuple psid2;
  1321. psid0 = option_cast_v6->readPsid(0);
  1322. EXPECT_EQ(6, psid0.first.asUnsigned());
  1323. EXPECT_EQ(3, psid0.second.asUint16());
  1324. psid1 = option_cast_v6->readPsid(1);
  1325. EXPECT_EQ(1, psid1.first.asUnsigned());
  1326. EXPECT_EQ(0, psid1.second.asUint16());
  1327. psid2 = option_cast_v6->readPsid(2);
  1328. EXPECT_EQ(3, psid2.first.asUnsigned());
  1329. EXPECT_EQ(7, psid2.second.asUint16());
  1330. }
  1331. // This test verifies that a definition of an option with a single DHCPv4
  1332. // tuple can be created and used to create an instance of the option.
  1333. TEST_F(OptionDefinitionTest, tuple4) {
  1334. OptionDefinition opt_def("option-tuple", 232, "tuple");
  1335. OptionPtr option;
  1336. // Create a buffer holding tuple
  1337. const char data[] = {
  1338. 6, 102, 111, 111, 98, 97, 114 // "foobar"
  1339. };
  1340. OptionBuffer buf(data, data + sizeof(data));
  1341. // Create an instance of this option from the definition.
  1342. ASSERT_NO_THROW(
  1343. option = opt_def.optionFactory(Option::V4, 232, buf);
  1344. );
  1345. // Make sure that the returned option class is correct.
  1346. const Option* optptr = option.get();
  1347. ASSERT_TRUE(optptr);
  1348. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1349. // Validate the value.
  1350. OptionCustomPtr option_cast =
  1351. boost::dynamic_pointer_cast<OptionCustom>(option);
  1352. ASSERT_EQ(1, option_cast->getDataFieldsNum());
  1353. OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
  1354. ASSERT_NO_THROW(option_cast->readTuple(tuple));
  1355. EXPECT_EQ("foobar", tuple.getText());
  1356. }
  1357. // This test verifies that a definition of an option with a single DHCPv6
  1358. // tuple can be created and used to create an instance of the option.
  1359. TEST_F(OptionDefinitionTest, tuple6) {
  1360. OptionDefinition opt_def("option-tuple", 1000, "tuple");
  1361. OptionPtr option;
  1362. // Create a buffer holding tuple
  1363. const char data[] = {
  1364. 0, 6, 102, 111, 111, 98, 97, 114 // "foobar"
  1365. };
  1366. OptionBuffer buf(data, data + sizeof(data));
  1367. // Create an instance of this option from the definition.
  1368. ASSERT_NO_THROW(
  1369. option = opt_def.optionFactory(Option::V6, 1000, buf);
  1370. );
  1371. // Make sure that the returned option class is correct.
  1372. const Option* optptr = option.get();
  1373. ASSERT_TRUE(optptr);
  1374. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1375. // Validate the value.
  1376. OptionCustomPtr option_cast =
  1377. boost::dynamic_pointer_cast<OptionCustom>(option);
  1378. ASSERT_EQ(1, option_cast->getDataFieldsNum());
  1379. OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
  1380. ASSERT_NO_THROW(option_cast->readTuple(tuple));
  1381. EXPECT_EQ("foobar", tuple.getText());
  1382. }
  1383. // This test verifies that a definition of an option with a single DHCPv4
  1384. // tuple can be created and that the instance of this option can be
  1385. // created by specifying tuple value in the textual format.
  1386. TEST_F(OptionDefinitionTest, tuple4Tokenized) {
  1387. OptionDefinition opt_def("option-tuple", 232, "tuple");
  1388. OptionPtr option;
  1389. // Specify a single tuple with "foobar" content.
  1390. std::vector<std::string> values(1, "foobar");
  1391. // Create an instance of this option using the definition.
  1392. ASSERT_NO_THROW(
  1393. option = opt_def.optionFactory(Option::V4, 232, values);
  1394. );
  1395. // Make sure that the returned option class is correct.
  1396. const Option* optptr = option.get();
  1397. ASSERT_TRUE(optptr);
  1398. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1399. // Validate the value.
  1400. OptionCustomPtr option_cast =
  1401. boost::dynamic_pointer_cast<OptionCustom>(option);
  1402. ASSERT_EQ(1, option_cast->getDataFieldsNum());
  1403. OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
  1404. ASSERT_NO_THROW(option_cast->readTuple(tuple));
  1405. EXPECT_EQ("foobar", tuple.getText());
  1406. }
  1407. // This test verifies that a definition of an option with a single DHCPv6
  1408. // tuple can be created and that the instance of this option can be
  1409. // created by specifying tuple value in the textual format.
  1410. TEST_F(OptionDefinitionTest, tuple6Tokenized) {
  1411. OptionDefinition opt_def("option-tuple", 1000, "tuple");
  1412. OptionPtr option;
  1413. // Specify a single tuple with "foobar" content.
  1414. std::vector<std::string> values(1, "foobar");
  1415. // Create an instance of this option using the definition.
  1416. ASSERT_NO_THROW(
  1417. option = opt_def.optionFactory(Option::V6, 1000, values);
  1418. );
  1419. // Make sure that the returned option class is correct.
  1420. const Option* optptr = option.get();
  1421. ASSERT_TRUE(optptr);
  1422. ASSERT_TRUE(typeid(*optptr) == typeid(OptionCustom));
  1423. // Validate the value.
  1424. OptionCustomPtr option_cast =
  1425. boost::dynamic_pointer_cast<OptionCustom>(option);
  1426. ASSERT_EQ(1, option_cast->getDataFieldsNum());
  1427. OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
  1428. ASSERT_NO_THROW(option_cast->readTuple(tuple));
  1429. EXPECT_EQ("foobar", tuple.getText());
  1430. }
  1431. // This test verifies that a definition of an option with an array
  1432. // of DHCPv4 tuples can be created and that the instance of this option
  1433. // can be created by specifying multiple DHCPv4 tuples in the textual format.
  1434. TEST_F(OptionDefinitionTest, tuple4ArrayTokenized) {
  1435. OptionDefinition opt_def("option-tuple", 232, "tuple", true);
  1436. OptionPtr option;
  1437. // Specify 3 tuples.
  1438. std::vector<std::string> values;
  1439. values.push_back("hello");
  1440. values.push_back("the");
  1441. values.push_back("world");
  1442. // Create an instance of this option using the definition.
  1443. ASSERT_NO_THROW(
  1444. option = opt_def.optionFactory(Option::V4, 232, values);
  1445. );
  1446. // Make sure that the returned option class is correct.
  1447. const Option* optptr = option.get();
  1448. ASSERT_TRUE(optptr);
  1449. ASSERT_TRUE(typeid(*optptr) == typeid(OptionOpaqueDataTuples));
  1450. // Validate the value.
  1451. OptionOpaqueDataTuplesPtr option_cast =
  1452. boost::dynamic_pointer_cast<OptionOpaqueDataTuples>(option);
  1453. // There should be 3 tuples in this option.
  1454. ASSERT_EQ(3, option_cast->getTuplesNum());
  1455. // Check their values.
  1456. OpaqueDataTuple tuple0 = option_cast->getTuple(0);
  1457. EXPECT_EQ("hello", tuple0.getText());
  1458. OpaqueDataTuple tuple1 = option_cast->getTuple(1);
  1459. EXPECT_EQ("the", tuple1.getText());
  1460. OpaqueDataTuple tuple2 = option_cast->getTuple(2);
  1461. EXPECT_EQ("world", tuple2.getText());
  1462. }
  1463. // This test verifies that a definition of an option with an array
  1464. // of DHCPv6 tuples can be created and that the instance of this option
  1465. // can be created by specifying multiple DHCPv6 tuples in the textual format.
  1466. TEST_F(OptionDefinitionTest, tuple6ArrayTokenized) {
  1467. OptionDefinition opt_def("option-tuple", 1000, "tuple", true);
  1468. OptionPtr option;
  1469. // Specify 3 tuples.
  1470. std::vector<std::string> values;
  1471. values.push_back("hello");
  1472. values.push_back("the");
  1473. values.push_back("world");
  1474. // Create an instance of this option using the definition.
  1475. ASSERT_NO_THROW(
  1476. option = opt_def.optionFactory(Option::V6, 1000, values);
  1477. );
  1478. // Make sure that the returned option class is correct.
  1479. const Option* optptr = option.get();
  1480. ASSERT_TRUE(optptr);
  1481. ASSERT_TRUE(typeid(*optptr) == typeid(OptionOpaqueDataTuples));
  1482. // Validate the value.
  1483. OptionOpaqueDataTuplesPtr option_cast =
  1484. boost::dynamic_pointer_cast<OptionOpaqueDataTuples>(option);
  1485. // There should be 3 tuples in this option.
  1486. ASSERT_EQ(3, option_cast->getTuplesNum());
  1487. // Check their values.
  1488. OpaqueDataTuple tuple0 = option_cast->getTuple(0);
  1489. EXPECT_EQ("hello", tuple0.getText());
  1490. OpaqueDataTuple tuple1 = option_cast->getTuple(1);
  1491. EXPECT_EQ("the", tuple1.getText());
  1492. OpaqueDataTuple tuple2 = option_cast->getTuple(2);
  1493. EXPECT_EQ("world", tuple2.getText());
  1494. }
  1495. } // anonymous namespace