]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5272] Couple more clean-ups.
authorTomek Mrugalski <tomasz@isc.org>
Wed, 2 Aug 2017 14:43:24 +0000 (16:43 +0200)
committerTomek Mrugalski <tomasz@isc.org>
Wed, 2 Aug 2017 14:43:24 +0000 (16:43 +0200)
src/hooks/dhcp/lease_cmds/lease_cmds.cc
src/hooks/dhcp/lease_cmds/tests/lease_cmds_unittest.cc
src/lib/dhcpsrv/lease.cc
src/lib/dhcpsrv/tests/lease_unittest.cc

index f0c6c2394195009ae2112763ebaa377c02ebda32..d9a033ca452fe4a99ec2db6ac9444bb5d61874f9 100644 (file)
@@ -44,8 +44,9 @@ public:
 /// As both call types (get and delete) need specify which reservation to
 /// act on, they have the same set of parameters. In particular, those
 /// two call types support the following sets of parameters:
-/// - subnet-id, address
-/// - subnet-id, identifier type, identifier value
+/// - address
+/// - subnet-id, identifier-type, identifier-value (v4)
+/// - subnet-id, lease-type, iaid, identifier-type, identifier-value (v6)
 ///
 /// This class stores those parameters and is used to pass them around.
 class Parameters {
@@ -114,7 +115,7 @@ private:
     /// - lease6-update
     /// - lease4-del-all
     /// - lease6-del-all
-    
+
     /// @throw Unexpected if CommandMgr is not available (should not happen)
     void registerCommands();
 
@@ -135,15 +136,15 @@ private:
     /// @throw Unexpected if CommandMgr is not available (should not happen)
     void deregisterCommands();
 
-    /// @brief reservation-add command handler
+    /// @brief lease4-add, lease6-add command handler
     ///
     /// This command attempts to add a lease.
     ///
     /// An example full command looks as follows. Note that the args
     /// parameter is expected to contain the "arguments" portion of it.
-    /// This function covers v4 lease only.
+    /// This function covers both v4 and v6 leases.
     ///
-    /// Example command
+    /// Example command for v4:
     /// {
     ///     "command": "lease4-add",
     ///     "parameters": {
@@ -151,7 +152,7 @@ private:
     ///         "hwaddr": "00:01:02:03:04:05",
     ///         "client-id": "this-is-a-client",
     ///         "valid-lft": 3600,
-    ///         "expire": 1499282530,
+    ///         "expire": 12345678,
     ///         "subnet-id": 1,
     ///         "fdqn-fwd": true,
     ///         "fqdn-rev": true,
@@ -159,6 +160,25 @@ private:
     ///         "state": 0
     ///     }
     /// }
+    /// Example command for v6:
+    /// {
+    ///     "command": "lease6-add",
+    ///     "arguments": {
+    ///         "subnet-id": 66,
+    ///         "ip-address": "2001:db8:abcd::",
+    ///         "type": "IA_PD",
+    ///         "prefix-len": 48,
+    ///         "duid": "01:02:03:04:05:06:07:08",
+    ///         "iaid": 1234,
+    ///         "preferred-lft": 500,
+    ///         "valid-lft": 1000,
+    ///         "expire": 12345678,
+    ///         "fqdn-fwd": true,
+    ///         "fqdn-rev": true,
+    ///         "hostname": "urania.example.org""
+    ///     }
+    /// }
+
     ///
     /// @param command should be 'reservation-add' (but it's ignored)
     /// @param args must contain host reservation definition.
@@ -230,12 +250,13 @@ private:
     static ConstElementPtr
     leaseDelHandler(const string& command, ConstElementPtr args);
 
+
     static ConstElementPtr
     leaseUpdateHandler(const string& command, ConstElementPtr args);
 
     static ConstElementPtr
     leaseWipeHandler(const string& command, ConstElementPtr args);
-    
+
     /// @brief Extracts parameters required for reservation-get and reservation-del
     ///
     /// See @ref Parameters class for detailed description of what is expected
@@ -245,18 +266,9 @@ private:
     /// @return parsed parameters
     /// @throw BadValue if input arguments don't make sense.
     static Parameters getParameters(const ConstElementPtr& args);
-
-    /// @brief Covenience pointer used to access database storage
-    static HostDataSourcePtr db_storage_;
-
-    /// @brief Protocol family (IPv4 or IPv6)
-    static uint16_t family_;
 };
 
 LeaseCmdsImpl::LeaseCmdsImpl() {
-    /// @todo: Remove family_
-    family_ = CfgMgr::instance().getFamily();
-
     registerCommands();
 }
 
