]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#2517] Added unit tests
authorFrancis Dupont <fdupont@isc.org>
Tue, 2 Aug 2022 16:44:04 +0000 (18:44 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 3 Aug 2022 13:26:10 +0000 (15:26 +0200)
src/bin/dhcp6/tests/vendor_opts_unittest.cc
src/lib/dhcp/tests/pkt6_unittest.cc

index 3789a377eb1ae2a2a1d6234751a3325d4b8d8772..83722721f8794a429857fbfa38b3702b83b016b5 100644 (file)
@@ -642,7 +642,7 @@ TEST_F(VendorOptsTest, vendorOpsInResponseOnly) {
 
 // Checks if it's possible to have 2 vendor-class options and 2 vendor-opts
 // options with different vendor IDs.
-TEST_F(VendorOptsTest, multipleVendor) {
+TEST_F(VendorOptsTest, twoVendors) {
     Dhcp6Client client;
 
     // The config defines 2 vendors with for each a vendor-class option,
@@ -732,7 +732,7 @@ TEST_F(VendorOptsTest, multipleVendor) {
         if (vendor_id == 1234) {
             ASSERT_FALSE(opt_class1234);
             opt_class1234 = opt_class;
-            break;
+            continue;
         }
         ASSERT_EQ(5678, vendor_id);
         ASSERT_FALSE(opt_class5678);
@@ -764,7 +764,7 @@ TEST_F(VendorOptsTest, multipleVendor) {
         if (vendor_id == 1234) {
             ASSERT_FALSE(opt_opts1234);
             opt_opts1234 = opt_opts;
-            break;
+            continue;
         }
         ASSERT_EQ(5678, vendor_id);
         ASSERT_FALSE(opt_opts5678);
@@ -774,7 +774,6 @@ TEST_F(VendorOptsTest, multipleVendor) {
     // Verify first vendor-opts option.
     ASSERT_TRUE(opt_opts1234);
     OptionCollection subs1234 = opt_opts1234->getOptions();
-    cerr << "opts1234: " << opt_opts1234->toText() << "\n";
     ASSERT_EQ(1, subs1234.size());
     OptionPtr sub1234 = subs1234.begin()->second;
     ASSERT_TRUE(sub1234);
@@ -797,4 +796,156 @@ TEST_F(VendorOptsTest, multipleVendor) {
     EXPECT_EQ("bar", opt_bar->getValue());
 }
 
+// Checks if it's possible to have 3 vendor-opts options with
+// different vendor IDs selected using the 3 ways (vendor-opts in
+// response, vendor-opts in query and vendor-class in query).
+TEST_F(VendorOptsTest, threeVendors) {
+    Dhcp6Client client;
+
+    // The config defines 2 vendors with for each a vendor-opts option
+    // and a custom vendor suboption, and a suboption for DOCSIS.
+    string config =
+        "{"
+        "    \"interfaces-config\": {"
+        "        \"interfaces\": [ ]"
+        "    },"
+        "    \"option-def\": ["
+        "        {"
+        "            \"name\": \"foo\","
+        "            \"code\": 123,"
+        "            \"space\": \"vendor-1234\","
+        "            \"type\": \"string\""
+        "        },"
+        "        {"
+        "            \"name\": \"bar\","
+        "            \"code\": 456,"
+        "            \"space\": \"vendor-5678\","
+        "            \"type\": \"string\""
+        "        },"
+        "        {"
+        "            \"name\": \"config-file\","
+        "            \"code\": 33,"
+        "            \"space\": \"vendor-4491\","
+        "            \"type\": \"string\""
+        "        }"
+        "    ],"
+        "    \"option-data\": ["
+        "        {"
+        "            \"name\": \"vendor-opts\","
+        "            \"always-send\": true,"
+        "            \"data\": \"1234\""
+        "        },"
+        "        {"
+        "            \"name\": \"vendor-opts\","
+        "            \"data\": \"5678\""
+        "        },"
+        "        {"
+        "            \"name\": \"foo\","
+        "            \"always-send\": true,"
+        "            \"space\": \"vendor-1234\","
+        "            \"data\": \"foo\""
+        "        },"
+        "        {"
+        "            \"name\": \"bar\","
+        "            \"always-send\": true,"
+        "            \"space\": \"vendor-5678\","
+        "            \"data\": \"bar\""
+        "        },"
+        "        {"
+        "            \"name\": \"config-file\","
+        "            \"space\": \"vendor-4491\","
+        "            \"data\": \"normal_erouter_v6.cm\""
+        "        }"
+        "    ],"
+        "\"subnet6\": [ { "
+        "    \"pools\": [ { \"pool\": \"2001:db8::/64\" } ],"
+        "    \"subnet\": \"2001:db8::/64\", "
+        "    \"interface\": \"eth0\" "
+        " } ]"
+        "}";
+
+    EXPECT_NO_THROW(configure(config, *client.getServer()));
+
+    // Add a vendor-class for vendor id 5678.
+    OptionVendorClassPtr cclass(new OptionVendorClass(Option::V6, 5678));
+    OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
+    tuple = "bar";
+    cclass->addTuple(tuple);
+    client.addExtraOption(cclass);
+
+    // Add a DOCSIS vendor-opts with an ORO.
+    OptionUint16ArrayPtr oro(new OptionUint16Array(Option::V6, DOCSIS3_V6_ORO));
+    oro->addValue(DOCSIS3_V6_CONFIG_FILE); // Request option 33.
+    OptionPtr vendor(new OptionVendor(Option::V6, 4491));
+    vendor->addOption(oro);
+    client.addExtraOption(vendor);
+
+    // Let's check whether the server is not able to process this packet.
+    EXPECT_NO_THROW(client.doSolicit());
+    ASSERT_TRUE(client.getContext().response_);
+
+    // Check there're vendor-opts options.
+    const OptionCollection& options =
+        client.getContext().response_->getOptions(D6O_VENDOR_OPTS);
+    ASSERT_EQ(3, options.size());
+    OptionVendorPtr opt_opts1234;
+    OptionVendorPtr opt_docsis;
+    OptionVendorPtr opt_opts5678;
+    for (auto opt : options) {
+        ASSERT_EQ(D6O_VENDOR_OPTS, opt.first);
+        OptionVendorPtr opt_opts =
+            boost::dynamic_pointer_cast<OptionVendor>(opt.second);
+        ASSERT_TRUE(opt_opts);
+        uint32_t vendor_id = opt_opts->getVendorId();
+        if (vendor_id == 1234) {
+            ASSERT_FALSE(opt_opts1234);
+            opt_opts1234 = opt_opts;
+            continue;
+        }
+        if (vendor_id == 4491) {
+            ASSERT_FALSE(opt_docsis);
+            opt_docsis = opt_opts;
+            continue;
+        }
+        ASSERT_EQ(5678, vendor_id);
+        ASSERT_FALSE(opt_opts5678);
+        opt_opts5678 = opt_opts;
+    }
+
+    // Verify first vendor-opts option.
+    ASSERT_TRUE(opt_opts1234);
+    OptionCollection subs1234 = opt_opts1234->getOptions();
+    ASSERT_EQ(1, subs1234.size());
+    OptionPtr sub1234 = subs1234.begin()->second;
+    ASSERT_TRUE(sub1234);
+    EXPECT_EQ(123, sub1234->getType());
+    OptionStringPtr opt_foo =
+        boost::dynamic_pointer_cast<OptionString>(sub1234);
+    ASSERT_TRUE(opt_foo);
+    EXPECT_EQ("foo", opt_foo->getValue());
+
+    // Verify DOCSIS vendor-opts option.
+    ASSERT_TRUE(opt_docsis);
+    OptionCollection subs_docsis = opt_docsis->getOptions();
+    ASSERT_EQ(1, subs_docsis.size());
+    OptionPtr cfile = subs_docsis.begin()->second;
+    ASSERT_TRUE(cfile);
+    EXPECT_EQ(33, cfile->getType());
+    OptionStringPtr cfile_str = boost::dynamic_pointer_cast<OptionString>(cfile);
+    ASSERT_TRUE(cfile_str);
+    EXPECT_EQ("normal_erouter_v6.cm", cfile_str->getValue());
+
+    // Verify last vendor-opts option.
+    ASSERT_TRUE(opt_opts5678);
+    OptionCollection subs5678 = opt_opts5678->getOptions();
+    ASSERT_EQ(1, subs5678.size());
+    OptionPtr sub5678 = subs5678.begin()->second;
+    ASSERT_TRUE(sub5678);
+    EXPECT_EQ(456, sub5678->getType());
+    OptionStringPtr opt_bar =
+        boost::dynamic_pointer_cast<OptionString>(sub5678);
+    ASSERT_TRUE(opt_bar);
+    EXPECT_EQ("bar", opt_bar->getValue());
+}
+
 }
index eca0f3fe50eb5cf7dc2be500e7fba1e67209823a..db365c63398765fb6e310c460a829cbfd7aca3e1 100644 (file)
@@ -73,7 +73,9 @@ public:
 
     using Pkt6::getNonCopiedOptions;
     using Pkt6::getNonCopiedRelayOption;
+    using Pkt6::getNonCopiedRelayOptions;
     using Pkt6::getNonCopiedAnyRelayOption;
+    using Pkt6::getNonCopiedAllRelayOptions;
 };
 
 typedef boost::shared_ptr<NakedPkt6> NakedPkt6Ptr;
@@ -700,6 +702,7 @@ TEST_F(Pkt6Test, relayUnpack) {
     EXPECT_EQ(2, msg->relay_info_[0].options_.size());
 
     // There should be interface-id option
+    EXPECT_EQ(1, msg->getRelayOptions(D6O_INTERFACE_ID, 0).size());
     ASSERT_TRUE(opt = msg->getRelayOption(D6O_INTERFACE_ID, 0));
     OptionBuffer data = opt->getData();
     EXPECT_EQ(32, opt->len()); // 28 bytes of data + 4 bytes header
@@ -708,6 +711,7 @@ TEST_F(Pkt6Test, relayUnpack) {
     EXPECT_TRUE(0 == memcmp("ISAM144|299|ipv6|nt:vp:1:110", &data[0], 28));
 
     // Get the remote-id option
+    EXPECT_EQ(1, msg->getRelayOptions(D6O_REMOTE_ID, 0).size());
     ASSERT_TRUE(opt = msg->getRelayOption(D6O_REMOTE_ID, 0));
     EXPECT_EQ(22, opt->len()); // 18 bytes of data + 4 bytes header
     boost::shared_ptr<OptionCustom> custom = boost::dynamic_pointer_cast<OptionCustom>(opt);
@@ -725,6 +729,7 @@ TEST_F(Pkt6Test, relayUnpack) {
     // Part 2: Check options inserted by the second relay
 
     // Get the interface-id from the second relay
+    EXPECT_EQ(1, msg->getRelayOptions(D6O_INTERFACE_ID, 1).size());
     ASSERT_TRUE(opt = msg->getRelayOption(D6O_INTERFACE_ID, 1));
     data = opt->getData();
     EXPECT_EQ(25, opt->len()); // 21 bytes + 4 bytes header
@@ -732,6 +737,7 @@ TEST_F(Pkt6Test, relayUnpack) {
     EXPECT_TRUE(0 == memcmp("ISAM144 eth 1/1/05/01", &data[0], 21));
 
     // Get the remote-id option
+    EXPECT_EQ(1, msg->getRelayOptions(D6O_REMOTE_ID, 1).size());
     ASSERT_TRUE(opt = msg->getRelayOption(D6O_REMOTE_ID, 1));
     EXPECT_EQ(8, opt->len());
     custom = boost::dynamic_pointer_cast<OptionCustom>(opt);
@@ -742,6 +748,7 @@ TEST_F(Pkt6Test, relayUnpack) {
 
     // Let's check if there is no leak between options stored in
     // the SOLICIT message and the relay.
+    EXPECT_TRUE(msg->getRelayOptions(D6O_IA_NA, 1).empty());
     EXPECT_FALSE(opt = msg->getRelayOption(D6O_IA_NA, 1));
 
 
@@ -853,6 +860,7 @@ TEST_F(Pkt6Test, relayPack) {
 
     // There should be exactly one option
     EXPECT_EQ(1, clone->relay_info_[0].options_.size());
+    EXPECT_EQ(1, clone->getRelayOptions(200, 0).size());
     OptionPtr opt = clone->getRelayOption(200, 0);
     EXPECT_TRUE(opt);
     EXPECT_EQ(opt->getType() , optRelay1->getType());
@@ -896,6 +904,50 @@ TEST_F(Pkt6Test, getRelayOption) {
     EXPECT_TRUE(opt_iface_id == opt_iface_id_returned);
 }
 
+TEST_F(Pkt6Test, getRelayOptions) {
+    NakedPkt6Ptr msg(boost::dynamic_pointer_cast<NakedPkt6>(capture2()));
+    ASSERT_TRUE(msg);
+
+    ASSERT_NO_THROW(msg->unpack());
+    ASSERT_EQ(2, msg->relay_info_.size());
+
+    OptionCollection opts_iface_id =
+        msg->getNonCopiedRelayOptions(D6O_INTERFACE_ID, 0);
+    ASSERT_EQ(1, opts_iface_id.size());
+
+    OptionPtr opt_iface_id = msg->getNonCopiedRelayOption(D6O_INTERFACE_ID, 0);
+    ASSERT_TRUE(opt_iface_id);
+
+    OptionCollection opts_iface_id_returned =
+        msg->getRelayOptions(D6O_INTERFACE_ID, 0);
+    ASSERT_EQ(1, opts_iface_id_returned.size());
+
+    OptionPtr opt_iface_id_returned = msg->getRelayOption(D6O_INTERFACE_ID, 0);
+    ASSERT_TRUE(opt_iface_id_returned);
+
+    EXPECT_TRUE(opt_iface_id == opt_iface_id_returned);
+    EXPECT_TRUE(opts_iface_id == opts_iface_id_returned);
+    EXPECT_TRUE(opts_iface_id.begin()->second == opt_iface_id);
+    EXPECT_TRUE(opts_iface_id_returned.begin()->second == opt_iface_id_returned);
+
+    msg->setCopyRetrievedOptions(true);
+
+    opts_iface_id_returned = msg->getRelayOptions(D6O_INTERFACE_ID, 0);
+    ASSERT_EQ(1, opts_iface_id_returned.size());
+    opt_iface_id_returned = msg->getRelayOption(D6O_INTERFACE_ID, 0);
+    EXPECT_FALSE(opt_iface_id == opt_iface_id_returned);
+    EXPECT_FALSE(opts_iface_id.begin()->second == opt_iface_id_returned);
+    EXPECT_FALSE(opts_iface_id_returned.begin()->second == opt_iface_id);
+    EXPECT_FALSE(opts_iface_id_returned.begin()->second == opt_iface_id_returned);
+
+    opt_iface_id = msg->getNonCopiedRelayOption(D6O_INTERFACE_ID, 0);
+    EXPECT_TRUE(opt_iface_id == opt_iface_id_returned);
+
+    opts_iface_id_returned = msg->getNonCopiedRelayOptions(D6O_INTERFACE_ID, 0);
+    opts_iface_id = msg->getNonCopiedRelayOptions(D6O_INTERFACE_ID, 0);
+    EXPECT_TRUE(opts_iface_id == opts_iface_id_returned);
+}
+
 // This test verifies that options added by relays to the message can be
 // accessed and retrieved properly
 TEST_F(Pkt6Test, getAnyRelayOption) {
@@ -950,6 +1002,10 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     EXPECT_FALSE(opt);
     opt = msg->getAnyRelayOption(300, Pkt6::RELAY_GET_LAST);
     EXPECT_FALSE(opt);
+    EXPECT_TRUE(msg->getAllRelayOptions(300, Pkt6::RELAY_SEARCH_FROM_CLIENT).empty());
+    EXPECT_TRUE(msg->getAllRelayOptions(300, Pkt6::RELAY_SEARCH_FROM_SERVER).empty());
+    EXPECT_TRUE(msg->getAllRelayOptions(300, Pkt6::RELAY_GET_FIRST).empty());
+    EXPECT_TRUE(msg->getAllRelayOptions(300, Pkt6::RELAY_GET_LAST).empty());
 
     // Option 200 is added in every relay.
 
@@ -959,25 +1015,50 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     ASSERT_TRUE(opt);
     EXPECT_TRUE(opt->equals(relay3_opt1));
     EXPECT_TRUE(opt == relay3_opt1);
-
-    // We want to ge that one inserted by relay1 (first match, starting from
+    OptionCollection opts =
+        msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_TRUE(opts.begin()->second == relay3_opt1);
+
+    // We want to get that one inserted by relay1 (first match, starting from
     // closest to the server.
     opt = msg->getAnyRelayOption(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
     ASSERT_TRUE(opt);
     EXPECT_TRUE(opt->equals(relay1_opt1));
     EXPECT_TRUE(opt == relay1_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_TRUE(opts.begin()->second == relay1_opt1);
 
     // We just want option from the first relay (closest to the client)
     opt = msg->getAnyRelayOption(200, Pkt6::RELAY_GET_FIRST);
     ASSERT_TRUE(opt);
     EXPECT_TRUE(opt->equals(relay3_opt1));
     EXPECT_TRUE(opt == relay3_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_GET_FIRST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_GET_FIRST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opts.begin()->second == relay3_opt1);
 
     // We just want option from the last relay (closest to the server)
     opt = msg->getAnyRelayOption(200, Pkt6::RELAY_GET_LAST);
     ASSERT_TRUE(opt);
     EXPECT_TRUE(opt->equals(relay1_opt1));
     EXPECT_TRUE(opt == relay1_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_GET_LAST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_GET_LAST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opts.begin()->second == relay1_opt1);
 
     // Enable copying options when they are retrieved and redo the tests
     // but expect that options are still equal but different pointers
@@ -994,6 +1075,14 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     relay3_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_SEARCH_FROM_CLIENT);
     ASSERT_TRUE(relay3_opt1);
     EXPECT_TRUE(opt == relay3_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_FALSE(opts.begin()->second == relay3_opt1);
+    relay3_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_TRUE(opts.begin()->second == relay3_opt1);
 
     opt = msg->getAnyRelayOption(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
     ASSERT_TRUE(opt);
@@ -1002,6 +1091,14 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     relay1_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
     ASSERT_TRUE(relay1_opt1);
     EXPECT_TRUE(opt == relay1_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(3, opts.size());
+    EXPECT_FALSE(opts.begin()->second == relay1_opt1);
+    relay1_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_TRUE(opts.begin()->second == relay1_opt1);
 
     opt = msg->getAnyRelayOption(200, Pkt6::RELAY_GET_FIRST);
     ASSERT_TRUE(opt);
@@ -1010,6 +1107,14 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     relay3_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_GET_FIRST);
     ASSERT_TRUE(relay3_opt1);
     EXPECT_TRUE(opt == relay3_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_GET_FIRST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_GET_FIRST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_FALSE(opts.begin()->second == relay3_opt1);
+    relay3_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_GET_FIRST);
+    EXPECT_TRUE(opts.begin()->second == relay3_opt1);
 
     opt = msg->getAnyRelayOption(200, Pkt6::RELAY_GET_LAST);
     ASSERT_TRUE(opt);
@@ -1018,6 +1123,14 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     relay1_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_GET_LAST);
     ASSERT_TRUE(relay1_opt1);
     EXPECT_TRUE(opt == relay1_opt1);
+    opts = msg->getNonCopiedAllRelayOptions(200, Pkt6::RELAY_GET_LAST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opt == opts.begin()->second);
+    opts = msg->getAllRelayOptions(200, Pkt6::RELAY_GET_LAST);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_FALSE(opts.begin()->second == relay1_opt1);
+    relay1_opt1 = msg->getNonCopiedAnyRelayOption(200, Pkt6::RELAY_GET_LAST);
+    EXPECT_TRUE(opts.begin()->second == relay1_opt1);
 
     // Disable copying options and continue with other tests.
     msg->setCopyRetrievedOptions(false);
@@ -1027,29 +1140,65 @@ TEST_F(Pkt6Test, getAnyRelayOption) {
     opt = msg->getAnyRelayOption(100, Pkt6::RELAY_SEARCH_FROM_SERVER);
     ASSERT_TRUE(opt);
     EXPECT_TRUE(opt->equals(relay2_opt1));
+    opts = msg->getNonCopiedAllRelayOptions(100, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opts.begin()->second == relay2_opt1);
+    opts = msg->getAllRelayOptions(100, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(relay2_opt1->equals(opts.begin()->second));
 
     opt = msg->getAnyRelayOption(100, Pkt6::RELAY_SEARCH_FROM_CLIENT);
     ASSERT_TRUE(opt);
     EXPECT_TRUE(opt->equals(relay2_opt1));
+    opts = msg->getNonCopiedAllRelayOptions(100, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(opts.begin()->second == relay2_opt1);
+    opts = msg->getAllRelayOptions(100, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_EQ(1, opts.size());
+    EXPECT_TRUE(relay2_opt1->equals(opts.begin()->second));
 
     opt = msg->getAnyRelayOption(100, Pkt6::RELAY_GET_FIRST);
     EXPECT_FALSE(opt);
+    opts = msg->getNonCopiedAllRelayOptions(100, Pkt6::RELAY_GET_FIRST);
+    EXPECT_TRUE(opts.empty());
+    opts = msg->getAllRelayOptions(100, Pkt6::RELAY_GET_FIRST);
+    EXPECT_TRUE(opts.empty());
 
     opt = msg->getAnyRelayOption(100, Pkt6::RELAY_GET_LAST);
     EXPECT_FALSE(opt);
+    opts = msg->getNonCopiedAllRelayOptions(100, Pkt6::RELAY_GET_LAST);
+    EXPECT_TRUE(opts.empty());
+    opts = msg->getAllRelayOptions(100, Pkt6::RELAY_GET_LAST);
+    EXPECT_TRUE(opts.empty());
 
     // Finally, try to get an option that does not exist
     opt = msg->getAnyRelayOption(500, Pkt6::RELAY_GET_FIRST);
     EXPECT_FALSE(opt);
+    opts = msg->getNonCopiedAllRelayOptions(500, Pkt6::RELAY_GET_FIRST);
+    EXPECT_TRUE(opts.empty());
+    opts = msg->getAllRelayOptions(500, Pkt6::RELAY_GET_FIRST);
+    EXPECT_TRUE(opts.empty());
 
     opt = msg->getAnyRelayOption(500, Pkt6::RELAY_GET_LAST);
     EXPECT_FALSE(opt);
+    opts = msg->getNonCopiedAllRelayOptions(500, Pkt6::RELAY_GET_LAST);
+    EXPECT_TRUE(opts.empty());
+    opts = msg->getAllRelayOptions(500, Pkt6::RELAY_GET_LAST);
+    EXPECT_TRUE(opts.empty());
 
     opt = msg->getAnyRelayOption(500, Pkt6::RELAY_SEARCH_FROM_SERVER);
     EXPECT_FALSE(opt);
+    opts = msg->getNonCopiedAllRelayOptions(500, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_TRUE(opts.empty());
+    opts = msg->getAllRelayOptions(500, Pkt6::RELAY_SEARCH_FROM_SERVER);
+    EXPECT_TRUE(opts.empty());
 
     opt = msg->getAnyRelayOption(500, Pkt6::RELAY_SEARCH_FROM_CLIENT);
     EXPECT_FALSE(opt);
+    opts = msg->getNonCopiedAllRelayOptions(500, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_TRUE(opts.empty());
+    opts = msg->getAllRelayOptions(500, Pkt6::RELAY_SEARCH_FROM_CLIENT);
+    EXPECT_TRUE(opts.empty());
 }
 
 // Tests whether Pkt6::toText() properly prints out all parameters, including