]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] Checkpoint: found a shared-network bug
authorFrancis Dupont <fdupont@isc.org>
Wed, 29 Nov 2017 01:14:21 +0000 (02:14 +0100)
committerFrancis Dupont <fdupont@isc.org>
Wed, 29 Nov 2017 01:14:21 +0000 (02:14 +0100)
doc/examples/kea4/advanced.json
doc/examples/kea6/advanced.json
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/parser_unittest.cc
src/bin/dhcp6/tests/parser_unittest.cc
src/lib/dhcpsrv/pool.h
src/lib/testutils/Makefile.am
src/lib/testutils/user_context_utils.cc [new file with mode: 0644]
src/lib/testutils/user_context_utils.h [new file with mode: 0644]

index 03ff4dc98c74446028176202e579ab78d2efa391..71385337309cd61d94d3d7c5a345c33aea4410a8 100644 (file)
             "subnet": "192.0.2.0/24",
             "user-context": {
                 "comment": "Our first subnet!"
-            }
+            },
             // Equivalent using smart parser
-            // "comment": "Our first subnet!"
+            "comment": "Our first subnet!"
         },
         {
             // This particular subnet has match-client-id value changed.
index 8e0fb0faaeb41d475c28f82de6cc9eea0155a3c8..fc9ab80278afca8f81b84c646da1044e88b7c47c 100644 (file)
         // Here's the user-context for the whole subnet.
         "user-context": { "comment": "Floor one, west wing" },
         // Equivalent using smart parser
-        // "comment": "Floor one, west wing",
+        "comment": "Floor one, west wing",
 
         // This defines PD (prefix delegation) pools. In this case
         // we have only one pool. That consists of /64 prefixes
index 8c00d545bed84a3ab3b5ee03a8ae8e8b8a79bc21..1a8cb35ee44c52ab7030da3b61f3a1787b8ea81e 100644 (file)
@@ -5607,4 +5607,74 @@ TEST_F(Dhcp4ParserTest, sharedNetworksDeriveClientClass) {
     EXPECT_TRUE(classes.empty());
 }
 
+// This test checks comments. Please keep it last.
+TEST_F(Dhcp4ParserTest, comments) {
+
+    string config = "{\n"
+        "\"shared-networks\": [ {\n"
+        "    \"name\": \"foo\"\n,"
+        "    \"comment\": \"A shared-network\"\n,"
+        "    \"subnet4\": [\n"
+        "    { \n"
+        "        \"subnet\": \"192.0.1.0/24\",\n"
+        "        \"comment\": \"A subnet\"\n,"
+        "        \"pools\": [\n"
+        "        {\n"
+        "             \"pool\": \"192.0.1.1-192.0.1.10\",\n"
+        "             \"comment\": \"A pool\"\n"
+        "        }\n"
+        "        ]\n"
+        "    }\n"
+        "    ]\n"
+        " } ]\n"
+        "} \n";
+
+    extractConfig(config);
+    configure(config, CONTROL_RESULT_SUCCESS, "");
+
+    // Now verify that the shared network was indeed configured.
+    CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
+        ->getCfgSharedNetworks4();
+    ASSERT_TRUE(cfg_net);
+    const SharedNetwork4Collection* nets = cfg_net->getAll();
+    ASSERT_TRUE(nets);
+    ASSERT_EQ(1, nets->size());
+    SharedNetwork4Ptr net = nets->at(0);
+    ASSERT_TRUE(net);
+
+    // Check shared network user context
+    ConstElementPtr ctx_net = net->getContext();
+    ASSERT_TRUE(ctx_net);
+    ASSERT_EQ(1, ctx_net->size());
+    ASSERT_TRUE(ctx_net->get("comment"));
+    EXPECT_EQ("\"A shared-network\"", ctx_net->get("comment")->str());
+
+    // The shared network has a subnet.
+    const Subnet4Collection * subs = net->getAllSubnets();
+    ASSERT_TRUE(subs);
+    ASSERT_EQ(1, subs->size());
+    Subnet4Ptr sub = subs->at(0);
+    ASSERT_TRUE(sub);
+
+    // Check subnet user context
+    ConstElementPtr ctx_sub = sub->getContext();
+    ASSERT_TRUE(ctx_sub);
+    ASSERT_EQ(1, ctx_sub->size());
+    ASSERT_TRUE(ctx_sub->get("comment"));
+    EXPECT_EQ("\"A subnet\"", ctx_sub->get("comment")->str());
+
+    // The subnet has a pool
+    const PoolCollection& pools = sub->getPools(Lease::TYPE_V4);
+    ASSERT_EQ(1, pools.size());
+    PoolPtr pool = pools.at(0);
+    ASSERT_TRUE(pool);
+
+    // Check pool user context                                               
+    ConstElementPtr ctx_pool = pool->getContext();
+    ASSERT_TRUE(ctx_pool);
+    ASSERT_EQ(1, ctx_pool->size());
+    ASSERT_TRUE(ctx_pool->get("comment"));
+    EXPECT_EQ("\"A pool\"", ctx_pool->get("comment")->str());
+}
+
 }