@@ -265,7 +277,8 @@ LeaseCmdsImpl::~LeaseCmdsImpl() {
 }
 
 void LeaseCmdsImpl::registerCommands() {
-    /// @todo: Use registration mechanism once #5321 discussion is done
+    /// @todo: Use registration mechanism once #5314 is merged.
+    /// See #5321 discussion.
     CommandMgr::instance().registerCommand("lease4-add",
         boost::bind(&LeaseCmdsImpl::leaseAddHandler, _1, _2));
     CommandMgr::instance().registerCommand("lease6-add",
@@ -314,7 +327,7 @@ ConstElementPtr
 LeaseCmdsImpl::leaseAddHandler(const std::string& name,
                                ConstElementPtr params) {
     bool v4 = (name == "lease4-add");
-    
+
     string txt = "(missing parameters)";
     if (params) {
         txt = params->str();
@@ -338,7 +351,7 @@ LeaseCmdsImpl::leaseAddHandler(const std::string& name,
             if (lease4) {
                 LeaseMgrFactory::instance().addLease(lease4);
             }
-            
+
         } else {
             Lease6Parser parser;
             lease6 = parser.parse(config, params);
@@ -369,23 +382,31 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
         isc_throw(BadValue, "Parameters missing or are not a map.");
     }
 
-    // We support 2 sets of parameters for lease-get/lease-del:
-    // lease-get(subnet-id, address)
-    // lease-get(subnet-id, interifier-type, identifier)
-
-    ConstElementPtr tmp = params->get("subnet-id");
-    if (!tmp) {
-        isc_throw(BadValue, "Mandatory 'subnet-id' parameter missing.");
-    }
-    if (tmp->getType() != Element::integer) {
-        isc_throw(BadValue, "'subnet-id' parameter is not integer.");
+    // We support several sets of parameters for leaseX-get/lease-del:
+    // lease-get(type, address)
+    // lease-get(type, subnet-id, interifier-type, identifier)
+
+    if (params->contains("type")) {
+        string t = params->get("type")->stringValue();
+        if (t == "IA_NA" || t == "0") {
+            x.lease_type = Lease::TYPE_NA;
+        } else if (t == "IA_TA" || t == "1") {
+            x.lease_type = Lease::TYPE_TA;
+        } else if (t == "IA_PD" || t == "2") {
+            x.lease_type = Lease::TYPE_PD;
+        } else if (t == "V4" || t == "3") {
+            x.lease_type = Lease::TYPE_V4;
+        } else {
+            isc_throw(BadValue, "Invalid lease type specified: "
+                      << t << ", only supported values are: IA_NA, IA_TA,"
+                      << " IA_PD and V4");
+        }
     }
-    x.subnet_id = tmp->intValue();
 
-    tmp = params->get("address");
+    ConstElementPtr tmp = params->get("ip-address");
     if (tmp) {
         if (tmp->getType() != Element::string) {
-            isc_throw(BadValue, "'address' is not a string.");
+            isc_throw(BadValue, "'ip-address' is not a string.");
         }
 
         x.addr = IOAddress(tmp->stringValue());
@@ -393,6 +414,19 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
         return (x);
     }
 
+    tmp = params->get("subnet-id");
+    if (!tmp) {
+        isc_throw(BadValue, "Mandatory 'subnet-id' parameter missing.");
+    }
+    if (tmp->getType() != Element::integer) {
+        isc_throw(BadValue, "'subnet-id' parameter is not integer.");
+    }
+    x.subnet_id = tmp->intValue();
+
+    if (params->contains("iaid")) {
+        x.iaid = params->get("iaid")->intValue();
+    }
+
     // No address specified. Ok, so it must be identifier based query.
     // "identifier-type": "duid",
     // "identifier": "aa:bb:cc:dd:ee:..."
@@ -421,6 +455,7 @@ LeaseCmdsImpl::getParameters(const ConstElementPtr& params) {
     case Parameters::TYPE_DUID: {
         DUID duid = DUID::fromText(ident->stringValue());
         x.duid = DuidPtr(new DUID(duid));
+        break;
     }
     case Parameters::TYPE_ADDR: {
         // We should never get here. The address clause should have been caught
@@ -466,6 +501,7 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
                 return (createAnswer(CONTROL_RESULT_ERROR,
                                      "Query by hw-address is not allowed in v6."));
             }
+            break;
         case Parameters::TYPE_DUID:
             if (!v4) {
                 if (!p.duid) {
@@ -479,6 +515,7 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
                 return (createAnswer(CONTROL_RESULT_ERROR,
                                      "Query by duid is not allowed in v4."));
             }
+            break;
         default: {
             stringstream tmp;
             tmp << "Unknown query type: " << static_cast<int>(p.query_type);
@@ -486,20 +523,18 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
         }
         }
     } catch (const std::exception& ex) {
-        stringstream tmp;
-        tmp << "Failure during leaseX-get: " << ex.what();
-        return (createAnswer(CONTROL_RESULT_ERROR, tmp.str()));
+        return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
     }
 
     ElementPtr lease_json;
     if (v4 && lease4) {
         lease_json = lease4->toElement();
-        return (createAnswer(CONTROL_RESULT_SUCCESS, "DHCPv4 lease found.", lease_json));
+        return (createAnswer(CONTROL_RESULT_SUCCESS, "IPv4 lease found.", lease_json));
     }
     if (!v4 && lease6) {
         lease_json = lease6->toElement();
-        return (createAnswer(CONTROL_RESULT_SUCCESS, "DHCPv6 lease found.", lease_json));
-        
+        return (createAnswer(CONTROL_RESULT_SUCCESS, "IPv6 lease found.", lease_json));
+
     }
 
     // If we got here, the lease has not been found.
@@ -507,53 +542,20 @@ LeaseCmdsImpl::leaseGetHandler(const std::string& name, ConstElementPtr params)
 }
 
 ConstElementPtr
-LeaseCmdsImpl::leaseDelHandler(const std::string& name,
-                               ConstElementPtr params) {
-    Parameters p;
-    bool deleted = false;
-#if 0    
-    try {
-        p = getParameters(params);
-
-        if (p.query_by_addr) {
-            // try to delete by address
-            deleted = LeaseMgrFactory::instance().del(p.subnet_id, p.addr);
-        } else {
-            // try to delete by identifier
-            if (family_ == AF_INET) {
-                deleted = LeaseMgrFactory::instance().del4(p.subnet_id, p.type,
-                                                           &p.ident[0], p.ident.size());
-            } else {
-                deleted = LeaseMgrFactory::instance().del6(p.subnet_id, p.type,
-                                                           &p.ident[0], p.ident.size());
-            }
-        }
-    } catch (const std::exception& ex) {
-        return (createAnswer(CONTROL_RESULT_ERROR, ex.what()));
-    }
-#endif
-
-    if (deleted) {
-        return (createAnswer(CONTROL_RESULT_SUCCESS, "Lease deleted."));
-    } else {
-        return (createAnswer(CONTROL_RESULT_ERROR,
-                             "Lease not deleted (not found)."));
-    }
+LeaseCmdsImpl::leaseDelHandler(const std::string& cmd, ConstElementPtr args) {
+    return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
 }
 
 ConstElementPtr
-LeaseCmdsImpl::leaseUpdateHandler(const string& command, ConstElementPtr args) {
+LeaseCmdsImpl::leaseUpdateHandler(const string& cmd, ConstElementPtr args) {
     return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
 }
 
 ConstElementPtr
-LeaseCmdsImpl::leaseWipeHandler(const string& command, ConstElementPtr args) {
+LeaseCmdsImpl::leaseWipeHandler(const string& cmd, ConstElementPtr args) {
     return (createAnswer(CONTROL_RESULT_ERROR, "not implemented yet."));
 }
 
-
-uint16_t LeaseCmdsImpl::family_ = AF_INET;
-
 LeaseCmds::LeaseCmds()
     :impl_(new LeaseCmdsImpl()) {
 }
index 530717649280fd13c5185a66146e3adddfe03e05..bc13ab67aad6402f5dca27c5a35faddc7b181ee3 100644 (file)
@@ -105,10 +105,8 @@ public:
             return (ConstElementPtr());
         }
 
-        cout << "#### processing command " << cmd->str() << endl;
-
+        // Process the command and verify response.
         ConstElementPtr rsp = CommandMgr::instance().processCommand(cmd);
-
         checkAnswer(rsp, exp_result, exp_txt);
 
         return (rsp);
@@ -120,7 +118,6 @@ public:
     /// comment.
     /// @param exp_status is an integer against which to compare the status.
     /// @param exp_txt is expected text (not checked if "")
-    ///
     void checkAnswer(isc::data::ConstElementPtr answer,
                      int exp_status,
                      string exp_txt = "") {
@@ -151,12 +148,52 @@ public:
     void loadLib() {
         if (libraries_.empty()) {
             data::ElementPtr params = data::Element::createMap();
-            std::cout << "Trying to load " << lib_name_ << "..." << std::endl;
             addLib(lib_name_, params);
         }
         EXPECT_NO_THROW(loadLibs());
     }
 
+    /// @brief Test checks if specified commands are provided by the library.
+    ///
+    /// @param cms a vector of string with command names
+    void testCommands(const std::vector<string> cmds) {
+
+        // The commands should not be registered yet.
+        for (auto cmd = cmds.begin(); cmd != cmds.end(); ++cmd) {
+            checkCommandRegistered(*cmd, false);
+        }
+
+        loadLib();
+
+        // The commands should be available after library was loaded.
+        for (auto cmd = cmds.begin(); cmd != cmds.end(); ++cmd) {
+            checkCommandRegistered(*cmd, true);
+        }
+
+        unloadLibs();
+
+        // and the commands should be gone now.
+        for (auto cmd = cmds.begin(); cmd != cmds.end(); ++cmd) {
+            checkCommandRegistered(*cmd, false);
+        }
+
+    }
+
+    // Check that the library can be loaded and unloaded multiple times.
+    void testMultipleLoads() {
+        EXPECT_NO_THROW(loadLib());
+        EXPECT_NO_THROW(unloadLibs());
+
+        EXPECT_NO_THROW(loadLib());
+        EXPECT_NO_THROW(unloadLibs());
+
+        EXPECT_NO_THROW(loadLib());
+        EXPECT_NO_THROW(unloadLibs());
+
+        EXPECT_NO_THROW(loadLib());
+        EXPECT_NO_THROW(unloadLibs());
+    }
+
     /// List of libraries to be/being loaded (usually just one)
     HookLibsCollection libraries_;
 
@@ -164,22 +201,45 @@ public:
     std::string lib_name_;
 };
 
+/// @brief Class dedicated to testing lease_cmds library.
+///
+/// Provides convenience methods for loading, testing all commands and
+/// unloading the lease_cmds library.
 class LeaseCmdsTest : public LibLoadTest {
 public:
 
     /// @brief Pointer to the lease manager
     LeaseMgr* lmptr_;
 
+    /// @brief Constructor
+    ///
+    /// Sets the library filename and clears the lease manager pointer.
+    /// Also ensured there is no lease manager leftovers from previous
+    /// test.
     LeaseCmdsTest()
         :LibLoadTest(LIB_SO) {
+        LeaseMgrFactory::destroy();
         lmptr_ = 0;
     }
 
+    /// @brief Destructor
+    ///
+    /// Removes library (if any), destroys lease manager (if any).
     virtual ~LeaseCmdsTest() {
+        unloadLibs();
         LeaseMgrFactory::destroy();
         lmptr_ = 0;
     }
 
+    /// @brief Initializes lease manager (and optionally populates it with a lease)
+    ///
+    /// Creates a lease manager (memfile, trimmed down to keep everything in memory
+    /// only) and optionally can create a lease, which is useful for leaseX-get and
+    /// leasex-del type of tests. For lease details, see @ref createLease4 and
+    /// @ref createLease6.
+    ///
+    /// @param v6 true = v6, false = v4
+    /// @param insert_lease governs whether a lease should be pre-inserted
     void initLeaseMgr(bool v6, bool insert_lease) {
 
         LeaseMgrFactory::destroy();
@@ -207,15 +267,23 @@ public:
             if (v6) {
                 lmptr_->addLease(createLease6());
             } else {
-                lmptr_->addLease(createLease6());
+                lmptr_->addLease(createLease4());
             }
         }
     }
 
+    /// @brief Creates an IPv4 lease
+    ///
+    /// Lease parameters: ip-address = 192.0.2.1, hwaddr = 08:08:08:08:08:08,
+    /// client-id = 42:42:42:42:42:42:42:42, valid lifetime = 3600,
+    /// cltt = 12345678, subnet-id = 44, fqdn-fwd = false, fqdn-rev = true
+    /// hostname = myhost.example.com
+    ///
+    /// @return Returns the lease created
     Lease4Ptr createLease4() {
         Lease4Ptr lease(new Lease4());
 
-        lease->addr_ = IOAddress("192.0.2.123");
+        lease->addr_ = IOAddress("192.0.2.1");
 
         // Initialize unused fields.
         lease->t1_ = 0;                             // Not saved
@@ -224,27 +292,36 @@ public:
         // Set other parameters.  For historical reasons, address 0 is not used.
         lease->hwaddr_.reset(new HWAddr(vector<uint8_t>(6, 0x08), HTYPE_ETHER));
         lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x42)));
-        lease->valid_lft_ = 8677;
-        lease->cltt_ = 168256;
-        lease->subnet_id_ = 23;
-        lease->fqdn_rev_ = true;
+        lease->valid_lft_ = 3600;
+        lease->cltt_ = 12345678;
+        lease->subnet_id_ = 44;
         lease->fqdn_fwd_ = false;
+        lease->fqdn_rev_ = true;
         lease->hostname_ = "myhost.example.com.";
 
         return (lease);
     }
 
+    /// @brief Creates an IPv6 lease
+    ///
+    /// Lease parameters: ip-address = 2001:db8::1, duid = 77:77:77:77:77:77:77:77,
+    /// cltt = 12345678, subnet-id = 66, fqdn-fwd = false, fqdn-rev = true,
+    /// hostname = myhost.example.com preferred lifetime = 1800,
+    /// valid lifetime = 3600
+    ///
+    /// @return Returns the lease created
     Lease6Ptr createLease6() {
         Lease6Ptr lease(new Lease6());
 
+        lease->addr_ = IOAddress("2001:db8::1");
         lease->type_ = Lease::TYPE_NA;
-        lease->prefixlen_ = 4;
-        lease->iaid_ = 142;
+        lease->prefixlen_ = 128;
+        lease->iaid_ = 42;
         lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x77)));
-        lease->preferred_lft_ = 900;
-        lease->valid_lft_ = 8677;
-        lease->cltt_ = 168256;
-        lease->subnet_id_ = 23;
+        lease->preferred_lft_ = 1800;
+        lease->valid_lft_ = 3600;
+        lease->cltt_ = 12345678;
+        lease->subnet_id_ = 66;
         lease->fqdn_fwd_ = true;
         lease->fqdn_rev_ = true;
         lease->hostname_ = "myhost.example.com.";
@@ -252,56 +329,93 @@ public:
         return (lease);
     }
 
