summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcp/tests/libdhcp++_unittest.cc
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2024-06-27 10:03:43 +0200
committerFrancis Dupont <fdupont@isc.org>2024-07-19 17:48:57 +0200
commit2366ac079b62e4339e64c1081492a0fe8481f052 (patch)
tree2474d4819a4634020f78c8fc7454b80703f3808f /src/lib/dhcp/tests/libdhcp++_unittest.cc
parent[#3440] Checkpoint: updated compatible UTs (diff)
downloadkea-2366ac079b62e4339e64c1081492a0fe8481f052.tar.xz
kea-2366ac079b62e4339e64c1081492a0fe8481f052.zip
[#3440] Checkpoint: updated all UTs
Diffstat (limited to 'src/lib/dhcp/tests/libdhcp++_unittest.cc')
-rw-r--r--src/lib/dhcp/tests/libdhcp++_unittest.cc536
1 files changed, 536 insertions, 0 deletions
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index 2992949816..d101810b09 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -268,6 +268,137 @@ public:
/// @brief Test which verifies that split options for v4 is working correctly.
///
+ /// @param bottom_opt The packet option.
+ /// @param middle_opt The packet option.
+ /// @param top_opt The packet option.
+ static void splitOptionWithSuboptionAtLimit(OptionPtr bottom_opt,
+ OptionPtr middle_opt,
+ OptionPtr top_opt) {
+ uint32_t bottom_size = 128;
+ uint32_t middle_size = 1;
+ uint32_t top_size = 249;
+ isc::util::OutputBuffer buf(0);
+ Pkt4Ptr pkt(new Pkt4(DHCPOFFER, 1234));
+ OptionCollection& col = pkt->options_;
+ col.clear();
+ col.insert(std::make_pair(170, bottom_opt));
+ uint32_t index = 0;
+ uint8_t opt_count = 0;
+ std::string expected = pkt->toText();
+ {
+ ScopedPkt4OptionsCopy initial_scoped_options(*pkt);
+ ManagedScopedOptionsCopyContainer scoped_options;
+ ASSERT_NO_THROW(LibDHCP::splitOptions4(col, scoped_options.scoped_options_));
+ ASSERT_NO_THROW(LibDHCP::packOptions4(buf, col, true));
+ ASSERT_NE(expected, pkt->toText());
+
+ for (auto const& opt : col) {
+ ASSERT_LE(opt.second->len(), 255);
+ }
+
+ ASSERT_EQ(3 * bottom_opt->getHeaderLen() + 2 * middle_opt->getHeaderLen() +
+ top_opt->getHeaderLen() + bottom_size + middle_size + top_size,
+ buf.getLength());
+
+ ASSERT_EQ(3, col.size());
+ for (auto const& bottom_subopt : col) {
+ ASSERT_EQ(bottom_subopt.second->getType(), 170);
+ if (opt_count == 0) {
+ // First option contains only data (0..127) and no suboptions.
+ ASSERT_EQ(bottom_subopt.second->getData().size(), bottom_size);
+ index = 0;
+ for (auto const& value : bottom_subopt.second->getData()) {
+ ASSERT_EQ(value, static_cast<uint8_t>(index));
+ index++;
+ }
+ ASSERT_EQ(bottom_subopt.second->getOptions().size(), 0);
+ } else {
+ // All other options contain no data and suboption 171.
+ ASSERT_EQ(bottom_subopt.second->getOptions().size(), 1);
+ for (auto const& middle_subopt : bottom_subopt.second->getOptions()) {
+ ASSERT_EQ(middle_subopt.first, 171);
+ if (opt_count == 1) {
+ // First suboption 171 contains only data (0) and no suboptions.
+ ASSERT_EQ(middle_subopt.second->getData().size(), middle_size);
+ index = 0;
+ for (auto const& value : middle_subopt.second->getData()) {
+ ASSERT_EQ(value, static_cast<uint8_t>(index));
+ index++;
+ }
+ ASSERT_EQ(middle_subopt.second->getOptions().size(), 0);
+ } else {
+ // Second suboption 171 contains no data and suboption 172.
+ ASSERT_EQ(middle_subopt.second->getData().size(), 0);
+ ASSERT_EQ(middle_subopt.second->getOptions().size(), 1);
+ auto const& top_subopt = middle_subopt.second->getOptions().find(172);
+ ASSERT_NE(top_subopt, middle_subopt.second->getOptions().end());
+ ASSERT_EQ(top_subopt->second->getType(), 172);
+ // Suboption 172 contains only data (0..248) and no suboptions.
+ ASSERT_EQ(top_subopt->second->getData().size(), top_size);
+ index = 0;
+ for (auto const& value : top_subopt->second->getData()) {
+ ASSERT_EQ(value, static_cast<uint8_t>(index));
+ index++;
+ }
+ ASSERT_EQ(top_subopt->second->getOptions().size(), 0);
+ }
+ }
+ }
+ opt_count++;
+ }
+ }
+ ASSERT_EQ(expected, pkt->toText());
+
+ OptionCollection col_back;
+ std::list<uint16_t> deferred_options;
+
+ size_t opts_len = buf.getLength();
+ vector<uint8_t> opts_buffer;
+ InputBuffer buffer_in(buf.getData(), opts_len);
+
+ // Use readVector because a function which parses option requires
+ // a vector as an input.
+ buffer_in.readVector(opts_buffer, opts_len);
+ ASSERT_NO_THROW(LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE,
+ col_back, deferred_options));
+
+ ASSERT_EQ(1, col_back.size());
+ EXPECT_EQ(170, col_back.begin()->first);
+ OptionPtr opt_back = col_back.begin()->second;
+ ASSERT_TRUE(opt_back);
+
+ // Using unpackOptions4 will not create suboptions, so entire
+ // data is serialized in the option buffer.
+ ASSERT_EQ(opt_back->getOptions().size(), 0);
+ OptionBuffer opt_data;
+ // Data 0..127
+ index = 0;
+ while (index < bottom_size) {
+ opt_data.push_back(index);
+ ++index;
+ }
+ // First sub-option 171
+ opt_data.push_back(171);
+ opt_data.push_back(middle_size);
+ // Data (0)
+ opt_data.push_back(0);
+ // Second sub-option 171
+ opt_data.push_back(171);
+ opt_data.push_back(top_opt->getHeaderLen() + top_size);
+ // Sub-sub=option 172
+ opt_data.push_back(172);
+ opt_data.push_back(top_size);
+ // Data 0..248
+ index = 0;
+ while (index < top_size) {
+ opt_data.push_back(index);
+ ++index;
+ }
+ EXPECT_EQ(opt_data, opt_back->getData());
+ }
+
+ /// @brief Test which verifies that split options for v4 is working correctly.
+ ///
/// @param option The packet option.
static void splitLongOption(OptionPtr option) {
isc::util::OutputBuffer buf(0);
@@ -1028,6 +1159,122 @@ TEST_F(LibDhcpTest, splitOptionOneByteLeftBufferMultiThreading) {
}
// This test verifies that split options for v4 is working correctly.
+TEST_F(LibDhcpTest, splitOptionWithSuboptionAtLimit) {
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ uint32_t bottom_size = 128;
+ OptionBuffer bottom_buf_in(bottom_size);
+ for (uint32_t i = 0; i < bottom_size; ++i) {
+ bottom_buf_in[i] = i;
+ }
+
+ OptionDefinitionPtr top_def(new OptionDefinition("top", 170, DHCP4_OPTION_SPACE, OPT_BINARY_TYPE, "miggle"));
+ OptionPtr bottom_opt(new OptionCustom(*top_def, Option::V4, bottom_buf_in));
+ ASSERT_TRUE(bottom_opt);
+
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ uint32_t middle_size = 1;
+ OptionBuffer middle_buf_in(middle_size);
+ for (uint32_t i = 0; i < middle_size; ++i) {
+ middle_buf_in[i] = i;
+ }
+
+ OptionDefinitionPtr middle_def(new OptionDefinition("top", 171, "middle", OPT_BINARY_TYPE, ""));
+ OptionPtr middle_opt(new OptionCustom(*middle_def, Option::V4, middle_buf_in));
+ ASSERT_TRUE(middle_opt);
+ bottom_opt->addOption(middle_opt);
+
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ uint32_t top_size = 249;
+ OptionBuffer top_buf_in(top_size);
+ for (uint32_t i = 0; i < top_size; ++i) {
+ top_buf_in[i] = i;
+ }
+
+ OptionPtr top_opt(new Option(Option::V4, 172, top_buf_in));
+ ASSERT_TRUE(top_opt);
+ middle_opt->addOption(top_opt);
+
+ OptionDefSpaceContainer defs;
+ defs.addItem(top_def);
+ defs.addItem(middle_def);
+ LibDHCP::setRuntimeOptionDefs(defs);
+ LibDHCP::commitRuntimeOptionDefs();
+
+ splitOptionWithSuboptionAtLimit(bottom_opt, middle_opt, top_opt);
+}
+
+// This test verifies that split options for v4 is working correctly.
+TEST_F(LibDhcpTest, splitOptionWithSuboptionAtLimitMultiThreading) {
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ uint32_t bottom_size = 128;
+ OptionBuffer bottom_buf_in(bottom_size);
+ for (uint32_t i = 0; i < bottom_size; ++i) {
+ bottom_buf_in[i] = i;
+ }
+
+ OptionDefinitionPtr top_def(new OptionDefinition("top", 170, DHCP4_OPTION_SPACE, OPT_BINARY_TYPE, "miggle"));
+ OptionPtr bottom_opt(new OptionCustom(*top_def, Option::V4, bottom_buf_in));
+ ASSERT_TRUE(bottom_opt);
+
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ uint32_t middle_size = 1;
+ OptionBuffer middle_buf_in(middle_size);
+ for (uint32_t i = 0; i < middle_size; ++i) {
+ middle_buf_in[i] = i;
+ }
+
+ OptionDefinitionPtr middle_def(new OptionDefinition("top", 171, "middle", OPT_BINARY_TYPE, ""));
+ OptionPtr middle_opt(new OptionCustom(*middle_def, Option::V4, middle_buf_in));
+ ASSERT_TRUE(middle_opt);
+ bottom_opt->addOption(middle_opt);
+
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ uint32_t top_size = 249;
+ OptionBuffer top_buf_in(top_size);
+ for (uint32_t i = 0; i < top_size; ++i) {
+ top_buf_in[i] = i;
+ }
+
+ OptionPtr top_opt(new Option(Option::V4, 172, top_buf_in));
+ ASSERT_TRUE(top_opt);
+ middle_opt->addOption(top_opt);
+
+ OptionDefSpaceContainer defs;
+ defs.addItem(top_def);
+ defs.addItem(middle_def);
+ LibDHCP::setRuntimeOptionDefs(defs);
+ LibDHCP::commitRuntimeOptionDefs();
+
+ typedef function<void()> CallBack;
+ ThreadPool<CallBack> tp;
+ tp.start(256);
+
+ // Options are shared between threads to mimic the server defined options
+ // in the packet which are added from running configuration.
+ for (uint32_t count = 0; count < 1024; ++count) {
+ auto const& work = [&] {
+ splitOptionWithSuboptionAtLimit(bottom_opt, middle_opt, top_opt);
+ };
+
+ boost::shared_ptr<CallBack> call_back = boost::make_shared<CallBack>(work);
+ tp.add(call_back);
+ }
+ ASSERT_TRUE(tp.wait(30));
+}
+
+// This test verifies that split options for v4 is working correctly.
TEST_F(LibDhcpTest, splitLongOption) {
OptionDefinition opt_def("option-foo", 231, "my-space", "binary",
"option-foo-space");
@@ -1265,6 +1512,295 @@ TEST_F(LibDhcpTest, splitLongOptionWithLongSuboptionMultiThreading) {
ASSERT_TRUE(tp.wait(30));
}
+// This test verifies that fuse options for v4 is working correctly.
+TEST_F(LibDhcpTest, fuseLongOption) {
+ OptionCollection col;
+
+ OptionDefinition opt_def("option-foo", 231, "my-space", "binary",
+ "option-foo-space");
+
+ for (uint32_t i = 0; i < 256; ++i) {
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ OptionBuffer buf_in(64);
+ for (uint32_t j = 0; j < 64; ++j) {
+ buf_in[j] = j;
+ }
+
+ boost::shared_ptr<OptionCustom> option;
+ ASSERT_NO_THROW(option.reset(new OptionCustom(opt_def, Option::V4, buf_in)));
+ ASSERT_TRUE(option);
+ col.insert(std::make_pair(231, option));
+ }
+ ASSERT_EQ(256, col.size());
+ isc::util::OutputBuffer buf(0);
+ ASSERT_NO_THROW(LibDHCP::packOptions4(buf, col, true));
+
+ OptionCollection col_back;
+ std::list<uint16_t> deferred_options;
+
+ size_t opts_len = buf.getLength();
+ vector<uint8_t> opts_buffer;
+ InputBuffer buffer_in(buf.getData(), opts_len);
+ // Use readVector because a function which parses option requires
+ // a vector as an input.
+ buffer_in.readVector(opts_buffer, opts_len);
+ ASSERT_NO_THROW(LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE,
+ col_back, deferred_options));
+
+ ASSERT_EQ(1, col_back.size());
+ uint8_t index = 0;
+ for (auto const& option : col_back) {
+ EXPECT_EQ(231, option.first);
+ for (auto const& value : option.second->getData()) {
+ EXPECT_EQ(index, value);
+ index++;
+ if (index == 64) {
+ index = 0;
+ }
+ }
+ }
+}
+
+// This test verifies that fuse options for v4 is working correctly.
+TEST_F(LibDhcpTest, fuseLongOptionWithLongSuboption) {
+ OptionCollection col;
+
+ const OptionDefinition& rai_def = LibDHCP::DHO_DHCP_AGENT_OPTIONS_DEF();
+ // Create RAI options which should be fused by the server.
+ OptionCustomPtr rai(new OptionCustom(rai_def, Option::V4));
+
+ for (uint32_t i = 0; i < 256; ++i) {
+ // Create a buffer holding some binary data. This data will be
+ // used as reference when we read back the data from a created
+ // option.
+ OptionBuffer buf_in(64);
+ for (uint32_t j = 0; j < 64; ++j) {
+ buf_in[j] = j;
+ }
+
+ OptionPtr circuit_id_opt(new Option(Option::V4,
+ RAI_OPTION_AGENT_CIRCUIT_ID, buf_in));
+ ASSERT_TRUE(circuit_id_opt);
+ rai->addOption(circuit_id_opt);
+ }
+ col.insert(std::make_pair(213, rai));
+ ASSERT_EQ(1, col.size());
+ ASSERT_EQ(256, col.begin()->second->getOptions().size());
+ isc::util::OutputBuffer buf(0);
+ ManagedScopedOptionsCopyContainer scoped_options;
+ ASSERT_NO_THROW(LibDHCP::splitOptions4(col, scoped_options.scoped_options_, 0));
+ ASSERT_NO_THROW(LibDHCP::packOptions4(buf, col, true));
+
+ OptionCollection col_back;
+ std::list<uint16_t> deferred_options;
+
+ size_t opts_len = buf.getLength();
+ vector<uint8_t> opts_buffer;
+ InputBuffer buffer_in(buf.getData(), opts_len);
+ // Use readVector because a function which parses option requires
+ // a vector as an input.
+ buffer_in.readVector(opts_buffer, opts_len);
+ ASSERT_NO_THROW(LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE,
+ col_back, deferred_options));
+
+ ASSERT_EQ(1, col_back.size());
+ ASSERT_EQ(1, col_back.begin()->second->getOptions().size());
+ uint8_t index = 0;
+ auto const& options = col_back.begin()->second->getOptions();
+ for (auto const& option : options) {
+ EXPECT_EQ(RAI_OPTION_AGENT_CIRCUIT_ID, option.first);
+ for (auto const& value : option.second->getData()) {
+ EXPECT_EQ(index, value);
+ index++;
+ if (index == 64) {
+ index = 0;
+ }
+ }
+ }
+}
+
+// This test checks that the server can receive multiple vendor options
+// (code 124) with some using the same enterprise ID and some using a different
+// enterprise ID. It should also be able to extend one option which contains
+// multiple enterprise IDs in multiple instances of OptionVendor.
+// The extendVendorOptions4 should be able to create one instance for each
+// enterprise ID, each with it's respective tuples.
+// Some of the test scenarios are not following RFCs, but people out there are
+// like to do it anyway. We want Kea to be robust and handle such scenarios,
+// therefore we're testing also for non-conformant behavior.
+TEST_F(LibDhcpTest, extendVivco) {
+ OptionBuffer data1 = {
+ 0, 0, 0, 1, // enterprise id 1
+ 5, // length 5
+ 0x66, 0x69, 0x72, 0x73, 0x74, // 'first'
+ 0, 0, 0, 1, // enterprise id 1
+ 6, // length 6
+ 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64 // 'second'
+ };
+ OptionPtr opt1(new Option(Option::V4, DHO_VIVCO_SUBOPTIONS,
+ data1.cbegin(), data1.cend()));
+ OptionBuffer data2 = {
+ 0, 0, 0, 2, // enterprise id 2
+ 5, // length 5
+ 0x65, 0x78, 0x74, 0x72, 0x61 // 'extra'
+ };
+ OptionPtr opt2(new Option(Option::V4, DHO_VIVCO_SUBOPTIONS,
+ data2.cbegin(), data2.cend()));
+ OptionBuffer data3 = {
+ 0, 0, 0, 1, // enterprise id 1
+ 5, // length 5
+ 0x74, 0x68, 0x69, 0x72, 0x64 // 'third'
+ };
+ OptionPtr opt3(new Option(Option::V4, DHO_VIVCO_SUBOPTIONS,
+ data3.cbegin(), data3.cend()));
+ OptionCollection options;
+ options.insert(make_pair(DHO_VIVCO_SUBOPTIONS, opt1));
+ options.insert(make_pair(DHO_VIVCO_SUBOPTIONS, opt2));
+ options.insert(make_pair(DHO_VIVCO_SUBOPTIONS, opt3));
+ EXPECT_EQ(options.size(), 3);
+
+ // Fuse options.
+ isc::util::OutputBuffer buf(0);
+ ASSERT_NO_THROW(LibDHCP::packOptions4(buf, options, true));
+ size_t opts_len = buf.getLength();
+ vector<uint8_t> opts_buffer;
+ InputBuffer buffer_in(buf.getData(), opts_len);
+ // Use readVector because a function which parses option requires
+ // a vector as an input.
+ buffer_in.readVector(opts_buffer, opts_len);
+ std::list<uint16_t> deferred_options;
+ options.clear();
+ ASSERT_NO_THROW(LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE,
+ options, deferred_options));
+
+ EXPECT_EQ(options.size(), 1);
+ EXPECT_NO_THROW(LibDHCP::extendVendorOptions4(options));
+ EXPECT_EQ(options.size(), 2);
+ EXPECT_EQ(options.count(DHO_VIVCO_SUBOPTIONS), 2);
+ for (auto const& option : options) {
+ ASSERT_EQ(option.second->getType(), DHO_VIVCO_SUBOPTIONS);
+ OptionVendorClassPtr vendor =
+ boost::dynamic_pointer_cast<OptionVendorClass>(option.second);
+ ASSERT_TRUE(vendor);
+ if (vendor->getVendorId() == 1) {
+ ASSERT_EQ(vendor->getTuplesNum(), 3);
+ OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
+ ASSERT_NO_THROW(tuple = vendor->getTuple(0));
+ EXPECT_EQ(5, tuple.getLength());
+ EXPECT_EQ("first", tuple.getText());
+ ASSERT_NO_THROW(tuple = vendor->getTuple(1));
+ EXPECT_EQ(6, tuple.getLength());
+ EXPECT_EQ("second", tuple.getText());
+ ASSERT_NO_THROW(tuple = vendor->getTuple(2));
+ EXPECT_EQ(5, tuple.getLength());
+ EXPECT_EQ("third", tuple.getText());
+ } else if (vendor->getVendorId() == 2) {
+ ASSERT_EQ(vendor->getTuplesNum(), 1);
+ OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
+ ASSERT_NO_THROW(tuple = vendor->getTuple(0));
+ EXPECT_EQ(5, tuple.getLength());
+ EXPECT_EQ("extra", tuple.getText());
+ } else {
+ FAIL() << "unexpected vendor type: " << vendor->getVendorId();
+ }
+ }
+}
+
+// This test checks that the server can receive multiple vendor options
+// (code 125) with some using the same enterprise ID and some using a different
+// enterprise ID. It should also be able to extend one option which contains
+// multiple enterprise IDs in multiple instances of OptionVendor.
+// The extendVendorOptions4 should be able to create one instance for each
+// enterprise ID, each with it's respective suboptions.
+// Some of the test scenarios are not following RFCs, but people out there are
+// like to do it anyway. We want Kea to be robust and handle such scenarios,
+// therefore we're testing also for non-conformant behavior.
+TEST_F(LibDhcpTest, extendVivso) {
+ OptionPtr suboption;
+ OptionVendorPtr opt1(new OptionVendor(Option::V4, 1));
+ suboption.reset(new OptionString(Option::V4, 16, "first"));
+ opt1->addOption(suboption);
+ OptionVendorPtr opt2(new OptionVendor(Option::V4, 1));
+ suboption.reset(new OptionString(Option::V4, 32, "second"));
+ opt2->addOption(suboption);
+ OptionVendorPtr opt3(new OptionVendor(Option::V4, 2));
+ suboption.reset(new OptionString(Option::V4, 128, "extra"));
+ opt3->addOption(suboption);
+ OptionVendorPtr opt4(new OptionVendor(Option::V4, 1));
+ suboption.reset(new OptionString(Option::V4, 64, "third"));
+ opt4->addOption(suboption);
+ OptionCollection container;
+ container.insert(make_pair(DHO_VIVSO_SUBOPTIONS, opt1));
+ container.insert(make_pair(DHO_VIVSO_SUBOPTIONS, opt2));
+ OptionCollection options;
+ for (auto const& option : container) {
+ const OptionBuffer& buffer = option.second->toBinary();
+ options.insert(make_pair(option.second->getType(),
+ OptionPtr(new Option(Option::V4,
+ option.second->getType(),
+ buffer))));
+ }
+
+ // Fuse options.
+ isc::util::OutputBuffer buf(0);
+ ASSERT_NO_THROW(LibDHCP::packOptions4(buf, options, true));
+ size_t opts_len = buf.getLength();
+ vector<uint8_t> opts_buffer;
+ InputBuffer buffer_in(buf.getData(), opts_len);
+ // Use readVector because a function which parses option requires
+ // a vector as an input.
+ buffer_in.readVector(opts_buffer, opts_len);
+ std::list<uint16_t> deferred_options;
+ options.clear();
+ ASSERT_NO_THROW(LibDHCP::unpackOptions4(opts_buffer, DHCP4_OPTION_SPACE,
+ options, deferred_options));
+
+ ASSERT_EQ(options.size(), 1);
+ ASSERT_EQ(options.count(DHO_VIVSO_SUBOPTIONS), 1);
+ ASSERT_EQ(options.find(DHO_VIVSO_SUBOPTIONS)->second->getType(), DHO_VIVSO_SUBOPTIONS);
+ container.clear();
+ container.insert(make_pair(DHO_VIVSO_SUBOPTIONS, options.begin()->second));
+ container.insert(make_pair(DHO_VIVSO_SUBOPTIONS, opt3));
+ container.insert(make_pair(DHO_VIVSO_SUBOPTIONS, opt4));
+ ASSERT_EQ(container.size(), 3);
+ options.clear();
+ for (auto const& option : container) {
+ const OptionBuffer& buffer = option.second->toBinary();
+ options.insert(make_pair(option.second->getType(),
+ OptionPtr(new Option(Option::V4,
+ option.second->getType(),
+ buffer))));
+ }
+ ASSERT_EQ(options.size(), 3);
+ LibDHCP::extendVendorOptions4(options);
+ ASSERT_EQ(options.size(), 2);
+ ASSERT_EQ(options.count(DHO_VIVSO_SUBOPTIONS), 2);
+ for (auto const& option : options) {
+ ASSERT_EQ(option.second->getType(), DHO_VIVSO_SUBOPTIONS);
+ OptionCollection suboptions = option.second->getOptions();
+ OptionPtr subopt;
+ OptionVendorPtr vendor = boost::dynamic_pointer_cast<OptionVendor>(option.second);
+ ASSERT_TRUE(vendor);
+ if (vendor->getVendorId() == 1) {
+ ASSERT_EQ(suboptions.size(), 3);
+ subopt = option.second->getOption(16);
+ ASSERT_TRUE(subopt);
+ subopt = option.second->getOption(32);
+ ASSERT_TRUE(subopt);
+ subopt = option.second->getOption(64);
+ ASSERT_TRUE(subopt);
+ } else if (vendor->getVendorId() == 2) {
+ ASSERT_EQ(suboptions.size(), 1);
+ subopt = option.second->getOption(128);
+ ASSERT_TRUE(subopt);
+ } else {
+ FAIL() << "unexpected vendor type: " << vendor->getVendorId();
+ }
+ }
+}
+
// This test verifies that pack options for v4 is working correctly.
TEST_F(LibDhcpTest, packOptions4) {
vector<uint8_t> payload[5];