Browse Source

[5280] leaseX-update, leaseX-del implemented.

Tomek Mrugalski 7 years ago
parent
commit
d1be21aa57

+ 225 - 33
src/hooks/dhcp/lease_cmds/lease_cmds.cc

@@ -240,15 +240,13 @@ private:
     static ConstElementPtr
     leaseGetHandler(const string& command, ConstElementPtr args);
 
-    /// @brief lease4-del, lease6-del command handler
+    /// @brief lease4-del command handler
     ///
-    /// This command attempts to delete a lease that match selected criteria.
-    /// The following types of parameters are supported:
-    /// - (subnet-id, address) for both v4 and v6
-    /// - (subnet-id, identifier-type, identifier) for v4
-    /// - (subnet-id, type, iana, identifier-type, identifier) for v6
+    /// This command attempts to delete an IPv4 lease that match selected
+    /// criteria. Two types of parameters are supported: (subnet-id, address) or
+    /// (subnet-id, identifier-type, identifier).
     ///
-    /// Example command for command by (subnet-id, address):
+    /// Example command for deletion by (subnet-id, address):
     /// {
     ///     "command": "lease4-del",
     ///     "arguments": {
@@ -257,7 +255,7 @@ private:
     ///     }
     /// }
     ///
-    /// Example command for query by (subnet-id, identifier-type, identifier)
+    /// Example command for deletion by (subnet-id, identifier-type, identifier)
     /// {
     ///     "command": "lease4-del",
     ///     "arguments": {
@@ -265,33 +263,58 @@ private:
     ///         "identifier-type": "hw-address",
     ///         "identifier": "00:01:02:03:04:05"
     ///     }
-    /// }
+    /// }";
+    /// @param command should be 'lease4-del' (but it's ignored)
+    /// @param args must contain host reservation definition.
+    /// @return result of the operation (host will be included as parameters, if found)
+    static ConstElementPtr
+    lease4DelHandler(const string& command, ConstElementPtr args);
+
+    /// @brief lease6-del command handler
     ///
-    /// Example command for query by (subnet-id, type, iana, identifier-type,
-    ///                               identifier):
+    /// This command attempts to delete a lease that match selected criteria.
+    /// Two types of parameters are supported: (subnet-id, address) or
+    /// (subnet-id, type, iaid, identifier-type, identifier).
+    ///
+    /// Example command for deletion by (subnet-id, address):
     /// {
     ///     "command": "lease6-del",
     ///     "arguments": {
-    ///     "subnet-id": 66,
-    ///     "iaid": 42,
-    ///     "type": "IA_NA",
-    ///     "identifier-type": "duid",
-    ///     "identifier": "77:77:77:77:77:77:77:77"
+    ///         "subnet-id": 1,
+    ///         "ip-address": "192.0.2.202"
     ///     }
     /// }
-    /// @param command 'lease4-del' or 'lease6-del'
-    /// @param args must contain lease parameters
-    /// @return result of the operation
+    ///
+    /// Example command for deletion by (subnet-id, type, iaid, identifier-type,
+    /// identifier):
+    /// {
+    ///     "command": "lease6-del",
+    ///     "arguments": {
+    ///         "subnet-id": 1,
+    ///         "type": "IA_NA",
+    ///         "iaid": 123456,
+    ///         "identifier-type": "hw-address",
+    ///         "identifier": "00:01:02:03:04:05"
+    ///     }
+    /// }";
+    /// @param command should be 'lease6-del' (but it's ignored)
+    /// @param args must contain host reservation definition.
+    /// @return result of the operation (host will be included as parameters, if found)
     static ConstElementPtr
-    leaseDelHandler(const string& command, ConstElementPtr args);
+    lease6DelHandler(const string& command, ConstElementPtr args);
 
-    /// @brief Not implemented yet.
     static ConstElementPtr
-    leaseUpdateHandler(const string& command, ConstElementPtr args);
+    lease4UpdateHandler(const string& command, ConstElementPtr args);
 
     /// @brief Not implemented yet.
     static ConstElementPtr