-
-    // @brief Checks if specified response contains IPv4 lease
-    void checkResponseLease4(ConstElementPtr rsp, bool client_id_required) {
-        ASSERT_TRUE(rsp);
-        ConstElementPtr l = rsp->get("arguments"); // Lease
+    /// @brief Checks if specified response contains IPv4 lease
+    ///
+    /// @param lease Element tree that represents a lease
+    /// @param ip expected IP address
+    /// @param subnet_id expected subnet-id
+    /// @param hwaddr expected value of hardware address
+    /// @param client_id_required true if client-id is expected
+    void checkLease4(ConstElementPtr l, std::string ip,
+                     uint32_t subnet_id, std::string hwaddr,
+                     bool client_id_required) {
         ASSERT_TRUE(l);
-        EXPECT_TRUE(l->get("ip-address"));
+        ASSERT_TRUE(l->get("ip-address"));
+        EXPECT_EQ(ip, l->get("ip-address")->stringValue());
+
+        ASSERT_TRUE(l->get("subnet-id"));
+        EXPECT_EQ(subnet_id, l->get("subnet-id")->intValue());
+
+        ASSERT_TRUE(l->get("hw-address"));
+        EXPECT_EQ(hwaddr, l->get("hw-address")->stringValue());
+
         // client-id may or may not appear
         if (client_id_required) {
             EXPECT_TRUE(l->get("client-id"));
         }
-        EXPECT_TRUE(l->get("hw-address"));
-        EXPECT_TRUE(l->get("valid-lft"));
-        EXPECT_TRUE(l->get("expire"));
-        EXPECT_TRUE(l->get("subnet-id"));
-        EXPECT_TRUE(l->get("state"));
-        EXPECT_TRUE(l->get("fqdn-fwd"));
-        EXPECT_TRUE(l->get("fqdn-rev"));
-        EXPECT_TRUE(l->get("hostname"));
-        EXPECT_TRUE(l->get("state"));
 
+        // Check that other parameters are there.
+        EXPECT_TRUE(l->contains("valid-lft"));
+        EXPECT_TRUE(l->contains("cltt"));
+        EXPECT_TRUE(l->contains("subnet-id"));
+        EXPECT_TRUE(l->contains("state"));
+        EXPECT_TRUE(l->contains("fqdn-fwd"));
+        EXPECT_TRUE(l->contains("fqdn-rev"));
+        EXPECT_TRUE(l->contains("hostname"));
+        EXPECT_TRUE(l->contains("state"));
 
         // Check that there are no v6 specific fields
-        EXPECT_FALSE(l->get("prefix"));
-        EXPECT_FALSE(l->get("duid"));
+        EXPECT_FALSE(l->contains("prefix"));
+        EXPECT_FALSE(l->contains("duid"));
+        EXPECT_FALSE(l->contains("preferred-lft"));
     }
 
-    // @brief Checks if specified response contains IPv6 lease
-    void checkResponseHost6(ConstElementPtr rsp) {
-        ASSERT_TRUE(rsp);
-        ConstElementPtr l = rsp->get("arguments"); // lease
+    /// @brief Checks if specified response contains IPv6 lease
+    ///
+    /// @param lease Element tree that represents a lease
+    /// @param ip expected IP address (or prefix)
+    /// @param prefixlen prefix length (0 = expect address)
+    /// @param subnet_id expected subnet-id
+    /// @param duid expected value of DUID
+    /// @param hwaddr_required true if hwaddr is expected
+    void checkLease6(ConstElementPtr l, std::string ip,
+                     uint8_t prefixlen,
+                     uint32_t subnet_id, std::string duid,
+                     bool hwaddr_required) {
+
         ASSERT_TRUE(l);
 
+        ASSERT_TRUE(l->contains("ip-address"));
+        EXPECT_EQ(ip, l->get("ip-address")->stringValue());
+        if (prefixlen != 0) {
+            ASSERT_TRUE(l->get("prefix-len"));
+            EXPECT_EQ(prefixlen, l->get("prefix-len")->intValue());
+        }
+
+        ASSERT_TRUE(l->contains("subnet-id"));
+        EXPECT_EQ(subnet_id, l->get("subnet-id")->intValue());
+
+        ASSERT_TRUE(l->contains("duid"));
+        EXPECT_EQ(duid, l->get("duid")->stringValue());
+
+        // hwaddr may or may not appear
+        if (hwaddr_required) {
+            EXPECT_TRUE(l->get("hwaddr"));
+        }
+
         // Check that there are expected fields
-        ASSERT_TRUE(l->contains("ip-address") || l->contains("prefix"))
-            << " either ip-address or prefix must be present for IPv6 lease";
-        EXPECT_TRUE(l->get("duid"));
-        EXPECT_TRUE(l->get("valid-lft"));
-        EXPECT_TRUE(l->get("expire"));
-        EXPECT_TRUE(l->get("subnet-id"));
-        EXPECT_TRUE(l->get("fqdn-fwd"));
-        EXPECT_TRUE(l->get("fqdn-rev"));
-        EXPECT_TRUE(l->get("hostname"));
-        EXPECT_TRUE(l->get("state"));
+        EXPECT_TRUE(l->contains("preferred-lft"));
+        EXPECT_TRUE(l->contains("valid-lft"));
+        EXPECT_TRUE(l->contains("cltt"));
+        EXPECT_TRUE(l->contains("subnet-id"));
+        EXPECT_TRUE(l->contains("fqdn-fwd"));
+        EXPECT_TRUE(l->contains("fqdn-rev"));
+        EXPECT_TRUE(l->contains("hostname"));
+        EXPECT_TRUE(l->contains("state"));
 
         // Check that there are no v4 specific fields.
-        EXPECT_FALSE(l->get("hw-address"));
-        EXPECT_FALSE(l->get("client-id"));
+        EXPECT_FALSE(l->contains("client-id"));
     }
-
 };
 
 // Simple test that checks the library really registers the commands.
@@ -312,48 +426,18 @@ TEST_F(LeaseCmdsTest, commands) {
                             "lease4-del", "lease6-del",
                             "lease4-update", "lease6-update",
                             "lease4-del-all", "lease6-del-all" };
-
-    // The commands should not be registered yet.
-    for (auto cmd = cmds.begin(); cmd != cmds.end(); ++cmd) {
-        checkCommandRegistered(*cmd, false);
-    }
-
-    loadLib();
-
-
-    // The commands should be available after library was loaded.
-    for (auto cmd = cmds.begin(); cmd != cmds.end(); ++cmd) {
-        checkCommandRegistered(*cmd, true);
-    }
-
-    unloadLibs();
-
-    // and the commands should be gone now.
-    for (auto cmd = cmds.begin(); cmd != cmds.end(); ++cmd) {
-        checkCommandRegistered(*cmd, false);
-    }
+    testCommands(cmds);
 }
 
 // Check that the library can be loaded and unloaded multiple times.
 TEST_F(LeaseCmdsTest, multipleLoads) {
-
-    EXPECT_NO_THROW(loadLib());
-    EXPECT_NO_THROW(unloadLibs());
-
-    EXPECT_NO_THROW(loadLib());
-    EXPECT_NO_THROW(unloadLibs());
-
-    EXPECT_NO_THROW(loadLib());
-    EXPECT_NO_THROW(unloadLibs());
-
-    EXPECT_NO_THROW(loadLib());
-    EXPECT_NO_THROW(unloadLibs());
+    testMultipleLoads();
 }
 
 using namespace isc::dhcp;
 
