]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#99,!176] Added unit test for deleting an option from option space.
authorMarcin Siodelski <marcin@isc.org>
Wed, 19 Dec 2018 20:00:33 +0000 (21:00 +0100)
committerMarcin Siodelski <marcin@isc.org>
Thu, 20 Dec 2018 19:47:42 +0000 (14:47 -0500)
src/lib/dhcpsrv/cfg_option.cc
src/lib/dhcpsrv/cfg_option.h
src/lib/dhcpsrv/tests/cfg_option_unittest.cc

index 1ef4d9061ac806ace2991d1d45462b7aa78e88ae..0125709a68a65a54a43e34858b85564b96ad4aee 100644 (file)
@@ -189,6 +189,43 @@ CfgOption::getAll(const uint32_t vendor_id) const {
     return (vendor_options_.getItems(vendor_id));
 }
 
+size_t
+CfgOption::del(const std::string& option_space, const uint16_t option_code) {
+    // Check for presence of options.
+    OptionContainerPtr options = getAll(option_space);
+    if (!options || options->empty()) {
+        // There are no options, so there is nothing to do.
+        return (0);
+    }
+
+    // If this is not top level option we may also need to delete the
+    // option instance from options encapsulating the particular option
+    // space.
+    if ((option_space != DHCP4_OPTION_SPACE) &&
+        (option_space != DHCP6_OPTION_SPACE)) {
+        // For each option space name iterate over the existing options.
+        auto option_space_names = getOptionSpaceNames();
+        for (auto option_space_from_list : option_space_names) {
+            // Get all options within the particular option space.
+            auto options_in_space = getAll(option_space_from_list);
+            for (auto option_it = options_in_space->begin();
+                 option_it != options_in_space->end();
+                 ++option_it) {
+
+                // Check if the option encapsulates our option space and
+                // it does, try to delete our option.
+                if (option_it->option_ &&
+                    (option_it->option_->getEncapsulatedSpace() == option_space)) {
+                    option_it->option_->delOption(option_code);
+                }
+            }
+        }
+    }
+
+    auto& idx = options->get<1>();
+    return (idx.erase(option_code));
+}
+
 ElementPtr
 CfgOption::toElement() const {
     // option-data value is a list of maps
index 533439a5a477a105dfa22c128274a36e5c9b906e..a618076c6d40a4c85cc871cdb459c0ad3fcda62d 100644 (file)
@@ -414,30 +414,17 @@ public:
         return (*od_itr);
     }
 
-    /// @brief Deletes option for the specified key and option code.
+    /// @brief Deletes option for the specified option space and option code.
     ///
-    /// The key should be a string, in which case it specifies an option space
-    /// name, or an uint32_t value, in which case it specifies a vendor
-    /// identifier.
+    /// If the option is encapsulated within some non top level option space,
+    /// it is also deleted from all option instances encapsulating this
+    /// option space.
     ///
     /// @param key Option space name or vendor identifier.
     /// @param option_code Code of the option to be returned.
-    /// @tparam Selector one of: @c std::string or @c uint32_t
     ///
     /// @return Number of deleted options.
-    template<typename Selector>
-    size_t del(const Selector& key, const uint16_t option_code) {
-        // Check for presence of options.
-        OptionContainerPtr options = getAll(key);
-        if (!options || options->empty()) {
-            // There are no options, so there is nothing to do.
-            return (0);
-        }
-
-        // Some options present, locate the one we are interested in.
-        auto& idx = options->get<1>();
-        return (idx.erase(option_code));
-    }
+    size_t del(const std::string& key, const uint16_t option_code);
 
     /// @brief Returns a list of configured option space names.
     ///
index 7d41f2779f584b24faa6f61d15e5aeead8e322b3..0a619d2931f461b63cabdd8659b1ae6e9947eeb7 100644 (file)
@@ -399,6 +399,48 @@ TEST_F(CfgOptionTest, encapsulate) {
     }
 }
 
+// This test verifies that an option can be deleted from the configuration.
+TEST_F(CfgOptionTest, del) {
+    CfgOption cfg;
+
+    generateEncapsulatedOptions(cfg);
+
+    // Append options from "foo" and "bar" space as sub-options and options
+    // from "foo-subs" and "bar-subs" as sub-options of "foo" and "bar"
+    // options.
+    ASSERT_NO_THROW(cfg.encapsulate());
+
+    // The option with the code 5 should exist in the option space "foo".
+    ASSERT_TRUE(cfg.get("foo", 5).option_);
+
+    // Because we called "encapsulate", this option should have been
+    // propagated to the options encapsulating option space "foo".
+    for (uint16_t code = 1000; code < 1020; ++code) {
+        OptionDescriptor top_level_option(false);
+        ASSERT_NO_THROW(top_level_option = cfg.get(DHCP6_OPTION_SPACE, code));
+        // Make sure that the option with code 5 is there.
+        ASSERT_TRUE(top_level_option.option_);
+        ASSERT_TRUE(top_level_option.option_->getOption(5));
+    }
+
+    // Delete option with the code 5 and belonging to option space "foo".
+    uint64_t deleted_num;
+    ASSERT_NO_THROW(deleted_num = cfg.del("foo", 5));
+    EXPECT_EQ(1, deleted_num);
+
+    // The option should now be gone from options config.
+    EXPECT_FALSE(cfg.get("foo", 5).option_);
+
+    // Iterate over the options encapsulating "foo" option space. Make sure
+    // that the option with code 5 is no longer encapsulated by these options.
+    for (uint16_t code = 1000; code < 1020; ++code) {
+        OptionDescriptor top_level_option(false);
+        ASSERT_NO_THROW(top_level_option = cfg.get(DHCP6_OPTION_SPACE, code));
+        ASSERT_TRUE(top_level_option.option_);
+        EXPECT_FALSE(top_level_option.option_->getOption(5));
+    }
+}
+
 // This test verifies that single option can be retrieved from the configuration
 // using option code and option space.
 TEST_F(CfgOptionTest, get) {