-    leaseWipeHandler(const string& command, ConstElementPtr args);
+    lease6UpdateHandler(const string& command, ConstElementPtr args);
+
+    static ConstElementPtr
+    lease4WipeHandler(const string& command, ConstElementPtr args);
+
+    static ConstElementPtr
+    lease6WipeHandler(const string& command, ConstElementPtr args);
 
     /// @brief Extracts parameters required for reservation-get and reservation-del
     ///
@@ -326,19 +349,19 @@ void LeaseCmdsImpl::registerCommands() {
         boost::bind(&LeaseCmdsImpl::leaseGetHandler, _1, _2));
 
     CommandMgr::instance().registerCommand("lease4-del",
-    boost::bind(&LeaseCmdsImpl::leaseDelHandler, _1, _2));
+    boost::bind(&LeaseCmdsImpl::lease4DelHandler, _1, _2));
     CommandMgr::instance().registerCommand("lease6-del",
-    boost::bind(&LeaseCmdsImpl::leaseDelHandler, _1, _2));
+    boost::bind(&LeaseCmdsImpl::lease6DelHandler, _1, _2));
 
     CommandMgr::instance().registerCommand("lease4-update",
-    boost::bind(&LeaseCmdsImpl::leaseUpdateHandler, _1, _2));
+    boost::bind(&LeaseCmdsImpl::lease4UpdateHandler, _1, _2));
     CommandMgr::instance().registerCommand("lease6-update",
-    boost::bind(&LeaseCmdsImpl::leaseUpdateHandler, _1, _2));
+    boost::bind(&LeaseCmdsImpl::lease6UpdateHandler, _1, _2));
 
     CommandMgr::instance().registerCommand("lease4-del-all",
-    boost::bind(&LeaseCmdsImpl::leaseWipeHandler, _1, _2));
+    boost::bind(&LeaseCmdsImpl::lease4WipeHandler, _1, _2));
     CommandMgr::instance().registerCommand("lease6-del-all",
-    boost::bind(&LeaseCmdsImpl::leaseWipeHandler, _1, _2));
+    boost::bind(&LeaseCmdsImpl::lease6WipeHandler, _1, _2));
 }
 
 void LeaseCmdsImpl::deregisterCommands() {
@@ -579,17 +602,186 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
 }
 
 ConstElementPtr
