cfg_option_unittest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. // Copyright (C) 2014-2016 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 <dhcp/dhcp6.h>
  8. #include <dhcp/option.h>
  9. #include <dhcp/option_int.h>
  10. #include <dhcp/option_space.h>
  11. #include <dhcpsrv/cfg_option.h>
  12. #include <boost/foreach.hpp>
  13. #include <boost/pointer_cast.hpp>
  14. #include <gtest/gtest.h>
  15. #include <iterator>
  16. #include <limits>
  17. #include <list>
  18. #include <sstream>
  19. using namespace isc;
  20. using namespace isc::dhcp;
  21. namespace {
  22. /// This class fixture for testing @c CfgOption class, holding option
  23. /// configuration.
  24. class CfgOptionTest : public ::testing::Test {
  25. public:
  26. /// @brief Generates encapsulated options and adds them to CfgOption
  27. ///
  28. /// This method generates the following options:
  29. /// - 1000-1019 options: uint16 with value 1234, encapsulate "foo"
  30. /// - 1-19 options: uint8 with value 1, encapsulate "foo-subs"
  31. /// - 1-9 options: uint8 with value 3
  32. /// - 1020-1039 options: uint16 with value 2345, encapsulate "bar"
  33. /// - 100-119 options: uint8 with value 2, encapsulate "bar-subs"
  34. /// - 501-509 options: uint8 with value 4
  35. void generateEncapsulatedOptions(CfgOption& cfg) {
  36. // Create top-level options encapsulating "foo" option space.
  37. for (uint16_t code = 1000; code < 1020; ++code) {
  38. OptionUint16Ptr option = OptionUint16Ptr(new OptionUint16(Option::V6,
  39. code, 1234));
  40. option->setEncapsulatedSpace("foo");
  41. ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
  42. }
  43. // Create top level options encapsulating "bar" option space.
  44. for (uint16_t code = 1020; code < 1040; ++code) {
  45. OptionUint16Ptr option = OptionUint16Ptr(new OptionUint16(Option::V6,
  46. code, 2345));
  47. option->setEncapsulatedSpace("bar");
  48. ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
  49. }
  50. // Create sub-options belonging to "foo" option space and encapsulating
  51. // foo-subs option space.
  52. for (uint16_t code = 1; code < 20; ++code) {
  53. OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6, code,
  54. 0x01));
  55. option->setEncapsulatedSpace("foo-subs");
  56. ASSERT_NO_THROW(cfg.add(option, false, "foo"));
  57. }
  58. // Create sub-options belonging to "bar" option space and encapsulating
  59. // bar-subs option space.
  60. for (uint16_t code = 100; code < 119; ++code) {
  61. OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6,
  62. code, 0x02));
  63. option->setEncapsulatedSpace("bar-subs");
  64. ASSERT_NO_THROW(cfg.add(option, false, "bar"));
  65. }
  66. // Create sub-options belonging to "foo-subs" option space.
  67. for (uint16_t code = 1; code < 10; ++code) {
  68. OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6, code,
  69. 0x03));
  70. ASSERT_NO_THROW(cfg.add(option, false, "foo-subs"));
  71. }
  72. // Create sub-options belonging to "bar-subs" option space.
  73. for (uint16_t code = 501; code < 510; ++code) {
  74. OptionUint8Ptr option = OptionUint8Ptr(new OptionUint8(Option::V6,
  75. code, 0x04));
  76. ASSERT_NO_THROW(cfg.add(option, false, "bar-subs"));
  77. }
  78. }
  79. };
  80. // This test verifies the empty predicate.
  81. TEST_F(CfgOptionTest, empty) {
  82. CfgOption cfg1;
  83. CfgOption cfg2;
  84. // Initially the option configurations should be empty.
  85. ASSERT_TRUE(cfg1.empty());
  86. ASSERT_TRUE(cfg2.empty());
  87. // Add an option to each configuration
  88. OptionPtr option(new Option(Option::V6, 1));
  89. ASSERT_NO_THROW(cfg1.add(option, false, DHCP6_OPTION_SPACE));
  90. ASSERT_NO_THROW(cfg2.add(option, true, "isc"));
  91. // The first option configuration has an option
  92. ASSERT_FALSE(cfg1.empty());
  93. // The second option configuration has a vendor option
  94. ASSERT_FALSE(cfg2.empty());
  95. }
  96. // This test verifies that the option configurations can be compared.
  97. TEST_F(CfgOptionTest, equals) {
  98. CfgOption cfg1;
  99. CfgOption cfg2;
  100. // Initially the configurations should be equal.
  101. ASSERT_TRUE(cfg1 == cfg2);
  102. ASSERT_FALSE(cfg1 != cfg2);
  103. // Add 9 options to two different option spaces. Each option have different
  104. // option code and content.
  105. for (uint16_t code = 1; code < 10; ++code) {
  106. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, code)));
  107. ASSERT_NO_THROW(cfg1.add(option, false, "isc"));
  108. ASSERT_NO_THROW(cfg1.add(option, true, "vendor-123"));
  109. }
  110. // Configurations should now be different.
  111. ASSERT_FALSE(cfg1 == cfg2);
  112. ASSERT_TRUE(cfg1 != cfg2);
  113. // Add 8 options (excluding the option with code 1) to the same option
  114. // spaces.
  115. for (uint16_t code = 2; code < 10; ++code) {
  116. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, code)));
  117. ASSERT_NO_THROW(cfg2.add(option, false, "isc"));
  118. ASSERT_NO_THROW(cfg2.add(option, true, "vendor-123"));
  119. }
  120. // Configurations should still be unequal.
  121. ASSERT_FALSE(cfg1 == cfg2);
  122. ASSERT_TRUE(cfg1 != cfg2);
  123. // Add missing option to the option space isc.
  124. ASSERT_NO_THROW(cfg2.add(OptionPtr(new Option(Option::V6, 1,
  125. OptionBuffer(10, 0x01))),
  126. false, "isc"));
  127. // Configurations should still be unequal because option with code 1
  128. // is missing in the option space vendor-123.
  129. ASSERT_FALSE(cfg1 == cfg2);
  130. ASSERT_TRUE(cfg1 != cfg2);
  131. // Add missing option.
  132. ASSERT_NO_THROW(cfg2.add(OptionPtr(new Option(Option::V6, 1,
  133. OptionBuffer(10, 0x01))),
  134. true, "vendor-123"));
  135. // Configurations should now be equal.
  136. ASSERT_TRUE(cfg1 == cfg2);
  137. ASSERT_FALSE(cfg1 != cfg2);
  138. }
  139. // This test verifies that multiple options can be added to the configuration
  140. // and that they can be retrieved using the option space name.
  141. TEST_F(CfgOptionTest, add) {
  142. CfgOption cfg;
  143. // Differentiate options by their codes (100-109)
  144. for (uint16_t code = 100; code < 110; ++code) {
  145. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  146. ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
  147. }
  148. // Add 7 options to another option space. The option codes partially overlap
  149. // with option codes that we have added to dhcp6 option space.
  150. for (uint16_t code = 105; code < 112; ++code) {
  151. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  152. ASSERT_NO_THROW(cfg.add(option, false, "isc"));
  153. }
  154. // Get options from the Subnet and check if all 10 are there.
  155. OptionContainerPtr options = cfg.getAll(DHCP6_OPTION_SPACE);
  156. ASSERT_TRUE(options);
  157. ASSERT_EQ(10, options->size());
  158. // Validate codes of options added to dhcp6 option space.
  159. uint16_t expected_code = 100;
  160. for (OptionContainer::const_iterator option_desc = options->begin();
  161. option_desc != options->end(); ++option_desc) {
  162. ASSERT_TRUE(option_desc->option_);
  163. EXPECT_EQ(expected_code, option_desc->option_->getType());
  164. ++expected_code;
  165. }
  166. options = cfg.getAll("isc");
  167. ASSERT_TRUE(options);
  168. ASSERT_EQ(7, options->size());
  169. // Validate codes of options added to isc option space.
  170. expected_code = 105;
  171. for (OptionContainer::const_iterator option_desc = options->begin();
  172. option_desc != options->end(); ++option_desc) {
  173. ASSERT_TRUE(option_desc->option_);
  174. EXPECT_EQ(expected_code, option_desc->option_->getType());
  175. ++expected_code;
  176. }
  177. // Try to get options from a non-existing option space.
  178. options = cfg.getAll("abcd");
  179. ASSERT_TRUE(options);
  180. EXPECT_TRUE(options->empty());
  181. }
  182. // This test verifies that two option configurations can be merged.
  183. TEST_F(CfgOptionTest, merge) {
  184. CfgOption cfg_src;
  185. CfgOption cfg_dst;
  186. // Create collection of options in option space dhcp6, with option codes
  187. // from the range of 100 to 109 and holding one byte of data equal to 0xFF.
  188. for (uint16_t code = 100; code < 110; ++code) {
  189. OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
  190. ASSERT_NO_THROW(cfg_src.add(option, false, DHCP6_OPTION_SPACE));
  191. }
  192. // Create collection of options in vendor space 123, with option codes
  193. // from the range of 100 to 109 and holding one byte of data equal to 0xFF.
  194. for (uint16_t code = 100; code < 110; code += 2) {
  195. OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
  196. ASSERT_NO_THROW(cfg_src.add(option, false, "vendor-123"));
  197. }
  198. // Create destination configuration (configuration that we merge the
  199. // other configuration to).
  200. // Create collection of options having even option codes in the range of
  201. // 100 to 108.
  202. for (uint16_t code = 100; code < 110; code += 2) {
  203. OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0x01)));
  204. ASSERT_NO_THROW(cfg_dst.add(option, false, DHCP6_OPTION_SPACE));
  205. }
  206. // Create collection of options having odd option codes in the range of
  207. // 101 to 109.
  208. for (uint16_t code = 101; code < 110; code += 2) {
  209. OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0x01)));
  210. ASSERT_NO_THROW(cfg_dst.add(option, false, "vendor-123"));
  211. }
  212. // Merge source configuration to the destination configuration. The options
  213. // in the destination should be preserved. The options from the source
  214. // configuration should be added.
  215. ASSERT_NO_THROW(cfg_src.mergeTo(cfg_dst));
  216. // Validate the options in the dhcp6 option space in the destination.
  217. for (uint16_t code = 100; code < 110; ++code) {
  218. OptionDescriptor desc = cfg_dst.get(DHCP6_OPTION_SPACE, code);
  219. ASSERT_TRUE(desc.option_);
  220. ASSERT_EQ(1, desc.option_->getData().size());
  221. // The options with even option codes should hold one byte of data
  222. // equal to 0x1. These are the ones that we have initially added to
  223. // the destination configuration. The other options should hold the
  224. // values of 0xFF which indicates that they have been merged from the
  225. // source configuration.
  226. if ((code % 2) == 0) {
  227. EXPECT_EQ(0x01, desc.option_->getData()[0]);
  228. } else {
  229. EXPECT_EQ(0xFF, desc.option_->getData()[0]);
  230. }
  231. }
  232. // Validate the options in the vendor space.
  233. for (uint16_t code = 100; code < 110; ++code) {
  234. OptionDescriptor desc = cfg_dst.get(123, code);
  235. ASSERT_TRUE(desc.option_);
  236. ASSERT_EQ(1, desc.option_->getData().size());
  237. // This time, the options with even option codes should hold a byte
  238. // of data equal to 0xFF. The other options should hold the byte of
  239. // data equal to 0x01.
  240. if ((code % 2) == 0) {
  241. EXPECT_EQ(0xFF, desc.option_->getData()[0]);
  242. } else {
  243. EXPECT_EQ(0x01, desc.option_->getData()[0]);
  244. }
  245. }
  246. }
  247. // This test verifies that the options configuration can be copied between
  248. // objects.
  249. TEST_F(CfgOptionTest, copy) {
  250. CfgOption cfg_src;
  251. // Add 10 options to the custom option space in the source configuration.
  252. for (uint16_t code = 100; code < 110; ++code) {
  253. OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0x01)));
  254. ASSERT_NO_THROW(cfg_src.add(option, false, "foo"));
  255. }
  256. CfgOption cfg_dst;
  257. // Add 20 options to the custom option space in destination configuration.
  258. for (uint16_t code = 100; code < 120; ++code) {
  259. OptionPtr option(new Option(Option::V6, code, OptionBuffer(1, 0xFF)));
  260. ASSERT_NO_THROW(cfg_dst.add(option, false, "isc"));
  261. }
  262. // Copy entire configuration to the destination. This should override any
  263. // existing data.
  264. ASSERT_NO_THROW(cfg_src.copyTo(cfg_dst));
  265. // Validate options in the destination configuration.
  266. for (uint16_t code = 100; code < 110; ++code) {
  267. OptionDescriptor desc = cfg_dst.get("foo", code);
  268. ASSERT_TRUE(desc.option_);
  269. ASSERT_EQ(1, desc.option_->getData().size());
  270. EXPECT_EQ(0x01, desc.option_->getData()[0]);
  271. }
  272. // Any existing options should be removed.
  273. OptionContainerPtr container = cfg_dst.getAll("isc");
  274. ASSERT_TRUE(container);
  275. EXPECT_TRUE(container->empty());
  276. // The option space "foo" should contain exactly 10 options.
  277. container = cfg_dst.getAll("foo");
  278. ASSERT_TRUE(container);
  279. EXPECT_EQ(10, container->size());
  280. }
  281. // This test verifies that encapsulated options are added as sub-options
  282. // to the top level options on request.
  283. TEST_F(CfgOptionTest, encapsulate) {
  284. CfgOption cfg;
  285. generateEncapsulatedOptions(cfg);
  286. // Append options from "foo" and "bar" space as sub-options and options
  287. // from "foo-subs" and "bar-subs" as sub-options of "foo" and "bar"
  288. // options.
  289. ASSERT_NO_THROW(cfg.encapsulate());
  290. // Verify that we have 40 top-level options.
  291. OptionContainerPtr options = cfg.getAll(DHCP6_OPTION_SPACE);
  292. ASSERT_EQ(40, options->size());
  293. // Iterate over top level options.
  294. for (uint16_t code = 1000; code < 1040; ++code) {
  295. OptionUint16Ptr option = boost::dynamic_pointer_cast<
  296. OptionUint16>(cfg.get(DHCP6_OPTION_SPACE, code).option_);
  297. ASSERT_TRUE(option) << "option with code " << code << " not found";
  298. // First level sub options. There are 19 sub-options for each top
  299. // level option.
  300. const OptionCollection& first_level = option->getOptions();
  301. ASSERT_EQ(19, first_level.size());
  302. // Iterate over all first level sub-options.
  303. std::pair<unsigned int, OptionPtr> first_level_opt;
  304. BOOST_FOREACH(first_level_opt, first_level) {
  305. // Each option in this test comprises a single one byte field and
  306. // should cast to OptionUint8 type.
  307. OptionUint8Ptr first_level_uint8 = boost::dynamic_pointer_cast<
  308. OptionUint8>(first_level_opt.second);
  309. ASSERT_TRUE(first_level_uint8);
  310. const unsigned int value = static_cast<unsigned int>(first_level_uint8->getValue());
  311. // There are two sets of first level sub-options. Those that include
  312. // a value of 1 and those that include a value of 2.
  313. if (first_level_uint8->getType() < 20) {
  314. EXPECT_EQ(1, value);
  315. } else {
  316. EXPECT_EQ(2, value);
  317. }
  318. // Each first level sub-option should include 9 second level
  319. // sub options.
  320. const OptionCollection& second_level = first_level_uint8->getOptions();
  321. ASSERT_EQ(9, second_level.size());
  322. // Iterate over sub-options and make sure they include the expected
  323. // values.
  324. std::pair<unsigned int, OptionPtr> second_level_opt;
  325. BOOST_FOREACH(second_level_opt, second_level) {
  326. OptionUint8Ptr second_level_uint8 = boost::dynamic_pointer_cast<
  327. OptionUint8>(second_level_opt.second);
  328. ASSERT_TRUE(second_level_uint8);
  329. const unsigned value = static_cast<
  330. unsigned>(second_level_uint8->getValue());
  331. // Certain sub-options should have a value of 3, other the values
  332. // of 4.
  333. if (second_level_uint8->getType() < 20) {
  334. EXPECT_EQ(3, value);
  335. } else {
  336. EXPECT_EQ(4, value);
  337. }
  338. }
  339. }
  340. }
  341. }
  342. // This test verifies that single option can be retrieved from the configuration
  343. // using option code and option space.
  344. TEST_F(CfgOptionTest, get) {
  345. CfgOption cfg;
  346. // Add 10 options to a "dhcp6" option space in the subnet.
  347. for (uint16_t code = 100; code < 110; ++code) {
  348. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  349. ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
  350. }
  351. // Check that we can get each added option descriptor using
  352. // individually.
  353. for (uint16_t code = 100; code < 110; ++code) {
  354. std::ostringstream stream;
  355. // First, try the invalid option space name.
  356. OptionDescriptor desc = cfg.get("isc", code);
  357. // Returned descriptor should contain NULL option ptr.
  358. EXPECT_FALSE(desc.option_);
  359. // Now, try the valid option space.
  360. desc = cfg.get(DHCP6_OPTION_SPACE, code);
  361. // Test that the option code matches the expected code.
  362. ASSERT_TRUE(desc.option_);
  363. EXPECT_EQ(code, desc.option_->getType());
  364. }
  365. }
  366. // This test verifies that the same options can be added to the configuration
  367. // under different option space.
  368. TEST_F(CfgOptionTest, addNonUniqueOptions) {
  369. CfgOption cfg;
  370. // Create a set of options with non-unique codes.
  371. for (int i = 0; i < 2; ++i) {
  372. // In the inner loop we create options with unique codes (100-109).
  373. for (uint16_t code = 100; code < 110; ++code) {
  374. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  375. ASSERT_NO_THROW(cfg.add(option, false, DHCP6_OPTION_SPACE));
  376. }
  377. }
  378. // Sanity check that all options are there.
  379. OptionContainerPtr options = cfg.getAll(DHCP6_OPTION_SPACE);
  380. ASSERT_EQ(20, options->size());
  381. // Use container index #1 to get the options by their codes.
  382. OptionContainerTypeIndex& idx = options->get<1>();
  383. // Look for the codes 100-109.
  384. for (uint16_t code = 100; code < 110; ++ code) {
  385. // For each code we should get two instances of options->
  386. std::pair<OptionContainerTypeIndex::const_iterator,
  387. OptionContainerTypeIndex::const_iterator> range =
  388. idx.equal_range(code);
  389. // Distance between iterators indicates how many options
  390. // have been retured for the particular code.
  391. ASSERT_EQ(2, distance(range.first, range.second));
  392. // Check that returned options actually have the expected option code.
  393. for (OptionContainerTypeIndex::const_iterator option_desc = range.first;
  394. option_desc != range.second; ++option_desc) {
  395. ASSERT_TRUE(option_desc->option_);
  396. EXPECT_EQ(code, option_desc->option_->getType());
  397. }
  398. }
  399. // Let's try to find some non-exiting option.
  400. const uint16_t non_existing_code = 150;
  401. std::pair<OptionContainerTypeIndex::const_iterator,
  402. OptionContainerTypeIndex::const_iterator> range =
  403. idx.equal_range(non_existing_code);
  404. // Empty set is expected.
  405. EXPECT_EQ(0, distance(range.first, range.second));
  406. }
  407. // This test verifies that the option with the persistency flag can be
  408. // added to the configuration and that options with the persistency flags
  409. // can be retrieved.
  410. TEST(Subnet6Test, addPersistentOption) {
  411. CfgOption cfg;
  412. // Add 10 options to the subnet with option codes 100 - 109.
  413. for (uint16_t code = 100; code < 110; ++code) {
  414. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  415. // We create 10 options and want some of them to be flagged
  416. // persistent and some non-persistent. Persistent options are
  417. // those that server sends to clients regardless if they ask
  418. // for them or not. We pick 3 out of 10 options and mark them
  419. // non-persistent and 7 other options persistent.
  420. // Code values: 102, 105 and 108 are divisible by 3
  421. // and options with these codes will be flagged non-persistent.
  422. // Options with other codes will be flagged persistent.
  423. bool persistent = (code % 3) ? true : false;
  424. ASSERT_NO_THROW(cfg.add(option, persistent, DHCP6_OPTION_SPACE));
  425. }
  426. // Get added options from the subnet.
  427. OptionContainerPtr options = cfg.getAll(DHCP6_OPTION_SPACE);
  428. // options->get<2> returns reference to container index #2. This
  429. // index is used to access options by the 'persistent' flag.
  430. OptionContainerPersistIndex& idx = options->get<2>();
  431. // Get all persistent options->
  432. std::pair<OptionContainerPersistIndex::const_iterator,
  433. OptionContainerPersistIndex::const_iterator> range_persistent =
  434. idx.equal_range(true);
  435. // 3 out of 10 options have been flagged persistent.
  436. ASSERT_EQ(7, distance(range_persistent.first, range_persistent.second));
  437. // Get all non-persistent options->
  438. std::pair<OptionContainerPersistIndex::const_iterator,
  439. OptionContainerPersistIndex::const_iterator> range_non_persistent =
  440. idx.equal_range(false);
  441. // 7 out of 10 options have been flagged persistent.
  442. ASSERT_EQ(3, distance(range_non_persistent.first, range_non_persistent.second));
  443. }
  444. // This test verifies that the vendor option can be added to the configuration.
  445. TEST_F(CfgOptionTest, addVendorOptions) {
  446. CfgOption cfg;
  447. // Differentiate options by their codes (100-109)
  448. for (uint16_t code = 100; code < 110; ++code) {
  449. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  450. ASSERT_NO_THROW(cfg.add(option, false, "vendor-12345678"));
  451. }
  452. // Second option space uses corner case value for vendor id = max uint8.
  453. uint32_t vendor_id = std::numeric_limits<uint32_t>::max();
  454. std::ostringstream option_space;
  455. option_space << "vendor-" << vendor_id;
  456. // Add 7 options to another option space. The option codes partially overlap
  457. // with option codes that we have added to dhcp6 option space.
  458. for (uint16_t code = 105; code < 112; ++code) {
  459. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  460. ASSERT_NO_THROW(cfg.add(option, false, option_space.str()));
  461. }
  462. // Get options from the Subnet and check if all 10 are there.
  463. OptionContainerPtr options = cfg.getAll(12345678);
  464. ASSERT_TRUE(options);
  465. ASSERT_EQ(10, options->size());
  466. // Validate codes of options added to dhcp6 option space.
  467. uint16_t expected_code = 100;
  468. for (OptionContainer::const_iterator option_desc = options->begin();
  469. option_desc != options->end(); ++option_desc) {
  470. ASSERT_TRUE(option_desc->option_);
  471. EXPECT_EQ(expected_code, option_desc->option_->getType());
  472. ++expected_code;
  473. }
  474. options = cfg.getAll(vendor_id);
  475. ASSERT_TRUE(options);
  476. ASSERT_EQ(7, options->size());
  477. // Validate codes of options added to isc option space.
  478. expected_code = 105;
  479. for (OptionContainer::const_iterator option_desc = options->begin();
  480. option_desc != options->end(); ++option_desc) {
  481. ASSERT_TRUE(option_desc->option_);
  482. EXPECT_EQ(expected_code, option_desc->option_->getType());
  483. ++expected_code;
  484. }
  485. // Try to get options from a non-existing option space.
  486. options = cfg.getAll(1111111);
  487. ASSERT_TRUE(options);
  488. EXPECT_TRUE(options->empty());
  489. }
  490. // This test verifies that option space names for the vendor options are
  491. // correct.
  492. TEST_F(CfgOptionTest, getVendorIdsSpaceNames) {
  493. CfgOption cfg;
  494. // Create 10 options, each goes under a different vendor id.
  495. for (uint16_t code = 100; code < 110; ++code) {
  496. OptionPtr option(new Option(Option::V6, code, OptionBuffer(10, 0xFF)));
  497. // Generate space name for a unique vendor id.
  498. std::ostringstream s;
  499. s << "vendor-" << code;
  500. ASSERT_NO_THROW(cfg.add(option, false, s.str()));
  501. }
  502. // We should now have 10 different vendor ids.
  503. std::list<std::string> space_names = cfg.getVendorIdsSpaceNames();
  504. ASSERT_EQ(10, space_names.size());
  505. // Check that the option space names for those vendor ids are correct.
  506. for (std::list<std::string>::iterator name = space_names.begin();
  507. name != space_names.end(); ++name) {
  508. uint16_t id = static_cast<uint16_t>(std::distance(space_names.begin(),
  509. name));
  510. std::ostringstream s;
  511. s << "vendor-" << (100 + id);
  512. EXPECT_EQ(s.str(), *name);
  513. }
  514. }
  515. } // end of anonymous namespace