index adadbe9676e9d8d97448fe45bf61f9902def2ec0..d35faef2f7a9a07a22e7cecbdfec4e700bda5e1b 100644 (file)
@@ -8,6 +8,7 @@
 #include <cc/data.h>
 #include <dhcp4/parser_context.h>
 #include <testutils/io_utils.h>
+#include <testutils/user_context_utils.h>
 
 using namespace isc::data;
 using namespace isc::test;
@@ -209,6 +210,7 @@ TEST(ParserTest, multilineComments) {
 ///
 /// @param fname name of the file to be loaded
 void testFile(const std::string& fname) {
+    ElementPtr json;
     ElementPtr reference_json;
     ConstElementPtr test_json;
 
@@ -216,7 +218,8 @@ void testFile(const std::string& fname) {
 
     cout << "Parsing file " << fname << " (" << decommented << ")" << endl;
 
-    EXPECT_NO_THROW(reference_json = Element::fromJSONFile(decommented, true));
+    EXPECT_NO_THROW(json = Element::fromJSONFile(decommented, true));
+    reference_json = moveComments(json);
 
     // remove the temporary file
     EXPECT_NO_THROW(::remove(decommented.c_str()));
index fdc9c85f3865dc0ae16531a17407cde9dfed5bd0..bbc969e9e03e8ebf969162f85112dc9941f985ce 100644 (file)
@@ -8,6 +8,7 @@
 #include <cc/data.h>
 #include <dhcp6/parser_context.h>
 #include <testutils/io_utils.h>
+#include <testutils/user_context_utils.h>
 
 using namespace isc::data;
 using namespace std;
@@ -212,6 +213,7 @@ TEST(ParserTest, multilineComments) {
 ///
 /// @param fname name of the file to be loaded
 void testFile(const std::string& fname) {
+    ElementPtr json;
     ElementPtr reference_json;
     ConstElementPtr test_json;
 
@@ -219,7 +221,8 @@ void testFile(const std::string& fname) {
 
     cout << "Parsing file " << fname << "(" << decommented << ")" << endl;
 
-    EXPECT_NO_THROW(reference_json = Element::fromJSONFile(decommented, true));
+    EXPECT_NO_THROW(json = Element::fromJSONFile(decommented, true));
+    reference_json = moveComments(json);
 
     // remove the temporary file
     EXPECT_NO_THROW(::remove(decommented.c_str()));
index 2660b90f6b0320b936c7f4f5936c2c08f064c140..55d4235fe335f88649c70e3d6c159d66ca76dd8b 100644 (file)
@@ -135,11 +135,6 @@ protected:
     /// @brief The last address in a pool
     isc::asiolink::IOAddress last_;
 
-    /// @brief Comments field
-    ///
-    /// @todo: This field is currently not used.
-    std::string comments_;
-
     /// @brief defines a lease type that will be served from this pool
     Lease::Type type_;
 
index cfd0c8d0582c3e87c63180631c362c9935beaf22..fc7665ec2265f71058acf68f4c151460f7c6a382 100644 (file)
@@ -10,7 +10,8 @@ noinst_LTLIBRARIES = libkea-testutils.la
 libkea_testutils_la_SOURCES  = io_utils.cc io_utils.h
 libkea_testutils_la_SOURCES += log_utils.cc log_utils.h
 libkea_testutils_la_SOURCES += test_to_element.cc test_to_element.h
-libkea_testutils_la_SOURCES += unix_control_client.h unix_control_client.cc
+libkea_testutils_la_SOURCES += unix_control_client.cc unix_control_client.h
+libkea_testutils_la_SOURCES += user_context_utils.cc user_context_utils.h
 libkea_testutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 libkea_testutils_la_LIBADD  = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
 libkea_testutils_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
diff --git a/src/lib/testutils/user_context_utils.cc b/src/lib/testutils/user_context_utils.cc
new file mode 100644 (file)
index 0000000..511ae73
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <testutils/user_context_utils.h>
+
+using namespace isc::data;
+
+namespace {
+
+/// @brief Exception to handle a unmodified value
+/// @tparam EP ElementPtr or ConstElementPtr (compiler can't infer which one)
+template<typename EP>
+class UnModified {
+public:
+    /// @brief Constructor
+    /// @param value the unmodified value
+    UnModified(EP value) : value_(value) { }
+
+    /// @brief Get the value
+    /// @return the value
+    EP get() const { return (value_); }
+
+protected:
+    /// @brief the unmodified value
+    EP value_;
+};
+
+/// @brief Recursive helper
+///
+/// Instead of returning a unmodified copy a @ref UnModified exception
+/// is raised with the unmodified value
+///
+/// @tparam EP ElementPtr or ConstElementPtr (compiler will infer which one)
+/// @param element the element to traverse
+/// @return a modified copy where comment entries were moved to user-context
+/// @throw UnModified with the unmodified value
+template<typename EP>
+EP moveComments1(EP element) {
+    bool modified = false;
+
+    // On lists recurse on items
+    if (element->getType() == Element::list) {
+        ElementPtr result = ElementPtr(new ListElement());
+        typedef std::vector<ElementPtr> ListType;
+        const ListType& list = element->listValue();
+        for (ListType::const_iterator it = list.cbegin();
+             it != list.cend(); ++it) {
+            try {
+                result->add(moveComments1(*it));
+                modified = true;
+            }
+            catch (const UnModified<ElementPtr>& ex) {
+                result->add(ex.get());
+            }
+        }
+        if (!modified) {
+            throw UnModified<EP>(element);
+        }
+        return (result);
+    } else if (element->getType() != Element::map) {
+        throw UnModified<EP>(element);
+    }
+
+    // Process maps: recurse on items
+    ElementPtr result = ElementPtr(new MapElement());
+    bool has_comment = false;
+    typedef std::map<std::string, ConstElementPtr> map_type;
+    const map_type& map = element->mapValue();
+    for (map_type::const_iterator it = map.cbegin(); it != map.cend(); ++it) {
+        if (it->first == "comment") {
+            // Note there is a comment entry to move
+            has_comment = true;
+        } else if (it->first == "user-context") {
+            // Do not traverse user-context entries
+            result->set("user-context", it->second);
+        } else {
+            // Not comment or user-context
+            try {
+                result->set(it->first, moveComments1(it->second));
+                modified = true;
+            }
+            catch (const UnModified<ConstElementPtr>& ex) {
+                result->set(it->first, ex.get());
+            }
+        }
+    }
+    // Check if the value should be not modified
+    if (!has_comment && !modified) {
+        throw UnModified<EP>(element);
+    }
+
+    if (has_comment) {
+        // Move the comment entry
+        ConstElementPtr comment = element->get("comment");
+        ElementPtr moved = Element::createMap();
+        moved->set("comment", comment);
+        result->combine_set("user-context", moved);
+    }
+
+    return (result);
+}
+
+} // anonymous namespace
+
+namespace isc {
+namespace test {
+
+ElementPtr moveComments(ElementPtr element) {
+    ElementPtr result;
+    try {
+        result = moveComments1(element);
+    }
+    catch (const UnModified<ElementPtr>& ex) {
+        result = ex.get();
+    }
+    return result;
+}
+
+}; // end of isc::test namespace
+}; // end of isc namespace
diff --git a/src/lib/testutils/user_context_utils.h b/src/lib/testutils/user_context_utils.h
new file mode 100644 (file)
index 0000000..417fdc6
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef USER_CONTEXT_UTILS_H
+#define USER_CONTEXT_UTILS_H
+
+#include <cc/data.h>
+
+namespace isc {
+namespace test {
+
+/// @brief Move comment entries to user-context
+///
+/// @param element
+/// @return a processed copy of element or unmodified element
+isc::data::ElementPtr moveComments(isc::data::ElementPtr element);
+
+}; // end of isc::test namespace
+}; // end of isc namespace
+
+#endif // USER_CONTEXT_UTILS_H