]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[204-move-models-] Added unit tests
authorFrancis Dupont <fdupont@isc.org>
Thu, 22 Nov 2018 14:01:40 +0000 (15:01 +0100)
committerFrancis Dupont <fdupont@isc.org>
Mon, 10 Dec 2018 10:08:44 +0000 (11:08 +0100)
src/bin/netconf/configs/hackathon102-v4-1.xml [deleted file]
src/bin/netconf/configs/hackathon102-v4-2.xml [deleted file]
src/bin/netconf/configs/simple4.xml [deleted file]
src/bin/netconf/netconf.h
src/bin/netconf/tests/netconf_unittests.cc

diff --git a/src/bin/netconf/configs/hackathon102-v4-1.xml b/src/bin/netconf/configs/hackathon102-v4-1.xml
deleted file mode 100644 (file)
index e267b65..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-  <server xmlns="urn:ietf:params:xml:ns:yang:ietf-dhcpv4-server">
-    <server-config>
-      <serv-attributes>
-       <name />
-       <description />
-       <ipv4-address>192.0.2.1</ipv4-address>
-       <!-- <interfaces-config /> -->
-       <vendor-info>
-         <ent-num>1234</ent-num>
-         <data>why is vendor-info mandatory?</data>
-       </vendor-info>
-
-      </serv-attributes>
-      <option-sets>
-       <option-set>
-           <option-set-id>1</option-set-id>
-
-           <router-option>
-                   <router>
-                           <router-id>1</router-id>
-                           <router-addr>198.51.100.254</router-addr>
-                   </router>
-           </router-option>
-
-           <domain-server-option>
-                   <domain-server>
-                           <domain-server-id>1</domain-server-id>
-                           <domain-server-addr>198.51.100.1</domain-server-addr>
-                   </domain-server>
-                   <domain-server>
-                           <domain-server-id>2</domain-server-id>
-                           <domain-server-addr>198.51.100.2</domain-server-addr>
-                   </domain-server>
-           </domain-server-option>
-
-           <broadcast-option>
-                   <broadcast-addr>198.51.100.255</broadcast-addr>
-           </broadcast-option>
-
-           <domain-search-option>
-                   <domain-search>
-                           <domain-search-id>1</domain-search-id>
-                           <domain-search-entry>example.net</domain-search-entry>
-                   </domain-search>
-                   <domain-search>
-                           <domain-search-id>2</domain-search-id>
-                           <domain-search-entry>sub.example.net</domain-search-entry>
-                   </domain-search>
-           </domain-search-option>
-
-       </option-set>
-
-      </option-sets>
-      <network-ranges>
-       <option-set-id>1</option-set-id>
-       <network-range>
-         <network-range-id>1</network-range-id>
-         <network-description />
-         <network-prefix>198.51.100.0/24</network-prefix>
-         <option-set-id>1</option-set-id>
-         <address-pools>
-                 <address-pool>
-                         <pool-id>1</pool-id>
-                         <pool-prefix>198.51.100.0/24</pool-prefix>
-                         <start-address>198.51.100.100</start-address>
-                         <end-address>198.51.100.200</end-address>
-                         <renew-time>3600</renew-time>
-                         <rebind-time>3600</rebind-time>
-                         <max-address-count>50</max-address-count>
-                         <option-set-id>1</option-set-id>
-                 </address-pool>
-         </address-pools>
-         <host-reservations>
-                 <host-reservation>
-                         <cli-id>1</cli-id>
-                         <hardware-address>00:53:00:00:00:00</hardware-address>
-                         <reserv-addr>198.51.100.210</reserv-addr>
-                         <hostname>host1.example.net</hostname>
-                 </host-reservation>
-         </host-reservations>
-       </network-range>
-      </network-ranges>
-    </server-config>
-  </server>
diff --git a/src/bin/netconf/configs/hackathon102-v4-2.xml b/src/bin/netconf/configs/hackathon102-v4-2.xml
deleted file mode 100644 (file)
index d4ba607..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-  <server xmlns="urn:ietf:params:xml:ns:yang:ietf-dhcpv4-server">
-    <server-config>
-      <network-ranges>
-       <network-range>
-         <network-range-id>1</network-range-id>
-         <network-prefix>198.51.100.0/24</network-prefix>
-         <address-pools>
-                 <address-pool>
-                         <pool-id>1</pool-id>
-                         <pool-prefix>198.51.100.0/24</pool-prefix>
-                         <start-address>198.51.100.100</start-address>
-                         <end-address>198.51.100.200</end-address>
-                 </address-pool>
-         </address-pools>
-       </network-range>
-      </network-ranges>
-    </server-config>
-  </server>
diff --git a/src/bin/netconf/configs/simple4.xml b/src/bin/netconf/configs/simple4.xml
deleted file mode 100644 (file)
index 1a7c325..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<config xmlns="urn:ietf:params:xml:ns:yang:kea-dhcp4-server">
-  <subnet4>
-    <subnet4>
-      <id>1</id>
-      <pools>
-        <pool>
-          <start-address>192.0.2.100</start-address>
-          <end-address>192.0.2.200</end-address>
-        </pool>
-      </pools>
-      <subnet>192.0.2.0/24</subnet>
-    </subnet4>
-  </subnet4>
-  <interfaces-config>
-    <interfaces>eth1</interfaces>
-  </interfaces-config>
-  <control-socket>
-    <socket-name>/tmp/kea4-ctrl-socket</socket-name>
-    <socket-type>unix</socket-type>
-  </control-socket>
-</config>
index bc5d964607090eb027c6f0547ad33aa6e30fcca7..125c5a7b1ac99548868515db8199769bbb11589d 100644 (file)
@@ -120,6 +120,15 @@ public:
     bool cancel_;
 
 protected:
+    /// @brief Get and display Kea server configuration.
+    ///
+    /// Retrieves current configuration via control socket (unix or http)
+    /// from a running Kea server. If boot-update is set to false, this
+    /// operation is a no-op.
+    ///
+    /// @param service_pair The service name and configuration pair.
+    void keaConfig(const CfgServersMapPair& service_pair);
+
     /// @brief Check essential module availability.
     ///
     /// Emit a fatal error if an essential one (i.e. required in
@@ -136,15 +145,6 @@ protected:
     /// the expected revision.
     void checkModules() const;
 
-    /// @brief Get and display Kea server configuration.
-    ///
-    /// Retrieves current configuration via control socket (unix or http)
-    /// from a running Kea server. If boot-update is set to false, this
-    /// operation is a no-op.
-    ///
-    /// @param service_pair The service name and configuration pair.
-    void keaConfig(const CfgServersMapPair& service_pair);
-
     /// @brief Retrieve Kea server configuration from the YANG startup
     ///        datastore and applies it to servers.
     ///
index 3ecf29eebfb612cad9e71677f7be04c78b9fa339..25f86641f35e46f2c9503a41de8ec071c90057d0 100644 (file)
@@ -16,6 +16,7 @@
 #include <cc/command_interpreter.h>
 #include <util/threads/thread.h>
 #include <yang/yang_models.h>
+#include <yang/yang_revisions.h>
 #include <yang/translator_config.h>
 #include <yang/testutils/translator_test.h>
 #include <testutils/log_utils.h>
@@ -60,11 +61,14 @@ public:
     /// Export protected methods and fields.
     using NetconfAgent::keaConfig;
     using NetconfAgent::initSysrepo;
+    using NetconfAgent::checkModule;
+    using NetconfAgent::checkModules;
     using NetconfAgent::yangConfig;
     using NetconfAgent::subscribeConfig;
     using NetconfAgent::conn_;
     using NetconfAgent::startup_sess_;
     using NetconfAgent::running_sess_;
+    using NetconfAgent::modules_;
     using NetconfAgent::subscriptions_;
 };
 
@@ -82,50 +86,6 @@ void clearYang(NakedNetconfAgentPtr agent) {
     }
 }
 