-LeaseCmdsImpl::leaseDelHandler(const std::string& cmd, ConstElementPtr args) {
-    return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
+LeaseCmdsImpl::lease4DelHandler(const std::string& , ConstElementPtr params) {
+    Parameters p;
+    Lease4Ptr lease4;
+    IOAddress addr(IOAddress::IPV4_ZERO_ADDRESS());
+    try {
+        p = getParameters(params);
+
+        switch (p.query_type) {
+        case Parameters::TYPE_ADDR: {
+
+            // If address was specified explicitly, let's use it as is.
+            addr = p.addr;
+            break;
+        }
+        case Parameters::TYPE_HWADDR:
+            if (!p.hwaddr) {
+                return (createAnswer(CONTROL_RESULT_ERROR,
+                                     "Program error: Query by hw-address "
+                                     "requires hwaddr to be specified"));
+            }
+
+            // Let's see if there's such a lease at all.
+            lease4 = LeaseMgrFactory::instance().getLease4(*p.hwaddr, p.subnet_id);
+            if (!lease4) {
+                return (createAnswer(CONTROL_RESULT_EMPTY, "IPv4 lease not found."));
+            }
+
+            // Found it, can use it as is.
+            addr = lease4->addr_;
+            break;
+
+        case Parameters::TYPE_DUID:
+            return (createAnswer(CONTROL_RESULT_ERROR,
+                                     "Delete by duid is not allowed in v4."));
+            break;
+
+        default: {
+            stringstream tmp;
+            tmp << "Unknown query type: " << static_cast<int>(p.query_type);
+            return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
+        }
+        }
+
+        if (LeaseMgrFactory::instance().deleteLease(addr)) {
+            return (createAnswer(CONTROL_RESULT_SUCCESS, "IPv4 lease deleted."));
+        } else {
+            return (createAnswer(CONTROL_RESULT_EMPTY, "IPv4 lease not found."));
+        }
+    } catch (const std::exception& ex) {
+        return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
+    }
+}
+
+ConstElementPtr
+LeaseCmdsImpl::lease6DelHandler(const std::string& , ConstElementPtr params) {
+    Parameters p;
+    Lease6Ptr lease6;
+    IOAddress addr(IOAddress::IPV6_ZERO_ADDRESS());
+    try {
+        p = getParameters(params);
+
+        switch (p.query_type) {
+        case Parameters::TYPE_ADDR: {
+
+            // If address was specified explicitly, let's use it as is.
+            addr = p.addr;
+            break;
+        }
+        case Parameters::TYPE_HWADDR:
+            return (createAnswer(CONTROL_RESULT_ERROR,
+                                 "Delete by hw-address is not allowed in v6."));
+
+        case Parameters::TYPE_DUID:
+            if (!p.duid) {
+                return (createAnswer(CONTROL_RESULT_ERROR,
+                                     "Program error: Query by duid "
+                                     "requires duid to be specified"));
+            }
+
+            // Let's see if there's such a lease at all.
+            lease6 = LeaseMgrFactory::instance().getLease6(p.lease_type, *p.duid,
+                                                           p.iaid, p.subnet_id);
+            if (!lease6) {
+                return (createAnswer(CONTROL_RESULT_EMPTY, "IPv6 lease not found."));
+            }
+
+            // Found it, can use it as is.
+            addr = lease6->addr_;
+            break;
+
+        default: {
+            stringstream tmp;
+            tmp << "Unknown query type: " << static_cast<int>(p.query_type);
+            return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
+        }
+        }
+
+        if (LeaseMgrFactory::instance().deleteLease(addr)) {
+            return (createAnswer(CONTROL_RESULT_SUCCESS, "IPv6 lease deleted."));
+        } else {
+            return (createAnswer(CONTROL_RESULT_EMPTY, "IPv6 lease not found."));
+        }
+    } catch (const std::exception& ex) {
+        return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
+    }
+}
+
+ConstElementPtr
+LeaseCmdsImpl::lease4UpdateHandler(const string& , ConstElementPtr params) {
+    try {
+
+        // We need the lease to be specified.
+        if (!params) {
+            isc_throw(isc::BadValue, "no parameters specified for lease4-update command");
+        }
+
+        // Get the parameters specified by the user first.
+        ConstSrvConfigPtr config = CfgMgr::instance().getCurrentCfg();
+        Lease4Ptr lease4;
+        Lease4Parser parser;
+        // The parser does sanity checks (if the address is in scope, if
+        // subnet-id is valid, etc)
+        lease4 = parser.parse(config, params);
+
+        // Ok, now check if there is a lease to be updated.
+        Lease4Ptr existing = LeaseMgrFactory::instance().getLease4(lease4->addr_);
+        if (!existing) {
+            stringstream tmp;
+            tmp << "There is no lease for address " << lease4->addr_ << ", can't update.";
+            return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
+        }
+
+        LeaseMgrFactory::instance().updateLease4(lease4);
+        return (createAnswer(CONTROL_RESULT_SUCCESS, "IPv4 lease updated."));
+
+    } catch (const std::exception& ex) {
+        return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
+    }
+}
+
+ConstElementPtr
+LeaseCmdsImpl::lease6UpdateHandler(const string& , ConstElementPtr params) {
+    try {
+        // We need the lease to be specified.
+        if (!params) {
+            isc_throw(isc::BadValue, "no parameters specified for lease6-update command");
+        }
+
+        // Get the parameters specified by the user first.
+        ConstSrvConfigPtr config = CfgMgr::instance().getCurrentCfg();
+        Lease6Ptr lease6;
+        Lease6Parser parser;
+        // The parser does sanity checks (if the address is in scope, if
+        // subnet-id is valid, etc)
+        lease6 = parser.parse(config, params);
+
+        // Ok, now check if there is a lease to be updated.
+        Lease6Ptr existing = LeaseMgrFactory::instance().getLease6(lease6->type_,
+                                                                   lease6->addr_);
+        if (!existing) {
+            stringstream tmp;
+            tmp << "There is no lease for address " << lease6->addr_ << ", can't update.";
+            return (createAnswer(CONTROL_RESULT_EMPTY, tmp.str()));
+        }
+
+        LeaseMgrFactory::instance().updateLease6(lease6);
+        return (createAnswer(CONTROL_RESULT_SUCCESS, "IPv6 lease updated."));
+
+    } catch (const std::exception& ex) {
+        return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
+    }
 }
 
 ConstElementPtr
-LeaseCmdsImpl::leaseUpdateHandler(const string& cmd, ConstElementPtr args) {
+LeaseCmdsImpl::lease4WipeHandler(const string& cmd, ConstElementPtr args) {
     return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
 }
 
 ConstElementPtr
-LeaseCmdsImpl::leaseWipeHandler(const string& cmd, ConstElementPtr args) {
+LeaseCmdsImpl::lease6WipeHandler(const string& cmd, ConstElementPtr args) {
     return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
 }
 

+ 582 - 5
src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc

@@ -947,7 +947,7 @@ TEST_F(LeaseCmdsTest, Lease4GetMissingParams) {
 // valid, but the lease is not there.
 TEST_F(LeaseCmdsTest, Lease4GetByAddrNotFound) {
 
-    // Initialize lease manager (false = v4, true = add lease)
+    // Initialize lease manager (false = v4, true = add a lease)
     initLeaseMgr(false, true);
 
     // Invalid
@@ -966,7 +966,7 @@ TEST_F(LeaseCmdsTest, Lease4GetByAddrNotFound) {
 // Checks that lease4-get can return a lease by address.
 TEST_F(LeaseCmdsTest, Lease4GetByAddr) {
 
-    // Initialize lease manager (false = v4, true = add lease)
+    // Initialize lease manager (false = v4, true = add a lease)
     initLeaseMgr(false, true);
 
     // Query for valid, existing lease.
@@ -1014,7 +1014,7 @@ TEST_F(LeaseCmdsTest, Lease4GetByHWAddrNotFound) {
 // Checks that lease4-get can find a lease by hardware address.
 TEST_F(LeaseCmdsTest, Lease4GetByHWAddr) {
 
-    // Initialize lease manager (false = v4, true = add lease)
+    // Initialize lease manager (false = v4, true = add a lease)
     initLeaseMgr(false, true);
 
     // Invalid
@@ -1043,7 +1043,7 @@ TEST_F(LeaseCmdsTest, Lease4GetByHWAddr) {
 // the query is correctly formed, but the lease is not there.
 TEST_F(LeaseCmdsTest, Lease6GetByAddr6NotFound) {
 
-    // Initialize lease manager (true = v6, true = add lease)
+    // Initialize lease manager (true = v6, true = add a lease)
     initLeaseMgr(true, true);
 
     // Now send the command.
@@ -1065,7 +1065,7 @@ TEST_F(LeaseCmdsTest, Lease6GetByAddr6NotFound) {
 // Checks that lease6-get(subnet-id, addr) can handle a situation when
 // the query is correctly formed, but the lease is not there.
 TEST_F(LeaseCmdsTest, Lease6GetByDuidNotFound) {
-    // Initialize lease manager (true = v6, true = add lease)
+    // Initialize lease manager (true = v6, true = add a lease)
     initLeaseMgr(true, true);
 
     // Now send the command.
@@ -1179,4 +1179,581 @@ TEST_F(LeaseCmdsTest, Lease6GetByDUID) {
     checkLease6(lease, "2001:db8::1", 0, 66, "77:77:77:77:77:77:77:77", false);
 }
 
+// Test checks if lease4-update handler refuses calls with missing parameters.
+TEST_F(LeaseCmdsTest, Lease4UpdateMissingParams) {
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // Everything missing. What sort of crap is that?
+    string txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "    }\n"
+        "}";
+    string exp_rsp = "missing parameter 'ip-address' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Just ip is not enough (subnet-id and hwaddr missing).
+    txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "            \"ip-address\": \"192.0.2.123\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "missing parameter 'subnet-id' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Better, but still no luck. (hwaddr missing).
+    txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "            \"subnet-id\": 44,\n"
+        "            \"ip-address\": \"192.0.2.202\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "missing parameter 'hw-address' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Close, but no cigars. (ip-address missing).
+    txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "            \"subnet-id\": 44,\n"
+        "            \"hw-address\": \"1a:1b:1c:1d:1e:1f\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "missing parameter 'ip-address' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+}
+
+// Verify that lease4-update can be rejected if parameters are specified, but
+// have incorrect values.
+TEST_F(LeaseCmdsTest, Lease4UpdateBadParams) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // All params are there, but there's no subnet-id 123 configured.
+    // (initLeaseMgr initialized subnet-id 44 for v4 and subnet-id 66 for v6).
+    string txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123,\n"
+        "        \"ip-address\": \"192.0.2.202\",\n"
+        "        \"hw-address\": \"1a:1b:1c:1d:1e:1f\"\n"
+        "    }\n"
+        "}";
+    string exp_rsp = "Invalid subnet-id: No IPv4 subnet with subnet-id=123 currently configured.";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // This time the new IP address does not belong to the subnet.
+    txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 44,\n"
+        "        \"ip-address\": \"10.0.0.1\",\n"
+        "        \"hw-address\": \"1a:1b:1c:1d:1e:1f\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "The address 10.0.0.1 does not belong to subnet 192.0.2.0/24, subnet-id=44";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // We don't use any of that bleeding edge nonsense in this museum. v4 only.
+    txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 44,\n"
+        "        \"ip-address\": \"2001:db8::1\",\n"
+        "        \"hw-address\": \"1a:1b:1c:1d:1e:1f\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "Non-IPv4 address specified: 2001:db8::1";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+}
+
+// Check that a lease4 can be updated. We're changing hw-address
+// and a hostname.
+TEST_F(LeaseCmdsTest, Lease4Update) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // Now send the command.
+    string txt =
+        "{\n"
+        "    \"command\": \"lease4-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 44,\n"
+        "        \"ip-address\": \"192.0.2.1\",\n"
+        "        \"hw-address\": \"1a:1b:1c:1d:1e:1f\",\n"
+        "        \"hostname\": \"newhostname.example.org\""
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease updated.";
+    testCommand(txt, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Now check that the lease is still there.
+    Lease4Ptr l = lmptr_->getLease4(IOAddress("192.0.2.1"));
+    ASSERT_TRUE(l);
+
+    // Make sure it's been updated.
+    ASSERT_TRUE(l->hwaddr_);
+    EXPECT_EQ("1a:1b:1c:1d:1e:1f", l->hwaddr_->toText(false));
+    EXPECT_EQ("newhostname.example.org", l->hostname_);
+}
+
+// Test checks if lease6-update handler refuses calls with missing parameters.
+TEST_F(LeaseCmdsTest, Lease6UpdateMissingParams) {
+    // Initialize lease manager (true = v6, true = add a lease)
+    initLeaseMgr(true, true);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // Everything missing. What sort of crap is that?
+    string txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "    }\n"
+        "}";
+    string exp_rsp = "missing parameter 'ip-address' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Just ip is not enough (subnet-id and hwaddr missing).
+    txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "            \"ip-address\": \"2001:db8::1\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "missing parameter 'subnet-id' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Better, but still no luck. (duid missing).
+    txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "            \"subnet-id\": 44,\n"
+        "            \"ip-address\": \"2001:db8::1\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "missing parameter 'duid' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // ip-address and identifier-type missing.
+    txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "            \"subnet-id\": 44,\n"
+        "            \"duid\": \"1a:1b:1c:1d:1e:1f\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "missing parameter 'ip-address' (<string>:3:19)";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+}
+
+// Verify that lease6-update can be rejected if parameters are specified, but
+// have incorrect values.
+TEST_F(LeaseCmdsTest, Lease6UpdateBadParams) {
+
+    // Initialize lease manager (true = v6, true = add a lease)
+    initLeaseMgr(true, true);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // All params are there, but there's no subnet-id 123 configured.
+    // (initLeaseMgr initialized subnet-id 44 for v4 and subnet-id 66 for v6).
+    string txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123,\n"
+        "        \"ip-address\": \"2001:db8::1\",\n"
+        "        \"duid\": \"88:88:88:88:88:88:88:88\"\n"
+        "    }\n"
+        "}";
+    string exp_rsp = "Invalid subnet-id: No IPv6 subnet with subnet-id=123 currently configured.";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // This time the new IP address does not belong to the subnet.
+    txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 66,\n"
+        "        \"ip-address\": \"3000::1\",\n"
+        "        \"duid\": \"88:88:88:88:88:88:88:88\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "The address 3000::1 does not belong to subnet 2001:db8::/48, subnet-id=66";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Nope, can't do v4 address in v6 lease.
+    txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 66,\n"
+        "        \"ip-address\": \"192.0.2.1\",\n"
+        "        \"duid\": \"88:88:88:88:88:88:88:88\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "Non-IPv6 address specified: 192.0.2.1";
+    testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
+}
+
+// Check that a lease6 can be updated. We're changing hw-address
+// and a hostname.
+TEST_F(LeaseCmdsTest, Lease6Update) {
+
+    // Initialize lease manager (true = v6, true = add a lease)
+    initLeaseMgr(true, true);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // Now send the command.
+    string txt =
+        "{\n"
+        "    \"command\": \"lease6-update\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 66,\n"
+        "        \"ip-address\": \"2001:db8::1\",\n"
+        "        \"iaid\": 7654321,\n"
+        "        \"duid\": \"88:88:88:88:88:88:88:88\",\n"
+        "        \"hostname\": \"newhostname.example.org\""
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv6 lease updated.";
+    testCommand(txt, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Now check that the lease is really there.
+    Lease6Ptr l = lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8::1"));
+    ASSERT_TRUE(l);
+
+    // Make sure the lease has been updated.
+    ASSERT_TRUE(l->duid_);
+    EXPECT_EQ("88:88:88:88:88:88:88:88", l->duid_->toText());
+    EXPECT_EQ("newhostname.example.org", l->hostname_);
+    EXPECT_EQ(7654321, l->iaid_);
+}
+
+// Checks that lease6-del can handle a situation when the query is
+// broken (some required parameters are missing).
+TEST_F(LeaseCmdsTest, Lease4DelMissingParams) {
+
+    // No parameters whatsoever. You want just a lease, any lease?
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "    }\n"
+        "}";
+    string exp_rsp = "Mandatory 'subnet-id' parameter missing.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Just the subnet-id won't cut it, either.
+    cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123"
+        "    }\n"
+        "}";
+    exp_rsp = "No 'ip-address' provided and 'identifier-type' is either missing or not a string.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // We can't identify your laptop by color. Sorry, buddy.
+    cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier-type\": \"color\",\n"
+        "        \"identifier\": \"blue\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "Incorrect identifier type: color, the only supported values are: "
+        "address, hw-address, duid";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Query by DUID is not supported in v4. Sorry.
+    cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier-type\": \"duid\",\n"
+        "        \"identifier\": \"01:01:01:01:01:01\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "Delete by duid is not allowed in v4.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Identifier value is missing.
+    cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier-type\": \"hw-address\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "No 'ip-address' provided and 'identifier' is either missing or not a string.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+
+    // Identifier-type is missing.
+    cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier\": \"01:02:03:04:05\"\n"
+        "    }\n"
+        "}";
+    exp_rsp = "No 'ip-address' provided and 'identifier-type' is either missing or not a string.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+}
+
+// Checks that lease4-del can handle a situation when the query is
+// valid, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease4DelByAddrNotFound) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Invalid
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"ip-address\": \"192.0.2.5\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease not found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
+}
+
+// Checks that lease4-del can return a lease by address.
+TEST_F(LeaseCmdsTest, Lease4DelByAddr) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Query for valid, existing lease.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"ip-address\": \"192.0.2.1\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease deleted.";
+    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Make sure the lease is really gone.
+    EXPECT_FALSE(lmptr_->getLease4(IOAddress("192.0.2.1")));
+}
+
+// Checks that lease4-del can handle a situation when the query is
+// well formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease4DelByHWAddrNotFound) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // No such lease.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"hw-address\","
+        "        \"identifier\": \"01:02:03:04:05:06\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease not found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
+
+    // Make sure the lease is still there.
+    EXPECT_TRUE(lmptr_->getLease4(IOAddress("192.0.2.1")));
+}
+
+// Checks that lease4-del can find a lease by hardware address.
+TEST_F(LeaseCmdsTest, Lease4DelByHWAddr) {
+
+    // Initialize lease manager (false = v4, true = add a lease)
+    initLeaseMgr(false, true);
+
+    // Invalid
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease4-del\",\n"
+        "    \"arguments\": {"
+        "        \"identifier-type\": \"hw-address\","
+        "        \"identifier\": \"08:08:08:08:08:08\","
+        "        \"subnet-id\": 44"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv4 lease deleted.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Make sure the lease is really gone.
+    EXPECT_FALSE(lmptr_->getLease4(IOAddress("192.0.2.1")));
+}
+
+// Checks that lease6-del(addr) can handle a situation when
+// the query is correctly formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease6DelByAddr6NotFound) {
+
+    // Initialize lease manager (true = v6, true = add a lease)
+    initLeaseMgr(true, true);
+
+    // Now send the command.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease6-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 1,\n"
+        "        \"ip-address\": \"2001:db8::2\"\n"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv6 lease not found.";
+
+    // Note the status expected is empty. The query completed correctly,
+    // just didn't found the lease.
+    testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
+}
+
+// Checks that lease6-del(subnet-id, addr) can handle a situation when
+// the query is correctly formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease6DelByDuidNotFound) {
+
+    // Initialize lease manager (true = v6, true = add a lease)
+    initLeaseMgr(true, true);
+
+    // Now send the command.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease6-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 1,\n"
+        "        \"identifier-type\": \"duid\","
+        "        \"identifier\": \"00:01:02:03:04:05:06:07\"\n"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv6 lease not found.";
+
+    // Note the status expected is empty. The query completed correctly,
+    // just didn't found the lease.
+    testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
+
+    // Make sure the lease is still there.
+    EXPECT_TRUE(lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8::1")));
+}
+
+// Checks that lease6-del(subnet-id, addr6) can handle a situation when
+// the query is correctly formed and the lease is returned.
+TEST_F(LeaseCmdsTest, Lease6DelByAddr) {
+
+    initLeaseMgr(true, true); // (true = v6, true = create a lease)
+
+    // Now send the command.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease6-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 66,\n"
+        "        \"ip-address\": \"2001:db8::1\""
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv6 lease deleted.";
+
+    // The status expected is success. The lease should be deleted.
+    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Make sure the lease is really gone.
+    EXPECT_FALSE(lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8::1")));
+}
+
+// Checks that lease6-del(subnet-id, type, addr6) can handle a situation when
+// the query is correctly formed and the lease is deleted.
+TEST_F(LeaseCmdsTest, Lease6DelByAddrPrefix) {
+
+    initLeaseMgr(true, false); // (true = v6, false = don't add any leases)
+
+    // Let's start with regular address lease and make it a prefix lease.
+    Lease6Ptr l = createLease6();
+    l->addr_ = IOAddress("2001:db8:1234:ab::");
+    l->type_ = Lease::TYPE_PD;
+    l->prefixlen_ = 56;
+    lmptr_->addLease(l);
+
+    // Now send the command.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease6-del\",\n"
+        "    \"arguments\": {"
+        "        \"type\": \"IA_PD\","
+        "        \"ip-address\": \"2001:db8:1234:ab::\""
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv6 lease deleted.";
+
+    // The status expected is success. The lease should be deleted.
+    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Make sure the lease is really gone.
+    EXPECT_FALSE(lmptr_->getLease6(Lease::TYPE_PD, IOAddress("2001:db8:1234:ab::")));
+}
+
+// Checks that lease6-del(subnet-id, iaid, identifier-type, identifier) can handle
+// a situation when the query finds a lease.
+TEST_F(LeaseCmdsTest, Lease6DelByDUID) {
+
+    initLeaseMgr(true, true); // (true = v6, true = create a lease)
+
+    // Now send the command.
+    string cmd =
+        "{\n"
+        "    \"command\": \"lease6-del\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 66,\n"
+        "        \"iaid\": 42,"
+        "        \"identifier-type\": \"duid\","
+        "        \"identifier\": \"77:77:77:77:77:77:77:77\"\n"
+        "    }\n"
+        "}";
+    string exp_rsp = "IPv6 lease deleted.";
+
+    // The status expected is success. The lease should be deleted.
+    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Make sure the lease is really gone.
+    EXPECT_FALSE(lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8::1")));
+}
+
 } // end of anonymous namespace