-// Check that lease4-add with bad params will fail.
-TEST_F(LeaseCmdsTest, Lease4AddBadParams) {
+// Check that lease4-add with missing parameters will fail.
+TEST_F(LeaseCmdsTest, Lease4AddMissingParams) {
 
     // Initialize lease manager (false = v4, false = don't add leases)
     initLeaseMgr(false, false);
@@ -382,7 +466,7 @@ TEST_F(LeaseCmdsTest, Lease4AddBadParams) {
     exp_rsp = "missing parameter 'subnet-id' (<string>:3:19)";
     testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
 
-    // Just subnet-id and ip is not enough (hwaddr missing).
+    // Better, but still no luck. (hwaddr missing).
     txt =
         "{\n"
         "    \"command\": \"lease4-add\",\n"
@@ -394,7 +478,7 @@ TEST_F(LeaseCmdsTest, Lease4AddBadParams) {
     exp_rsp = "missing parameter 'hw-address' (<string>:3:19)";
     testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
 
-    // Just subnet-id and hw-address is not enough (ip missing).
+    // Close, but no cigars. (ip-address missing).
     txt =
         "{\n"
         "    \"command\": \"lease4-add\",\n"
@@ -407,9 +491,9 @@ TEST_F(LeaseCmdsTest, Lease4AddBadParams) {
     testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
 }
 
-// Verify that lease4-add can be rejected if parameters specified, but
+// Verify that lease4-add can be rejected if parameters are specified, but
 // have incorrect values.
-TEST_F(LeaseCmdsTest, Lease4AddSanityChecks) {
+TEST_F(LeaseCmdsTest, Lease4AddBadParams) {
 
     // Initialize lease manager (false = v4, false = don't add leases)
     initLeaseMgr(false, false);
@@ -418,7 +502,7 @@ TEST_F(LeaseCmdsTest, Lease4AddSanityChecks) {
     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.
+    // (initLeaseMgr initialized subnet-id 44 for v4 and subnet-id 66 for v6).
     string txt =
         "{\n"
         "    \"command\": \"lease4-add\",\n"
@@ -444,8 +528,7 @@ TEST_F(LeaseCmdsTest, Lease4AddSanityChecks) {
     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);
 
-    // Get lost with this v6 nonsense. We don't use any of that bleeding edge
-    // nonsense in this museum. v4 only.
+    // We don't use any of that bleeding edge nonsense in this museum. v4 only.
     txt =
         "{\n"
         "    \"command\": \"lease4-add\",\n"
@@ -494,7 +577,7 @@ TEST_F(LeaseCmdsTest, Lease4Add) {
     EXPECT_EQ("", l->hostname_);
 
     // Test execution is fast. The cltt should be set to now. In some rare
-    // cases we could hit the seconds counter to tick, so having a value off
+    // cases we could have the seconds counter to tick, so having a value off
     // by one is ok.
     EXPECT_LE(abs(l->cltt_ - time(NULL)), 1);
     EXPECT_EQ(0, l->state_);
@@ -543,8 +626,8 @@ TEST_F(LeaseCmdsTest, Lease4AddFull) {
     EXPECT_EQ("urania.example.org", l->hostname_);
 }
 
-// Check that lease6-add will bad parameters will fail.
-TEST_F(LeaseCmdsTest, Lease6AddBadParams) {
+// Check that lease6-add with missing parameters will fail.
+TEST_F(LeaseCmdsTest, Lease6AddMissingParams) {
 
     // Initialize lease manager (true = v6, false = don't add leases)
     initLeaseMgr(true, false);
@@ -626,7 +709,7 @@ TEST_F(LeaseCmdsTest, Lease6AddBadParams) {
 
 // Verify that lease6-add can be rejected if parameters specified, but
 // have incorrect values.
-TEST_F(LeaseCmdsTest, Lease6AddSanityChecks) {
+TEST_F(LeaseCmdsTest, Lease6AddBadParams) {
 
     // Initialize lease manager (true = v6, false = don't add leases)
     initLeaseMgr(true, false);
@@ -662,7 +745,7 @@ TEST_F(LeaseCmdsTest, Lease6AddSanityChecks) {
     exp_rsp = "The address 3000::3 does not belong to subnet 2001:db8::/48, subnet-id=66";
     testCommand(txt, CONTROL_RESULT_ERROR, exp_rsp);
 
-    // Let's warp back in time. Who needs this v6 nonsense anyway?
+    // v4? You're a time traveller from early 80s or what?
     txt =
         "{\n"
         "    \"command\": \"lease6-add\",\n"
@@ -704,7 +787,39 @@ TEST_F(LeaseCmdsTest, Lease6Add) {
     EXPECT_TRUE(lmptr_->getLease6(Lease::TYPE_NA, IOAddress("2001:db8::3")));
 }
 
-// Check that a well formed lease4 with tons of parameters can be added.
+// Check that a simple, well formed prefix lease can be added.
+TEST_F(LeaseCmdsTest, Lease6AddPrefix) {
+
+    // Initialize lease manager (true = v6, false = don't add leases)
+    initLeaseMgr(true, false);
+
+    // Check that the lease manager pointer is there.
+    ASSERT_TRUE(lmptr_);
+
+    // Now send the command.
+    string txt =
+        "{\n"
+        "    \"command\": \"lease6-add\",\n"
+        "    \"arguments\": {"
+        "        \"subnet-id\": 66,\n"
+        "        \"ip-address\": \"2001:db8:abcd::\",\n"
+        "        \"prefix-len\": 48,\n"
+        "        \"type\": \"IA_PD\",\n"
+        "        \"duid\": \"1a:1b:1c:1d:1e:1f\",\n"
+        "        \"iaid\": 1234\n"
+        "    }\n"
+        "}";
+    string exp_rsp = "Lease added.";
+    testCommand(txt, CONTROL_RESULT_SUCCESS, exp_rsp);
+
+    // Now check that the lease is really there.
+    Lease6Ptr l = lmptr_->getLease6(Lease::TYPE_PD, IOAddress("2001:db8:abcd::"));
+    ASSERT_TRUE(l);
+    EXPECT_EQ(Lease::TYPE_PD, l->type_);
+    EXPECT_EQ(48, l->prefixlen_);
+}
+
+// Check that a well formed lease6 with tons of parameters can be added.
 TEST_F(LeaseCmdsTest, Lease6AddFullAddr) {
 
     // Initialize lease manager (true = v6, false = don't add leases)
@@ -749,10 +864,11 @@ TEST_F(LeaseCmdsTest, Lease6AddFullAddr) {
     EXPECT_EQ("urania.example.org", l->hostname_);
 }
 
-// Checks that lease4-get can handle a situation when the query is
-// broken (no parameters at all).
-TEST_F(LeaseCmdsTest, Lease4GetNoParams) {
-    // Now send the command.
+// Checks that lease6-get can handle a situation when the query is
+// broken (some required parameters are missing).
+TEST_F(LeaseCmdsTest, Lease4GetMissingParams) {
+
+    // No parameters whatsoever. You want just a lease, any lease?
     string cmd =
         "{\n"
         "    \"command\": \"lease4-get\",\n"
@@ -760,502 +876,305 @@ TEST_F(LeaseCmdsTest, Lease4GetNoParams) {
         "    }\n"
         "}";
     string exp_rsp = "Mandatory 'subnet-id' parameter missing.";
-
-    // This should be rejected, because subnet-id parameter is mandatory.
     testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
-}
 
-// Checks that lease4-get can handle a situation when the query is
-// broken (just subnet-id).
-TEST_F(LeaseCmdsTest, Lease4GetNoAddress) {
-    string cmd =
+    // Just the subnet-id won't cut it, either.
+    cmd =
         "{\n"
         "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1\n"
+        "        \"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);
 
-    string rsp = "No 'ip-address' provided and 'identifier-type' is either "
-                 "missing or not a string.";
-
-    // Providing just subnet-id is not enough, the code needs either
-    // (subnet-id, addr) or (subnet-id, identifier-type, identifier)
-    testCommand(cmd, CONTROL_RESULT_ERROR, rsp);
-}
-
-// Checks that reservation-get can handle a situation when the query is
-// broken (subnet-id, identifier-type) and identifier itself missing.
-TEST_F(LeaseCmdsTest, Lease4GetNoIdentifier) {
-    string cmd =
+    // We can't identify your laptop by color. Sorry, buddy.
+    cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"identifier-type\": \"hw-address\""
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier-type\": \"color\",\n"
+        "        \"identifier\": \"blue\"\n"
         "    }\n"
         "}";
-    string rsp = "No 'ip-address' provided and 'identifier' is either missing "
-                 "or not a string.";
-
-    // It's better (one parameter missing), but we still not there yet.
-    testCommand(cmd, CONTROL_RESULT_ERROR, rsp);
-}
+    exp_rsp = "Incorrect identifier type: color, the only supported values are: "
+        "address, hw-address, duid";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
 
-// Checks that reservation-get can handle a situation when the query is
-// broken (subnet-id, identifier) and identifier-type is missing.
-TEST_F(LeaseCmdsTest, ReservationGetNoIdentifierType) {
-    string cmd =
+    // Query by DUID is not supported in v4. Sorry.
+    cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"identifier\": \"00:11:22:33:44:55\""
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier-type\": \"duid\",\n"
+        "        \"identifier\": \"01:01:01:01:01:01\"\n"
         "    }\n"
         "}";
-    string rsp = "No 'ip-address' provided and 'identifier-type' is either missing "
-                 "or not a string.";
-
-    testCommand(cmd, CONTROL_RESULT_ERROR, rsp);
-}
+    exp_rsp = "Query by duid is not allowed in v4.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
 
-// Checks that reservation-get(subnet-id, addr) can handle a situation when
-// the query is correctly formed, but the host is not there.
-TEST_F(LeaseCmdsTest, ReservationGetByAddr4NotFound) {
-    // Now send the command.
-    string cmd =
+    // Identifier value is missing.
+    cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"ip-address\": \"192.0.2.202\"\n"
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier-type\": \"hw-address\"\n"
         "    }\n"
         "}";
-    string exp_rsp = "Host not found.";
-
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-}
-
-// Checks that reservation-get(subnet-id, addr4) can handle a situation when
-// the query is correctly formed and the host is returned.
-TEST_F(LeaseCmdsTest, ReservationGetByAddr4) {
-
-    // First, let's create a dummy host data source.
-    initLeaseMgr(true, false); // insert v4 host
+    exp_rsp = "No 'ip-address' provided and 'identifier' is either missing or not a string.";
+    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
 
-    // Now send the command.
-    string cmd =
+    // Identifier-type is missing.
+    cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 4,\n"
-        "        \"ip-address\": \"192.0.2.100\"\n"
+        "        \"subnet-id\": 123,\n"
+        "        \"identifier\": \"01:02:03:04:05\"\n"
         "    }\n"
         "}";
-    string exp_rsp = "Host found.";
-
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-
-    // Now check that the host parameters were indeed returned.
-    ASSERT_TRUE(rsp);
-    ConstElementPtr host = rsp->get("arguments");
-    ASSERT_TRUE(host);
-    EXPECT_TRUE(host->get("boot-file-name"));
-    EXPECT_TRUE(host->get("ip-address"));
-    EXPECT_TRUE(host->get("hw-address"));
-    EXPECT_TRUE(host->get("hostname"));
-    EXPECT_TRUE(host->get("next-server"));
-    EXPECT_TRUE(host->get("option-data"));
-    EXPECT_TRUE(host->get("server-hostname"));
-
-    // Check that there are no v6 specific fields
-    EXPECT_FALSE(host->get("ip-addresses"));
-    EXPECT_FALSE(host->get("prefixes"));
+    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 reservation-get(subnet-id, addr) can handle a situation when
-// the query is correctly formed, but the host is not there.
-TEST_F(LeaseCmdsTest, ReservationGetByAddr6NotFound) {
-    // Now send the command.
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-get\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"ip-address\": \"2001:db8::1\"\n"
-        "    }\n"
-        "}";
-    string exp_rsp = "Host not found.";
+// Checks that lease4-get can handle a situation when the query is
+// valid, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease4GetByAddrNotFound) {
 
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-}
+    // Initialize lease manager (false = v4, true = add lease)
+    initLeaseMgr(false, true);
 
-// Checks that reservation-get(subnet-id, addr) can handle a situation when
-// the query is correctly formed, but the host is not there.
-TEST_F(LeaseCmdsTest, ReservationGetByIdentifierNotFound) {
-    // Now send the command.
+    // Invalid
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"identifier-type\": \"hw-address\","
-        "        \"identifier\": \"00:01:02:03:04:05\"\n"
+        "        \"ip-address\": \"192.0.2.5\","
+        "        \"subnet-id\": 44"
         "    }\n"
         "}";
-    string exp_rsp = "Host not found.";
-
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+    string exp_rsp = "Lease not found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
 }
 
-// Checks that reservation-get(subnet-id, identifier-type, identifier) can handle
-// a situation when the query returns a host.
-TEST_F(LeaseCmdsTest, ReservationGetByIdentifier4) {
-    CfgMgr::instance().setFamily(AF_INET);
+// Checks that lease4-get can return a lease by address.
+TEST_F(LeaseCmdsTest, Lease4GetByAddr) {
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(true, false); // insert v4 host
+    // Initialize lease manager (false = v4, true = add lease)
+    initLeaseMgr(false, true);
 
-    // Now send the command.
+    // Query for valid, existing lease.
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 4,\n"
-        "        \"identifier-type\": \"hw-address\","
-        "        \"identifier\": \"01:02:03:04:05:06\"\n"
+        "        \"ip-address\": \"192.0.2.1\","
+        "        \"subnet-id\": 44"
         "    }\n"
         "}";
-    string exp_rsp = "Host found.";
-
-    // Note the status expected is success. The host should be returned.
+    string exp_rsp = "IPv4 lease found.";
     ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
 
-    // Now check that the host parameters were indeed returned.
+    // Now check that the lease parameters were indeed returned.
     ASSERT_TRUE(rsp);
-    ConstElementPtr host = rsp->get("arguments");
-    ASSERT_TRUE(host);
-    EXPECT_TRUE(host->get("boot-file-name"));
-    EXPECT_TRUE(host->get("ip-address"));
-    EXPECT_TRUE(host->get("hw-address"));
-    EXPECT_TRUE(host->get("hostname"));
-    EXPECT_TRUE(host->get("next-server"));
-    EXPECT_TRUE(host->get("option-data"));
-    EXPECT_TRUE(host->get("server-hostname"));
-
-    // Check that there are no v6 specific fields
-    EXPECT_FALSE(host->get("ip-addresses"));
-    EXPECT_FALSE(host->get("prefixes"));
-}
-
-// Checks that reservation-get(subnet-id, addr4) can handle a situation when
-// the query is correctly formed and the host is returned.
-TEST_F(LeaseCmdsTest, ReservationGetByAddr6) {
-
-    CfgMgr::instance().setFamily(AF_INET6);
+    ConstElementPtr lease = rsp->get("arguments");
+    ASSERT_TRUE(lease);
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(false, true); // insert v6 host
-
-    // Now send the command.
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-get\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 6,\n"
-        "        \"ip-address\": \"2001:db8::cafe:babe\""
-        "    }\n"
-        "}";
-    string exp_rsp = "Host found.";
-
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-    checkResponseHost6(rsp);
+    // Let's check if the response makes any sense.
+    checkLease4(lease, "192.0.2.1", 44, "08:08:08:08:08:08", false);
 }
 
-// Checks that reservation-get(subnet-id, identifier-type, identifier) can handle
-// a situation when the query returns a host.
-TEST_F(LeaseCmdsTest, ReservationGetByIdentifier6) {
-    CfgMgr::instance().setFamily(AF_INET6);
+// Checks that lease4-get can handle a situation when the query is
+// well formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease4GetByHWAddrNotFound) {
 
-    // Now send the command.
+    // Initialize lease manager (false = v4, false = don't add a lease)
+    initLeaseMgr(false, false);
+
+    // No such lease.
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-get\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 6,\n"
         "        \"identifier-type\": \"hw-address\","
-        "        \"identifier\": \"01:02:03:04:05:06\"\n"
+        "        \"identifier\": \"01:02:03:04:05:06\","
+        "        \"subnet-id\": 44"
         "    }\n"
         "}";
-    string exp_rsp = "Host found.";
-
-    // Note the status expected is success. The host should be returned.
-    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-
-    // Now check that the host parameters were indeed returned.
-    checkResponseHost6(rsp);
+    string exp_rsp = "Lease not found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp);
 }
 
-// reservation-del
-
-// Checks that reservation-del can handle a situation when the query is
-// broken (no parameters at all).
-TEST_F(LeaseCmdsTest, ReservationDelNoParams) {
-    // Now send the command.
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-del\",\n"
-        "    \"arguments\": {"
-        "    }\n"
-        "}";
-    string exp_rsp = "Mandatory 'subnet-id' parameter missing.";
+// Checks that lease4-get can find a lease by hardware address.
+TEST_F(LeaseCmdsTest, Lease4GetByHWAddr) {
 
-    // This should be rejected, because subnet-id parameter is mandatory.
-    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
-}
+    // Initialize lease manager (false = v4, true = add lease)
+    initLeaseMgr(false, true);
 
-// Checks that reservation-del can handle a situation when the query is
-// broken (just subnet-id).
-TEST_F(LeaseCmdsTest, ReservationDelNoAddress) {
+    // Invalid
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-del\",\n"
+        "    \"command\": \"lease4-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1\n"
+        "        \"identifier-type\": \"hw-address\","
+        "        \"identifier\": \"08:08:08:08:08:08\","
+        "        \"subnet-id\": 44"
         "    }\n"
         "}";
+    string exp_rsp = "IPv4 lease found.";
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
 
-    string rsp = "No 'ip-address' provided and 'identifier-type' is either "
-                 "missing or not a string.";
-
-    // Providing just subnet-id is not enough, the code needs either
-    // (subnet-id, addr) or (subnet-id, identifier-type, identifier)
-    testCommand(cmd, CONTROL_RESULT_ERROR, rsp);
-}
-
-// Checks that reservation-del can handle a situation when the query is
-// broken (subnet-id, identifier-type specified, identifier missing).
-TEST_F(LeaseCmdsTest, ReservationDelIdentifier) {
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-del\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"identifier-type\": \"hw-address\""
-        "    }\n"
-        "}";
-    string rsp = "No 'ip-address' provided and 'identifier' is either missing "
-                 "or not a string.";
+    // Now check that the lease parameters were indeed returned.
+    ASSERT_TRUE(rsp);
+    ConstElementPtr lease = rsp->get("arguments");
+    ASSERT_TRUE(lease);
 
-    // It's better (one parameter missing), but we still not there yet.
-    testCommand(cmd, CONTROL_RESULT_ERROR, rsp);
+    // Let's check if the response makes any sense.
+    checkLease4(lease, "192.0.2.1", 44, "08:08:08:08:08:08", false);
 }
 
-// Checks that reservation-del can handle a situation when the query is
-// broken (subnet-id, identifier specified, identifier-type missing).
-TEST_F(LeaseCmdsTest, ReservationDelNoIdentifierType) {
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-del\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"identifier\": \"00:11:22:33:44:55\""
-        "    }\n"
-        "}";
-    string rsp = "No 'ip-address' provided and 'identifier-type' is either missing "
-                 "or not a string.";
+// Checks that lease6-get(addr) can handle a situation when
+// the query is correctly formed, but the lease is not there.
+TEST_F(LeaseCmdsTest, Lease6GetByAddr6NotFound) {
 
-    testCommand(cmd, CONTROL_RESULT_ERROR, rsp);
-}
+    // Initialize lease manager (true = v6, true = add lease)
+    initLeaseMgr(true, true);
 
-// Checks that properly formed reservation-del(subnet-id, addr) will not work if
-// there is no hosts-database configured.
-TEST_F(LeaseCmdsTest, ReservationDelNoHostsDatabase) {
     // Now send the command.
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-del\",\n"
+        "    \"command\": \"lease6-get\",\n"
         "    \"arguments\": {"
         "        \"subnet-id\": 1,\n"
-        "        \"ip-address\": \"192.0.2.202\"\n"
+        "        \"ip-address\": \"2001:db8::2\"\n"
         "    }\n"
         "}";
-    string exp_rsp = "Unable to delete a host because there is no "
-                     "hosts-database configured.";
+    string exp_rsp = "Lease not found.";
 
-    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+    // 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 reservation-del(subnet-id, addr) can handle a situation when
-// the query is correctly formed, but the host is not there.
-TEST_F(LeaseCmdsTest, ReservationDelByAddr4NotFound) {
-
-    initLeaseMgr(false, false);
+// 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)
+    initLeaseMgr(true, true);
 
     // Now send the command.
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-del\",\n"
+        "    \"command\": \"lease6-get\",\n"
         "    \"arguments\": {"
         "        \"subnet-id\": 1,\n"
-        "        \"ip-address\": \"192.0.2.202\"\n"
+        "        \"identifier-type\": \"duid\","
+        "        \"identifier\": \"00:01:02:03:04:05:06:07\"\n"
         "    }\n"
         "}";
-    string exp_rsp = "Host not deleted (not found).";
+    string exp_rsp = "Lease not found.";
 
-    // Note the status expected is failure, because the host was not found.
-    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+    // 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 reservation-del(subnet-id, addr4) can handle a situation when
-// the query is correctly formed and the host is deleted.
-TEST_F(LeaseCmdsTest, ReservationDelByAddr4) {
+// Checks that lease6-get(subnet-id, addr6) can handle a situation when
+// the query is correctly formed and the lease is returned.
+TEST_F(LeaseCmdsTest, Lease6GetByAddr) {
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(true, false); // insert v4 host
+    initLeaseMgr(true, true); // (true = v6, true = create a lease)
 
     // Now send the command.
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-del\",\n"
+        "    \"command\": \"lease6-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 4,\n"
-        "        \"ip-address\": \"192.0.2.100\"\n"
+        "        \"subnet-id\": 66,\n"
+        "        \"ip-address\": \"2001:db8::1\""
         "    }\n"
         "}";
-    string exp_rsp = "Host deleted.";
+    string exp_rsp = "IPv6 lease found.";
 
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-}
-
-// Checks that reservation-del(subnet-id, addr) can handle a situation when
-// the query is correctly formed, but the host is not there.
-TEST_F(LeaseCmdsTest, ReservationDelByAddr6NotFound) {
-
-    // First, let's create a dummy host data source.
-    initLeaseMgr(false, false); // Don't insert any hosts.
+    // The status expected is success. The lease should be returned.
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+    ASSERT_TRUE(rsp);
 
-    // Now send the command.
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-del\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"ip-address\": \"2001:db8::1\"\n"
-        "    }\n"
-        "}";
-    string exp_rsp = "Host not deleted (not found).";
+    ConstElementPtr lease = rsp->get("arguments");
+    ASSERT_TRUE(lease);
 
-    // Note the status expected is failure, because the host was not found.
-    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
+    // Now check that the lease was indeed returned.
+    checkLease6(lease, "2001:db8::1", 0, 66, "77:77:77:77:77:77:77:77", false);
 }
 
-// Checks that reservation-del(subnet-id, addr) can handle a situation when
-// the query is correctly formed, but the host is not there.
-TEST_F(LeaseCmdsTest, ReservationDelByIdentifierNotFound) {
+// Checks that lease6-get(subnet-id, type, addr6) can handle a situation when
+// the query is correctly formed and the lease is returned.
+TEST_F(LeaseCmdsTest, Lease6GetByAddrPrefix) {
+
+    // We need to get a prefix lease. We need to create it by hand.
+    initLeaseMgr(true, false); // (true = v6, true = create a lease)
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(false, false); // Don't insert any hosts.
+    // 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\": \"reservation-del\",\n"
+        "    \"command\": \"lease6-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 1,\n"
-        "        \"identifier-type\": \"hw-address\","
-        "        \"identifier\": \"00:01:02:03:04:05\"\n"
+        "        \"type\": \"IA_PD\","
+        "        \"ip-address\": \"2001:db8:1234:ab::\""
         "    }\n"
         "}";
-    string exp_rsp = "Host not deleted (not found).";
+    string exp_rsp = "IPv6 lease found.";
 
-    // Note the status expected is failure, because the host was not found.
-    testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp);
-}
-
-// Checks that reservation-del(subnet-id, identifier-type, identifier) can handle
-// a situation when the v4 host is deleted.
-TEST_F(LeaseCmdsTest, ReservationDelByIdentifier4) {
-    CfgMgr::instance().setFamily(AF_INET);
+    // The status expected is success. The lease should be returned.
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+    ASSERT_TRUE(rsp);
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(true, false); // insert v4 host
+    ConstElementPtr lease = rsp->get("arguments");
+    ASSERT_TRUE(lease);
 
-    // Now send the command.
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-del\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 4,\n"
-        "        \"identifier-type\": \"hw-address\","
-        "        \"identifier\": \"01:02:03:04:05:06\"\n"
-        "    }\n"
-        "}";
-    string exp_rsp = "Host deleted.";
-
-    // Note the status expected is success. The host should be returned.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+    // Now check that the lease was indeed returned.
+    checkLease6(lease, "2001:db8:1234:ab::", 56, 66, "77:77:77:77:77:77:77:77", false);
 }
 
-// Checks that reservation-del(subnet-id, addr4) can handle a situation when
-// the query is correctly formed and the host is deleted.
-TEST_F(LeaseCmdsTest, ReservationDelByAddr6) {
-
-    CfgMgr::instance().setFamily(AF_INET6);
+// Checks that lease6-get(subnet-id, iaid, identifier-type, identifier) can handle
+// a situation when the query returns a lease.
+TEST_F(LeaseCmdsTest, Lease6GetByDUID) {
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(false, true); // insert v6 host
+    initLeaseMgr(true, true); // (true = v6, true = create a lease)
 
     // Now send the command.
     string cmd =
         "{\n"
-        "    \"command\": \"reservation-del\",\n"
+        "    \"command\": \"lease6-get\",\n"
         "    \"arguments\": {"
-        "        \"subnet-id\": 6,\n"
-        "        \"ip-address\": \"2001:db8::cafe:babe\""
+        "        \"subnet-id\": 66,\n"
+        "        \"iaid\": 42,"
+        "        \"identifier-type\": \"duid\","
+        "        \"identifier\": \"77:77:77:77:77:77:77:77\"\n"
         "    }\n"
         "}";
-    string exp_rsp = "Host deleted.";
-
-    // Note the status expected is success, because the query was well formed
-    // and the DB search actually completed. It just didn't found the host.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
-}
-
-// Checks that reservation-del(subnet-id, identifier-type, identifier) can handle
-// a situation when the v6 host is actually deleted.
-TEST_F(LeaseCmdsTest, ReservationDelByIdentifier6) {
-    CfgMgr::instance().setFamily(AF_INET6);
+    string exp_rsp = "IPv6 lease found.";
 
-    // First, let's create a dummy host data source.
-    initLeaseMgr(false, true); // insert v6 host
+    // The status expected is success. The lease should be returned.
+    ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+    ASSERT_TRUE(rsp);
 
-    // Now send the command.
-    string cmd =
-        "{\n"
-        "    \"command\": \"reservation-del\",\n"
-        "    \"arguments\": {"
-        "        \"subnet-id\": 6,\n"
-        "        \"identifier-type\": \"hw-address\","
-        "        \"identifier\": \"01:02:03:04:05:06\"\n"
-        "    }\n"
-        "}";
-    string exp_rsp = "Host deleted.";
+    ConstElementPtr lease = rsp->get("arguments");
+    ASSERT_TRUE(lease);
 
-    // Note the status expected is success. The host should be returned.
-    testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp);
+    // Now check that the lease was indeed returned.
+    checkLease6(lease, "2001:db8::1", 0, 66, "77:77:77:77:77:77:77:77", false);
 }
 
 } // end of anonymous namespace
index 0ca12d0d4d185d0a924a3a10057055027e3155c2..1aa6e28b70e8191f188471a4f8104015e0e0ac67 100644 (file)
@@ -393,7 +393,9 @@ Lease6::toElement() const {
     ElementPtr map = Element::createMap();
     map->set("ip-address", Element::create(addr_.toText()));
     map->set("type", Element::create(typeToText(type_)));
-    map->set("prefix-len", Element::create(prefixlen_));
+    if (type_ == Lease::TYPE_PD) {
+        map->set("prefix-len", Element::create(prefixlen_));
+    }
     map->set("iaid", Element::create(static_cast<long int>(iaid_)));
     map->set("duid", Element::create(duid_->toText()));
     map->set("subnet-id", Element::create(static_cast<long int>(subnet_id_)));
index 6aaad6a792452faba0c989862b701c4f89345c37..2c4ab09371fde2f88ed2141780843b6b3d20bcb1 100644 (file)
@@ -901,7 +901,8 @@ TEST(Lease6Test, toText) {
 }
 
 // Verify that Lease6 structure can be converted to JSON properly.
-TEST(Lease6Test, toElement) {
+// This tests an address lease conversion.
+TEST(Lease6Test, toElementAddress) {
 
     HWAddrPtr hwaddr(new HWAddr(HWADDR, sizeof(HWADDR), HTYPE_ETHER));
 
@@ -924,8 +925,8 @@ TEST(Lease6Test, toElement) {
     ASSERT_TRUE(l->contains("type"));
     EXPECT_EQ("IA_NA", l->get("type")->stringValue());
 
-    ASSERT_TRUE(l->contains("prefix-len"));
-    EXPECT_EQ(128, l->get("prefix-len")->intValue());
+    // This is an address lease, it does not have a prefix length.
+    ASSERT_FALSE(l->contains("prefix-len"));
 
     ASSERT_TRUE(l->contains("iaid"));
     EXPECT_EQ(123456, l->get("iaid")->intValue());
@@ -965,6 +966,73 @@ TEST(Lease6Test, toElement) {
     EXPECT_FALSE(l->contains("hw-address"));
 }
 
+// Verify that Lease6 structure can be converted to JSON properly.
+// This tests an address lease conversion.
+TEST(Lease6Test, toElementPrefix) {
+
+    HWAddrPtr hwaddr(new HWAddr(HWADDR, sizeof(HWADDR), HTYPE_ETHER));
+
+    uint8_t llt[] = {0, 1, 2, 3, 4, 5, 6, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+    DuidPtr duid(new DUID(llt, sizeof(llt)));
+
+    Lease6 lease(Lease::TYPE_PD, IOAddress("2001:db8::"), duid, 123456,
+                 400, 800, 100, 200, 5678, hwaddr, 56);
+    lease.cltt_ = 12345678;
+    lease.state_ = Lease::STATE_DEFAULT;
+    lease.hostname_ = "urania.example.org";
+
+    ElementPtr l = lease.toElement();
+
+    ASSERT_TRUE(l);
+
+    ASSERT_TRUE(l->contains("ip-address"));
+    EXPECT_EQ("2001:db8::", l->get("ip-address")->stringValue());
+
+    ASSERT_TRUE(l->contains("type"));
+    EXPECT_EQ("IA_PD", l->get("type")->stringValue());
+
+    // This is a prefix lease, it must have a prefix length.
+    ASSERT_TRUE(l->contains("prefix-len"));
+    EXPECT_EQ(56, l->get("prefix-len")->intValue());
+
+    ASSERT_TRUE(l->contains("iaid"));
+    EXPECT_EQ(123456, l->get("iaid")->intValue());
+
+    ASSERT_TRUE(l->contains("preferred-lft"));
+    EXPECT_EQ(400, l->get("preferred-lft")->intValue());
+
+    ASSERT_TRUE(l->contains("valid-lft"));
+    EXPECT_EQ(800, l->get("valid-lft")->intValue());
+
+    ASSERT_TRUE(l->contains("duid"));
+    EXPECT_EQ("00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f",
+              l->get("duid")->stringValue());
+
+    ASSERT_TRUE(l->contains("hw-address"));
+    EXPECT_EQ(hwaddr->toText(false), l->get("hw-address")->stringValue());
+
+    ASSERT_TRUE(l->contains("subnet-id"));
+    EXPECT_EQ(5678, l->get("subnet-id")->intValue());
+
+    ASSERT_TRUE(l->contains("state"));
+    EXPECT_EQ(static_cast<int>(Lease::STATE_DEFAULT),
+              l->get("state")->intValue());
+
+    ASSERT_TRUE(l->contains("fqdn-fwd"));
+    EXPECT_FALSE(l->get("fqdn-fwd")->boolValue());
+
+    ASSERT_TRUE(l->contains("fqdn-rev"));
+    EXPECT_FALSE(l->get("fqdn-rev")->boolValue());
+
+    ASSERT_TRUE(l->contains("hostname"));
+    EXPECT_EQ("urania.example.org", l->get("hostname")->stringValue());
+
+    // Now let's try with a lease without hardware address.
+    lease.hwaddr_.reset();
+    l = lease.toElement();
+    EXPECT_FALSE(l->contains("hw-address"));
+}
+
 // Verify that the lease states are correctly returned in the textual format.
 TEST(Lease6Test, stateToText) {
     EXPECT_EQ("default", Lease6::statesToText(Lease::STATE_DEFAULT));