-/// @brief Prune JSON configuration.
-///
-/// Typically remove defaults and other extra entries.
-///
-/// @param expected The expected configuration (the model).
-/// @param other The other configuration (the to be pruned).
-/// @return A copy of the other configuration with extra entries in maps
-/// removed so it can be directly compared to expected.
-ConstElementPtr prune(ConstElementPtr expected, ConstElementPtr other) {
-    if (!expected || !other) {
-        isc_throw(BadValue, "prune on null");
-    }
-    if ((expected->getType() == Element::list) &&
-        (other->getType() == Element::list)) {
-        // Handle ordered list.
-        ElementPtr result = Element::createList();
-        for (size_t i = 0; i < other->size(); ++i) {
-            if (i > expected->size()) {
-                // Add extra elements.
-                result->add(copy(other->get(i)));
-            } else {
-                // Add pruned element.
-                result->add(copy(prune(expected->get(i), other->get(i))));
-            }
-        }
-        return (result);
-    } else if ((expected->getType() == Element::map) &&
-               (other->getType() == Element::map)) {
-        // Handle map.
-        ElementPtr result = Element::createMap();
-        for (auto it : expected->mapValue()) {
-            ConstElementPtr item = other->get(it.first);
-            if (item) {
-                // Set pruned item.
-                result->set(it.first, copy(prune(it.second, item)));
-            }
-        }
-        return (result);
-    } else {
-        // Not list or map: just return it.
-        return (other);
-    }
-}
-
 /// @brief Test fixture class for netconf agent.
 class NetconfAgentTest : public ThreadedTest {
 public:
@@ -362,6 +322,94 @@ TEST_F(NetconfAgentTest, initSysrepo) {
     EXPECT_TRUE(agent_->startup_sess_);
     EXPECT_TRUE(agent_->running_sess_);
     EXPECT_EQ(1, agent_->subscriptions_.size());
+    EXPECT_LE(16, agent_->modules_.size());
+    // No way to check the module_install callback (BTW is ther
+    // an API to install modules? If none only system tests can
+    // do something)...
+}
+
+/// Verifies the checkModule method emits expected errors.
+TEST_F(NetconfAgentLogTest, checkModule) {
+    // keatest-module should not be in YANG_REVISIONS.
+    EXPECT_EQ(0, YANG_REVISIONS.count("keatest-module"));
+    // But kea-dhcp[46]-server must be in.
+    ASSERT_EQ(1, YANG_REVISIONS.count("kea-dhcp4-server"));
+    ASSERT_EQ(1, YANG_REVISIONS.count("kea-dhcp6-server"));
+
+    // kea-dhcp[46]-server should be available.
+    EXPECT_NO_THROW(agent_->initSysrepo());
+    EXPECT_EQ(1, agent_->modules_.count("kea-dhcp4-server"));
+    EXPECT_EQ(1, agent_->modules_.count("kea-dhcp6-server"));
+    EXPECT_TRUE(agent_->checkModule("kea-dhcp4-server"));
+    EXPECT_TRUE(agent_->checkModule("kea-dhcp6-server"));
+
+    // Unknown module should emit a missing error.
+    EXPECT_EQ(0, agent_->modules_.count("does-not-exist"));
+    EXPECT_FALSE(agent_->checkModule("does-not-exist"));
+    addString("METCONF_MODULE_MISSING_ERR Missing essential module "
+              "does-not-exist in sysrepo");
+
+    // Patch the found revision to get a revision error.
+    const string& module = "kea-dhcp4-server";
+    auto it4 = agent_->modules_.find(module);
+    if (it4 != agent_->modules_.end()) {
+        agent_->modules_.erase(it4);
+    }
+    // The module was written far after 20180714...
+    const string& bad_revision = "2018-07-14";
+    agent_->modules_.insert(make_pair(module, bad_revision));
+    EXPECT_FALSE(agent_->checkModule(module));
+    ostringstream msg;
+    msg << "METCONF_MODULE_REVISION_ERR Essential module " << module
+        << " does have the right revision: expected "
+        << YANG_REVISIONS.at(module) << ", got " << bad_revision;
+    addString(msg.str());
+
+    // Enable this for debugging.
+    // logCheckVerbose(true);
+    EXPECT_TRUE(checkFile());
+}
+
+/// Verifies the checkModules method emits expected warnings.
+TEST_F(NetconfAgentLogTest, checkModules) {
+    // kea-dhcp[46]-server must be in YANG_REVISIONS.
+    ASSERT_EQ(1, YANG_REVISIONS.count("kea-dhcp4-server"));
+    ASSERT_EQ(1, YANG_REVISIONS.count("kea-dhcp6-server"));
+
+    // kea-dhcp[46]-server should be available.
+    EXPECT_NO_THROW(agent_->initSysrepo());
+    EXPECT_EQ(1, agent_->modules_.count("kea-dhcp4-server"));
+    EXPECT_EQ(1, agent_->modules_.count("kea-dhcp6-server"));
+
+    // Run checkModules but it will be indirectly check as
+    // emitting nothing.
+    ASSERT_NO_THROW(agent_->checkModules());
+
+    // Remove kea-dhcp6-server.
+    const string& module = "kea-dhcp6-server";
+    auto it6 = agent_->modules_.find(module);
+    if (it6 != agent_->modules_.end()) {
+        agent_->modules_.erase(it6);
+    }
+    ASSERT_NO_THROW(agent_->checkModules());
+    ostringstream mmsg;
+    mmsg << "METCONF_MODULE_MISSING_WARN Missing module " << module
+         << " in sysrepo";
+    addString(mmsg.str());
+
+    // Add it back with a bad revision.
+    const string& bad_revision = "2018-07-14";
+    agent_->modules_.insert(make_pair(module, bad_revision));
+    ASSERT_NO_THROW(agent_->checkModules());
+    ostringstream rmsg;
+    rmsg << "METCONF_MODULE_REVISION_WARN Module " << module
+         << " does have the right revision: expected "
+         << YANG_REVISIONS.at(module) << ", got " << bad_revision;
+    addString(rmsg.str());
+
+    // Enable this for debugging.
+    // logCheckVerbose(true);
+    EXPECT_TRUE(checkFile());
 }
 
 /// @brief Default change callback (print changes and return OK).
@@ -597,10 +645,9 @@ TEST_F(NetconfAgentTest, keaConfig) {
         "}";
     ConstElementPtr expected;
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    ConstElementPtr pruned = prune(expected, request);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*request));
     // Alternative showing more for debugging...
-    // EXPECT_EQ(prettyPrint(expected), prettyPrint(pruned));
+    // EXPECT_EQ(prettyPrint(expected), prettyPrint(request));
 
     // Check response.
     ASSERT_EQ(1, responses_.size());
@@ -614,8 +661,7 @@ TEST_F(NetconfAgentTest, keaConfig) {
         "    }\n"
         "}";
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    pruned = prune(expected, response);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*response));
 }
 
 /// Verifies the yangConfig method works as expected: apply YANG config
@@ -714,8 +760,7 @@ TEST_F(NetconfAgentTest, yangConfig) {
         "}";
     ConstElementPtr expected;
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    ConstElementPtr pruned = prune(expected, request);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*request));
 
     // Check response.
     ASSERT_EQ(1, responses_.size());
@@ -726,8 +771,7 @@ TEST_F(NetconfAgentTest, yangConfig) {
         "\"result\": 0\n"
         "}";
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    pruned = prune(expected, response);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*response));
 }
 
 /// Verifies the subscribeConfig method works as expected.
@@ -897,8 +941,7 @@ TEST_F(NetconfAgentTest, update) {
         "}";
     ConstElementPtr expected;
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    ConstElementPtr pruned = prune(expected, request);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*request));
 
     // Check response.
     ASSERT_EQ(1, responses_.size());
@@ -909,8 +952,7 @@ TEST_F(NetconfAgentTest, update) {
         "\"result\": 0\n"
         "}";
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    pruned = prune(expected, response);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*response));
 }
 
 /// Verifies the validate method works as expected: test new YANG configuration
@@ -1034,8 +1076,7 @@ TEST_F(NetconfAgentTest, validate) {
         "}";
     ConstElementPtr expected;
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    ConstElementPtr pruned = prune(expected, request);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*request));
 
     request_str = requests_[1];
     ASSERT_NO_THROW(request = Element::fromJSON(request_str));
@@ -1057,8 +1098,7 @@ TEST_F(NetconfAgentTest, validate) {
         "  }\n"
         "}";
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    pruned = prune(expected, request);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*request));
 
     // Check responses.
     ASSERT_EQ(2, responses_.size());
@@ -1069,8 +1109,7 @@ TEST_F(NetconfAgentTest, validate) {
         "\"result\": 0\n"
         "}";
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    pruned = prune(expected, response);
-    EXPECT_TRUE(expected->equals(*pruned));
+    EXPECT_TRUE(expected->equals(*response));
 
     response_str = responses_[1];
     ASSERT_NO_THROW(response = Element::fromJSON(response_str));
@@ -1078,9 +1117,7 @@ TEST_F(NetconfAgentTest, validate) {
         "\"result\": 0\n"
         "}";
     ASSERT_NO_THROW(expected = Element::fromJSON(expected_str));
-    pruned = prune(expected, response);
-    EXPECT_TRUE(expected->equals(*pruned));
-
+    EXPECT_TRUE(expected->equals(*response));
 }
 
 /// Verifies what happens when the validate method returns an error.