]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
enabled more tests, implemented hwaddr, hwtype and hwaddr_source in pgsql
authorRazvan Becheriu <razvan.becheriu@qualitance.com>
Mon, 19 Feb 2018 14:14:38 +0000 (16:14 +0200)
committerRazvan Becheriu <razvan.becheriu@qualitance.com>
Mon, 19 Feb 2018 14:14:38 +0000 (16:14 +0200)
src/lib/dhcpsrv/cfg_option.cc
src/lib/dhcpsrv/mysql_lease_mgr.cc
src/lib/dhcpsrv/mysql_lease_mgr.h
src/lib/dhcpsrv/pgsql_lease_mgr.cc
src/lib/dhcpsrv/pgsql_lease_mgr.h
src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc
src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc
src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc

index 83fc8589a75e21ce114da01b2673207151cd88c9..05c489b6032b182c30a4b6a217387e6ed250fb08 100644 (file)
@@ -171,7 +171,7 @@ CfgOption::mergeInternal(const OptionSpaceContainer<OptionContainer,
             // If there is no such option in the destination container,
             // add one.
             if (std::distance(range.first, range.second) == 0) {
-                dest_container.addItem(OptionDescriptor(src_opt), *it);
+                dest_container.addItem(OptionDescriptor(*src_opt), *it);
             }
         }
     }
index b32d0b7130ec1d00386ffd355e1cd9c26ed0c95a..049da7604314fba021725bc8a84bf44a407966ec 100644 (file)
@@ -197,7 +197,8 @@ tagged_statements = { {
     {MySqlLeaseMgr::INSERT_LEASE4,
                     "INSERT INTO lease4(address, hwaddr, client_id, "
                         "valid_lifetime, expire, subnet_id, "
-                        "fqdn_fwd, fqdn_rev, hostname, state) "
+                        "fqdn_fwd, fqdn_rev, hostname, "
+                        "state) "
                             "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::INSERT_LEASE6,
                     "INSERT INTO lease6(address, duid, valid_lifetime, "
@@ -211,7 +212,8 @@ tagged_statements = { {
                     "UPDATE lease4 SET address = ?, hwaddr = ?, "
                         "client_id = ?, valid_lifetime = ?, expire = ?, "
                         "subnet_id = ?, fqdn_fwd = ?, fqdn_rev = ?, "
-                        "hostname = ?, state = ? "
+                        "hostname = ?, "
+                        "state = ? "
                             "WHERE address = ?"},
     {MySqlLeaseMgr::UPDATE_LEASE6,
                     "UPDATE lease6 SET address = ?, duid = ?, "
@@ -231,7 +233,7 @@ tagged_statements = { {
     }
 };
 
-};
+}  // namespace
 
 namespace isc {
 namespace dhcp {
@@ -299,7 +301,6 @@ public:
     }
 };
 
-
 /// @brief Exchange MySQL and Lease4 Data
 ///
 /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
@@ -322,8 +323,8 @@ public:
     ///
     /// The initialization of the variables here is only to satisfy cppcheck -
     /// all variables are initialized/set in the methods before they are used.
-    MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), client_id_length_(0),
-                            client_id_null_(MLM_FALSE),
+    MySqlLease4Exchange() : addr4_(0), hwaddr_length_(0), hwaddr_null_(MLM_FALSE),
+                            client_id_length_(0), client_id_null_(MLM_FALSE),
                             subnet_id_(0), valid_lifetime_(0),
                             fqdn_fwd_(false), fqdn_rev_(false), hostname_length_(0),
                             state_(0) {
@@ -371,7 +372,7 @@ public:
         // structure.
 
         try {
-            // Address: uint32_t
+            // address: uint32_t
             // The address in the Lease structure is an IOAddress object.  Convert
             // this to an integer for storage.
             addr4_ = lease_->addr_.toUint32();
@@ -381,16 +382,26 @@ public:
             // bind_[0].is_null = &MLM_FALSE; // commented out for performance
                                               // reasons, see memset() above
 
-            // hwaddr: varbinary(128)
-            // For speed, we avoid copying the data into temporary storage and
-            // instead extract it from the lease structure directly.
-            hwaddr_length_ = lease_->hwaddr_->hwaddr_.size();
-            bind_[1].buffer_type = MYSQL_TYPE_BLOB;
-            bind_[1].buffer = reinterpret_cast<char*>(&(lease_->hwaddr_->hwaddr_[0]));
-            bind_[1].buffer_length = hwaddr_length_;
-            bind_[1].length = &hwaddr_length_;
-            // bind_[1].is_null = &MLM_FALSE; // commented out for performance
-                                              // reasons, see memset() above
+            // hwaddr: varbinary(20) - hardware/MAC address
+            HWAddrPtr hwaddr = lease_->hwaddr_;
+            if (hwaddr) {
+                hwaddr_ = hwaddr->hwaddr_;
+                hwaddr_length_ = hwaddr->hwaddr_.size();
+                bind_[1].buffer_type = MYSQL_TYPE_BLOB;
+                bind_[1].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
+                bind_[1].buffer_length = hwaddr_length_;
+                bind_[1].length = &hwaddr_length_;
+            } else {
+                bind_[1].buffer_type = MYSQL_TYPE_NULL;
+                // According to http://dev.mysql.com/doc/refman/5.5/en/
+                // c-api-prepared-statement-data-structures.html, the other
+                // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
+                // but let's set them to some sane values in case earlier versions
+                // didn't have that assumption.
+                hwaddr_null_ = MLM_TRUE;
+                bind_[1].buffer = NULL;
+                bind_[1].is_null = &hwaddr_null_;
+            }
 
             // client_id: varbinary(128)
             if (lease_->client_id_) {
@@ -404,7 +415,6 @@ public:
                                                  // reasons, see memset() above
             } else {
                 bind_[2].buffer_type = MYSQL_TYPE_NULL;
-
                 // According to http://dev.mysql.com/doc/refman/5.5/en/
                 // c-api-prepared-statement-data-structures.html, the other
                 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
@@ -504,7 +514,7 @@ public:
         // code that explicitly sets is_null is there, but is commented out.
         memset(bind_, 0, sizeof(bind_));
 
-        // address:  uint32_t
+        // address: uint32_t
         bind_[0].buffer_type = MYSQL_TYPE_LONG;
         bind_[0].buffer = reinterpret_cast<char*>(&addr4_);
         bind_[0].is_unsigned = MLM_TRUE;
@@ -650,36 +660,29 @@ private:
     // Note: All array lengths are equal to the corresponding variable in the
     //       schema.
     // Note: Arrays are declared fixed length for speed of creation
-    uint32_t        addr4_;             ///< IPv4 address
-    MYSQL_BIND      bind_[LEASE_COLUMNS]; ///< Bind array
-    std::string     columns_[LEASE_COLUMNS]; ///< Column names
-    my_bool         error_[LEASE_COLUMNS]; ///< Error array
-    std::vector<uint8_t> hwaddr_;       ///< Hardware address
-    uint8_t         hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
-                                        ///< Hardware address buffer
-    unsigned long   hwaddr_length_;     ///< Hardware address length
-    std::vector<uint8_t> client_id_;    ///< Client identification
-    uint8_t         client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
-                                        ///< Client ID buffer
-    unsigned long   client_id_length_;  ///< Client ID address length
-    my_bool         client_id_null_;    ///< Is Client ID null?
-
-    MYSQL_TIME      expire_;            ///< Lease expiry time
-    Lease4Ptr       lease_;             ///< Pointer to lease object
-    uint32_t        subnet_id_;         ///< Subnet identification
-    uint32_t        valid_lifetime_;    ///< Lease time
-
-    my_bool         fqdn_fwd_;          ///< Has forward DNS update been
-                                        ///< performed
-    my_bool         fqdn_rev_;          ///< Has reverse DNS update been
-                                        ///< performed
-    char            hostname_buffer_[HOSTNAME_MAX_LEN];
-                                        ///< Client hostname
-    unsigned long   hostname_length_;   ///< Client hostname length
-    uint32_t        state_;             ///< Lease state
+    uint32_t               addr4_;                     ///< IPv4 address
+    MYSQL_BIND             bind_[LEASE_COLUMNS];       ///< Bind array
+    std::string            columns_[LEASE_COLUMNS];    ///< Column names
+    my_bool                error_[LEASE_COLUMNS];      ///< Error array
+    std::vector<uint8_t>   hwaddr_;                    ///< Hardware address
+    uint8_t                hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Hardware address buffer
+    unsigned long          hwaddr_length_;             ///< Hardware address length
+    my_bool                hwaddr_null_;               ///< Used when HWAddr is null
+    std::vector<uint8_t>   client_id_;                 ///< Client identification
+    uint8_t                client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN]; ///< Client ID buffer
+    unsigned long          client_id_length_;          ///< Client ID address length
+    my_bool                client_id_null_;            ///< Is Client ID null?
+    MYSQL_TIME             expire_;                    ///< Lease expiry time
+    Lease4Ptr              lease_;                     ///< Pointer to lease object
+    uint32_t               subnet_id_;                 ///< Subnet identification
+    uint32_t               valid_lifetime_;            ///< Lease time
+    my_bool                fqdn_fwd_;                  ///< Has forward DNS update been performed
+    my_bool                fqdn_rev_;                  ///< Has reverse DNS update been performed
+    char                   hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname
+    unsigned long          hostname_length_;           ///< Client hostname length
+    uint32_t               state_;                     ///< Lease state
 };
 
-
 /// @brief Exchange MySQL and Lease6 Data
 ///
 /// On any MySQL operation, arrays of MYSQL_BIND structures must be built to
@@ -809,7 +812,6 @@ public:
             /// expiry time (expire).  The relationship is given by:
             //
             // expire = cltt_ + valid_lft_
-            //
             MySqlConnection::convertToDatabaseTime(lease_->cltt_, lease_->valid_lft_,
                                                    expire_);
             bind_[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
@@ -885,14 +887,12 @@ public:
             if (hwaddr) {
                 hwaddr_ = hwaddr->hwaddr_;
                 hwaddr_length_ = hwaddr->hwaddr_.size();
-
                 bind_[12].buffer_type = MYSQL_TYPE_BLOB;
                 bind_[12].buffer = reinterpret_cast<char*>(&(hwaddr_[0]));
                 bind_[12].buffer_length = hwaddr_length_;
                 bind_[12].length = &hwaddr_length_;
             } else {
                 bind_[12].buffer_type = MYSQL_TYPE_NULL;
-
                 // According to http://dev.mysql.com/doc/refman/5.5/en/
                 // c-api-prepared-statement-data-structures.html, the other
                 // fields doesn't matter if type is set to MYSQL_TYPE_NULL,
@@ -930,7 +930,6 @@ public:
                 bind_[14].is_unsigned = MLM_TRUE;
             } else {
                 hwaddr_source_ = 0;
-
                 bind_[14].buffer_type = MYSQL_TYPE_NULL;
                 // According to http://dev.mysql.com/doc/refman/5.5/en/
                 // c-api-prepared-statement-data-structures.html, the other
@@ -953,7 +952,7 @@ public:
             setErrorIndicators(bind_, error_, LEASE_COLUMNS);
 
             // .. and check that we have the numbers correct at compile time.
-            BOOST_STATIC_ASSERT(14 < LEASE_COLUMNS);
+            BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
 
         } catch (const std::exception& ex) {
             isc_throw(DbOperationError,
@@ -1076,7 +1075,6 @@ public:
         // bind_[11].is_null = &MLM_FALSE; // commented out for performance
                                            // reasons, see memset() above
 
-        // hardware address
         // hwaddr: varbinary(20)
         hwaddr_null_ = MLM_FALSE;
         hwaddr_length_ = sizeof(hwaddr_buffer_);
@@ -1204,39 +1202,35 @@ private:
     // Note: All array lengths are equal to the corresponding variable in the
     // schema.
     // Note: arrays are declared fixed length for speed of creation
-    std::string     addr6_;             ///< String form of address
-    char            addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
-                                        ///< array form of V6 address
-    unsigned long   addr6_length_;      ///< Length of the address
-    MYSQL_BIND      bind_[LEASE_COLUMNS]; ///< Bind array
-    std::string     columns_[LEASE_COLUMNS]; ///< Column names
-    std::vector<uint8_t> duid_;         ///< Client identification
-    uint8_t         duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
-    unsigned long   duid_length_;       ///< Length of the DUID
-    my_bool         error_[LEASE_COLUMNS]; ///< Error indicators
-    MYSQL_TIME      expire_;            ///< Lease expiry time
-    uint32_t        iaid_;              ///< Identity association ID
-    Lease6Ptr       lease_;             ///< Pointer to lease object
-    uint8_t         lease_type_;        ///< Lease type
-    uint8_t         prefixlen_;         ///< Prefix length
-    uint32_t        pref_lifetime_;     ///< Preferred lifetime
-    uint32_t        subnet_id_;         ///< Subnet identification
-    uint32_t        valid_lifetime_;    ///< Lease time
-    my_bool         fqdn_fwd_;          ///< Has forward DNS update been
-                                        ///< performed
-    my_bool         fqdn_rev_;          ///< Has reverse DNS update been
-                                        ///< performed
-    char            hostname_buffer_[HOSTNAME_MAX_LEN];
-                                        ///< Client hostname
-    unsigned long   hostname_length_;   ///< Client hostname length
-    uint8_t         hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
-                                        ///< Buffer for Hardware address
-    std::vector<uint8_t> hwaddr_;       ///< Hardware address (optional)
-    unsigned long   hwaddr_length_;     ///< Aux. variable denoting hwaddr_ size()
-    my_bool         hwaddr_null_;       ///< Used when HWAddr is null
-    uint16_t        hwtype_;            ///< Hardware type
-    uint32_t        hwaddr_source_;     ///< Source of the hardware address
-    uint32_t        state_;             ///< Lease state.
+    std::string            addr6_;                     ///< String form of address
+    char                   addr6_buffer_[ADDRESS6_TEXT_MAX_LEN + 1]; ///< Character
+                                                       ///< array form of V6 address
+    unsigned long          addr6_length_;              ///< Length of the address
+    MYSQL_BIND             bind_[LEASE_COLUMNS];       ///< Bind array
+    std::string            columns_[LEASE_COLUMNS];    ///< Column names
+    std::vector<uint8_t>   duid_;                      ///< Client identification
+    uint8_t                duid_buffer_[DUID::MAX_DUID_LEN]; ///< Buffer form of DUID
+    unsigned long          duid_length_;               ///< Length of the DUID
+    my_bool                error_[LEASE_COLUMNS];      ///< Error indicators
+    MYSQL_TIME             expire_;                    ///< Lease expiry time
+    uint32_t               iaid_;                      ///< Identity association ID
+    Lease6Ptr              lease_;                     ///< Pointer to lease object
+    uint8_t                lease_type_;                ///< Lease type
+    uint8_t                prefixlen_;                 ///< Prefix length
+    uint32_t               pref_lifetime_;             ///< Preferred lifetime
+    uint32_t               subnet_id_;                 ///< Subnet identification
+    uint32_t               valid_lifetime_;            ///< Lease time
+    my_bool                fqdn_fwd_;                  ///< Has forward DNS update been performed
+    my_bool                fqdn_rev_;                  ///< Has reverse DNS update been performed
+    char                   hostname_buffer_[HOSTNAME_MAX_LEN]; ///< Client hostname
+    unsigned long          hostname_length_;           ///< Client hostname length
+    uint8_t                hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; ///< Buffer form of Hardware address
+    std::vector<uint8_t>   hwaddr_;                    ///< Hardware address (optional)
+    unsigned long          hwaddr_length_;             ///< Aux. variable denoting hwaddr_ size()
+    my_bool                hwaddr_null_;               ///< Used when HWAddr is null
+    uint16_t               hwtype_;                    ///< Hardware type
+    uint32_t               hwaddr_source_;             ///< Source of the hardware address
+    uint32_t               state_;                     ///< Lease state.
 };
 
 /// @brief MySql derivation of the statistical lease data query
@@ -1291,7 +1285,7 @@ public:
 
         // Fetch the lease type if we were told to do so.
         if (fetch_type_) {
-            // lease type:  uint32_t
+            // lease type: uint32_t
             bind_[col].buffer_type = MYSQL_TYPE_LONG;
             bind_[col].buffer = reinterpret_cast<char*>(&lease_type_);
             bind_[col].is_unsigned = MLM_TRUE;
@@ -1300,7 +1294,7 @@ public:
             fetch_type_ = Lease::TYPE_NA;
         }
 
-        // state:  uint32_t
+        // state: uint32_t
         bind_[col].buffer_type = MYSQL_TYPE_LONG;
         bind_[col].buffer = reinterpret_cast<char*>(&lease_state_);
         bind_[col].is_unsigned = MLM_TRUE;
@@ -2255,5 +2249,5 @@ MySqlLeaseMgr::checkError(int status, StatementIndex index,
     conn_.checkError(status, index, what);
 }
 
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+}  // namespace dhcp
+}  // namespace isc
index 8d075a293885f87ed1b4b61b173343a95d735fc3..ac7fc7bcf83e087235ccc0d44c57296113d6159b 100644 (file)
@@ -672,7 +672,7 @@ private:
     MySqlConnection conn_;
 };
 
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+}  // namespace dhcp
+}  // namespace isc
 
 #endif // MYSQL_LEASE_MGR_H
index 8e208acc1d6c83fd895718c1310d571394047243..1ebd37edad4ccc6c2f9db6af26ab2f7088d6066a 100644 (file)
@@ -26,9 +26,6 @@ using namespace std;
 
 namespace {
 
-/// @todo TKM lease6 needs to accommodate hwaddr, hwtype, and hwaddr source
-/// columns.  This is covered by tickets #3557, #4530, and PR#9.
-
 /// @brief Catalog of all the SQL statements currently supported.  Note
 /// that the order columns appear in statement body must match the order they
 /// that the occur in the table.  This does not apply to the where clause.
@@ -60,7 +57,8 @@ PgSqlTaggedStatement tagged_statements[] = {
       "get_lease4",
       "SELECT address, hwaddr, client_id, "
         "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
-        "fqdn_fwd, fqdn_rev, hostname, state "
+        "fqdn_fwd, fqdn_rev, hostname, "
+        "state "
       "FROM lease4"},
 
     // GET_LEASE4_ADDR
@@ -118,7 +116,8 @@ PgSqlTaggedStatement tagged_statements[] = {
       "get_lease4_subid",
       "SELECT address, hwaddr, client_id, "
         "valid_lifetime, extract(epoch from expire)::bigint, subnet_id, "
-        "fqdn_fwd, fqdn_rev, hostname, state "
+        "fqdn_fwd, fqdn_rev, hostname, "
+      "state "
       "FROM lease4 "
       "WHERE subnet_id = $1"},
 
@@ -140,19 +139,21 @@ PgSqlTaggedStatement tagged_statements[] = {
       "SELECT address, duid, valid_lifetime, "
         "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
         "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
         "state "
       "FROM lease6 "
       "WHERE address = $1 AND lease_type = $2"},
 
     // GET_LEASE6_DUID_IAID
-    {  3, { OID_BYTEA, OID_INT8, OID_INT2 },
-       "get_lease6_duid_iaid",
-       "SELECT address, duid, valid_lifetime, "
-         "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
-         "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
-         "state "
-       "FROM lease6 "
-       "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
+    { 3, { OID_BYTEA, OID_INT8, OID_INT2 },
+      "get_lease6_duid_iaid",
+      "SELECT address, duid, valid_lifetime, "
+        "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
+        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
+        "state "
+      "FROM lease6 "
+      "WHERE duid = $1 AND iaid = $2 AND lease_type = $3"},
 
     // GET_LEASE6_DUID_IAID_SUBID
     { 4, { OID_INT2, OID_BYTEA, OID_INT8, OID_INT8 },
@@ -160,6 +161,7 @@ PgSqlTaggedStatement tagged_statements[] = {
       "SELECT address, duid, valid_lifetime, "
         "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
         "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
         "state "
       "FROM lease6 "
       "WHERE lease_type = $1 "
@@ -172,6 +174,7 @@ PgSqlTaggedStatement tagged_statements[] = {
         "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, "
         "lease_type, iaid, prefix_len, "
         "fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
         "state "
       "FROM lease6 "
       "WHERE state != $1 AND expire < $2 "
@@ -193,14 +196,16 @@ PgSqlTaggedStatement tagged_statements[] = {
       "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"},
 
     // INSERT_LEASE6
-    { 13, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
+    { 16, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
             OID_INT8, OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL,
-            OID_VARCHAR, OID_INT8 },
+            OID_VARCHAR, OID_BYTEA, OID_INT2, OID_INT2, OID_INT8 },
       "insert_lease6",
       "INSERT INTO lease6(address, duid, valid_lifetime, "
         "expire, subnet_id, pref_lifetime, "
-        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, state) "
-      "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)"},
+        "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, "
+        "hwaddr, hwtype, hwaddr_source, "
+        "state) "
+      "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)"},
 
     // UPDATE_LEASE4
     { 11, { OID_INT8, OID_BYTEA, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8,
@@ -209,20 +214,22 @@ PgSqlTaggedStatement tagged_statements[] = {
       "UPDATE lease4 SET address = $1, hwaddr = $2, "
         "client_id = $3, valid_lifetime = $4, expire = $5, "
         "subnet_id = $6, fqdn_fwd = $7, fqdn_rev = $8, hostname = $9, "
-        "state = $10"
+        "state = $10 "
       "WHERE address = $11"},
 
     // UPDATE_LEASE6
-    { 14, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
+    { 17, { OID_VARCHAR, OID_BYTEA, OID_INT8, OID_TIMESTAMP, OID_INT8, OID_INT8,
             OID_INT2, OID_INT8, OID_INT2, OID_BOOL, OID_BOOL, OID_VARCHAR,
+            OID_BYTEA, OID_INT2, OID_INT2,
             OID_INT8, OID_VARCHAR },
       "update_lease6",
       "UPDATE lease6 SET address = $1, duid = $2, "
         "valid_lifetime = $3, expire = $4, subnet_id = $5, "
         "pref_lifetime = $6, lease_type = $7, iaid = $8, "
         "prefix_len = $9, fqdn_fwd = $10, fqdn_rev = $11, hostname = $12, "
-        "state = $13 "
-      "WHERE address = $14"},
+        "hwaddr = $13, hwtype = $14, hwaddr_source = $15, "
+        "state = $16 "
+      "WHERE address = $17"},
 
     // RECOUNT_LEASE4_STATS,
     { 0, { OID_NONE },
@@ -241,7 +248,7 @@ PgSqlTaggedStatement tagged_statements[] = {
     { 0,  { 0 }, NULL, NULL}
 };
 
-};
+}  // namespace
 
 namespace isc {
 namespace dhcp {
@@ -254,7 +261,7 @@ namespace dhcp {
 class PgSqlLeaseExchange : public PgSqlExchange {
 public:
     PgSqlLeaseExchange()
-        : addr_str_(""), valid_lifetime_(0), valid_lft_str_(""),
+        : addr_str_(""), valid_lifetime_(0), valid_lifetime_str_(""),
           expire_(0), expire_str_(""), subnet_id_(0), subnet_id_str_(""),
           cltt_(0), fqdn_fwd_(false), fqdn_rev_(false), hostname_(""),
           state_str_("") {
@@ -265,20 +272,19 @@ public:
 protected:
     /// @brief Common Instance members used for binding and conversion
     //@{
-    std::string addr_str_;
-    uint32_t valid_lifetime_;
-    std::string valid_lft_str_;
-    time_t expire_;
-    std::string expire_str_;
-    uint32_t subnet_id_;
-    std::string subnet_id_str_;
-    time_t cltt_;
-    bool fqdn_fwd_;
-    bool fqdn_rev_;
-    std::string hostname_;
-    std::string state_str_;
+    std::string            addr_str_;
+    uint32_t               valid_lifetime_;
+    std::string            valid_lifetime_str_;
+    time_t                 expire_;
+    std::string            expire_str_;
+    uint32_t               subnet_id_;
+    std::string            subnet_id_str_;
+    time_t                 cltt_;
+    bool                   fqdn_fwd_;
+    bool                   fqdn_rev_;
+    std::string            hostname_;
+    std::string            state_str_;
     //@}
-
 };
 
 /// @brief Supports exchanging IPv4 leases with PostgreSQL.
@@ -361,7 +367,6 @@ public:
                                   << " exceeds maximum allowed of: "
                                   << HWAddr::MAX_HWADDR_LEN);
                 }
-
                 bind_array.add(lease->hwaddr_->hwaddr_);
             } else {
                 bind_array.add("");
@@ -373,18 +378,17 @@ public:
                 bind_array.add("");
             }
 
-            valid_lft_str_ = boost::lexical_cast<std::string>
-                             (lease->valid_lft_);
-            bind_array.add(valid_lft_str_);
+            valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
+            bind_array.add(valid_lifetime_str_);
 
             expire_str_ = convertToDatabaseTime(lease->cltt_, lease_->valid_lft_);
             bind_array.add(expire_str_);
 
-            subnet_id_str_ = boost::lexical_cast<std::string>
-                             (lease->subnet_id_);
+            subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
             bind_array.add(subnet_id_str_);
 
             bind_array.add(lease->fqdn_fwd_);
+
             bind_array.add(lease->fqdn_rev_);
 
             bind_array.add(lease->hostname_);
@@ -427,6 +431,7 @@ public:
             cltt_ = expire_ - valid_lifetime_;
 
             getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
+
             getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
 
             hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
@@ -457,15 +462,15 @@ private:
     /// @brief Lease4 object currently being sent to the database.
     /// Storing this value ensures that it remains in scope while any bindings
     /// that refer to its contents are in use.
-    Lease4Ptr       lease_;
-
-    /// @Brief Lease4 specific members used for binding and conversion.
-    uint32_t        addr4_;
-    size_t          hwaddr_length_;
-    std::vector<uint8_t> hwaddr_;
-    uint8_t         hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
-    size_t          client_id_length_;
-    uint8_t         client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
+    Lease4Ptr              lease_;
+
+    /// @brief Lease4 specific members for binding and conversion.
+    uint32_t               addr4_;
+    size_t                 hwaddr_length_;
+    std::vector<uint8_t>   hwaddr_;
+    uint8_t                hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
+    size_t                 client_id_length_;
+    uint8_t                client_id_buffer_[ClientId::MAX_CLIENT_ID_LEN];
 };
 
 /// @brief Supports exchanging IPv6 leases with PostgreSQL.
@@ -489,18 +494,21 @@ private:
     static const int FQDN_FWD_COL = 9;
     static const int FQDN_REV_COL = 10;
     static const int HOSTNAME_COL = 11;
-    static const int STATE_COL = 12;
+    static const int HWADDR_COL = 12;
+    static const int HWTYPE_COL = 13;
+    static const int HWADDR_SOURCE_COL = 14;
+    static const int STATE_COL = 15;
     //@}
     /// @brief Number of columns in the table holding DHCPv6 leases.
-    static const size_t LEASE_COLUMNS = 13;
+    static const size_t LEASE_COLUMNS = 16;
 
 public:
     PgSqlLease6Exchange()
         : lease_(), duid_length_(0), duid_(), iaid_u_(0), iaid_str_(""),
           lease_type_(Lease6::TYPE_NA), lease_type_str_(""), prefix_len_(0),
-          prefix_len_str_(""), pref_lifetime_(0), preferred_lft_str_("") {
+          prefix_len_str_(""), pref_lifetime_(0), preferred_lifetime_str_("") {
 
-        BOOST_STATIC_ASSERT(12 < LEASE_COLUMNS);
+        BOOST_STATIC_ASSERT(15 < LEASE_COLUMNS);
 
         memset(duid_buffer_, 0, sizeof(duid_buffer_));
 
@@ -517,6 +525,9 @@ public:
         columns_.push_back("fqdn_fwd");
         columns_.push_back("fqdn_rev");
         columns_.push_back("hostname");
+        columns_.push_back("hwaddr");
+        columns_.push_back("hwtype");
+        columns_.push_back("hwaddr_source");
         columns_.push_back("state");
     }
 
@@ -549,20 +560,17 @@ public:
                 isc_throw (BadValue, "IPv6 Lease cannot have a null DUID");
             }
 
-            valid_lft_str_ = boost::lexical_cast<std::string>
-                             (lease->valid_lft_);
-            bind_array.add(valid_lft_str_);
+            valid_lifetime_str_ = boost::lexical_cast<std::string>(lease->valid_lft_);
+            bind_array.add(valid_lifetime_str_);
 
             expire_str_ = convertToDatabaseTime(lease->cltt_, lease_->valid_lft_);
             bind_array.add(expire_str_);
 
-            subnet_id_str_ = boost::lexical_cast<std::string>
-                             (lease->subnet_id_);
+            subnet_id_str_ = boost::lexical_cast<std::string>(lease->subnet_id_);
             bind_array.add(subnet_id_str_);
 
-            preferred_lft_str_ = boost::lexical_cast<std::string>
-                                 (lease_->preferred_lft_);
-            bind_array.add(preferred_lft_str_);
+            preferred_lifetime_str_ = boost::lexical_cast<std::string>(lease_->preferred_lft_);
+            bind_array.add(preferred_lifetime_str_);
 
             lease_type_str_ = boost::lexical_cast<std::string>(lease_->type_);
             bind_array.add(lease_type_str_);
@@ -576,14 +584,44 @@ public:
 
             prefix_len_str_ = boost::lexical_cast<std::string>
                               (static_cast<unsigned int>(lease_->prefixlen_));
-
             bind_array.add(prefix_len_str_);
 
             bind_array.add(lease->fqdn_fwd_);
+
             bind_array.add(lease->fqdn_rev_);
 
             bind_array.add(lease->hostname_);
 
+            if (lease->hwaddr_ && !lease->hwaddr_->hwaddr_.empty()) {
+                // PostgreSql does not provide MAX on variable length types
+                // so we have to enforce it ourselves.
+                if (lease->hwaddr_->hwaddr_.size() > HWAddr::MAX_HWADDR_LEN) {
+                        isc_throw(DbOperationError, "Hardware address length : "
+                                  << lease_->hwaddr_->hwaddr_.size()
+                                  << " exceeds maximum allowed of: "
+                                  << HWAddr::MAX_HWADDR_LEN);
+                }
+                bind_array.add(lease->hwaddr_->hwaddr_);
+            } else {
+                bind_array.add("");
+            }
+
+            if (lease->hwaddr_) {
+                hwtype_str_ = boost::lexical_cast<std::string>
+                              (static_cast<unsigned int>(lease_->hwaddr_->htype_));
+                hwaddr_source_str_ = boost::lexical_cast<std::string>
+                                     (static_cast<unsigned int>(lease_->hwaddr_->source_));
+            } else {
+                hwtype_str_ = boost::lexical_cast<std::string>
+                              (static_cast<unsigned int>(HTYPE_UNDEFINED));
+                hwaddr_source_str_ = boost::lexical_cast<std::string>
+                                     (static_cast<unsigned int>(HWAddr::HWADDR_SOURCE_UNKNOWN));
+            }
+
+            bind_array.add(hwtype_str_);
+
+            bind_array.add(hwaddr_source_str_);
+
             state_str_ = boost::lexical_cast<std::string>(lease->state_);
             bind_array.add(state_str_);
 
@@ -615,8 +653,7 @@ public:
 
             isc::asiolink::IOAddress addr(getIPv6Value(r, row, ADDRESS_COL));
 
-            convertFromBytea(r, row, DUID_COL, duid_buffer_,
-                             sizeof(duid_buffer_), duid_length_);
+            convertFromBytea(r, row, DUID_COL, duid_buffer_, sizeof(duid_buffer_), duid_length_);
             DuidPtr duid_ptr(new DUID(duid_buffer_, duid_length_));
 
             getColumnValue(r, row, VALID_LIFETIME_COL, valid_lifetime_);
@@ -637,16 +674,26 @@ public:
             getColumnValue(r, row , PREFIX_LEN_COL, prefix_len_);
 
             getColumnValue(r, row, FQDN_FWD_COL, fqdn_fwd_);
+
             getColumnValue(r, row, FQDN_REV_COL, fqdn_rev_);
 
             hostname_ = getRawColumnValue(r, row, HOSTNAME_COL);
 
+            convertFromBytea(r, row, HWADDR_COL, hwaddr_buffer_,
+                             sizeof(hwaddr_buffer_), hwaddr_length_);
+
+            getColumnValue(r, row , HWTYPE_COL, hwtype_);
+
+            getColumnValue(r, row , HWADDR_SOURCE_COL, hwaddr_source_);
+
+            HWAddrPtr hwaddr(new HWAddr(hwaddr_buffer_, hwaddr_length_,
+                                        hwtype_));
+
+            hwaddr->source_ = hwaddr_source_;
+
             uint32_t state;
             getColumnValue(r, row , STATE_COL, state);
 
-            /// @todo: implement this in #3557.
-            HWAddrPtr hwaddr;
-
             Lease6Ptr result(new Lease6(lease_type_, addr, duid_ptr,
                                         iaid_u_.uval_, pref_lifetime_,
                                         valid_lifetime_, 0, 0,
@@ -697,13 +744,13 @@ private:
     /// @brief Lease6 object currently being sent to the database.
     /// Storing this value ensures that it remains in scope while any bindings
     /// that refer to its contents are in use.
-    Lease6Ptr       lease_;
+    Lease6Ptr              lease_;
 
     /// @brief Lease6 specific members for binding and conversion.
     //@{
-    size_t          duid_length_;
-    vector<uint8_t> duid_;
-    uint8_t         duid_buffer_[DUID::MAX_DUID_LEN];
+    size_t                 duid_length_;
+    vector<uint8_t>        duid_;
+    uint8_t                duid_buffer_[DUID::MAX_DUID_LEN];
 
     /// @brief Union for marshalling IAID into and out of the database
     /// IAID is defined in the RFC as 4 octets, which Kea code handles as
@@ -716,15 +763,22 @@ private:
         Uiaid(int32_t val) : ival_(val){};
         uint32_t uval_;
         int32_t ival_;
-    } iaid_u_;
-
-    std::string iaid_str_;
-    Lease6::Type    lease_type_;
-    std::string lease_type_str_;
-    uint8_t         prefix_len_;
-    std::string prefix_len_str_;
-    uint32_t        pref_lifetime_;
-    std::string preferred_lft_str_;
+    }                      iaid_u_;
+
+    std::string            iaid_str_;
+    Lease6::Type           lease_type_;
+    std::string            lease_type_str_;
+    uint8_t                prefix_len_;
+    std::string            prefix_len_str_;
+    uint32_t               pref_lifetime_;
+    std::string            preferred_lifetime_str_;
+    size_t                 hwaddr_length_;
+    vector<uint8_t>        hwaddr_;
+    uint8_t                hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN];
+    uint32_t               hwtype_;
+    std::string            hwtype_str_;
+    uint32_t               hwaddr_source_;
+    std::string            hwaddr_source_str_;
     //@}
 };
 
index d79b4f7fb5c46fffefe91f9fb5fa50e32c5848fd..bb2155d27a452c831010cf8ab137732d325d76ea 100644 (file)
@@ -627,7 +627,7 @@ private:
     PgSqlConnection conn_;
 };
 
-}; // end of isc::dhcp namespace
-}; // end of isc namespace
+}  // namespace dhcp
+}  // namespace isc
 
 #endif // PGSQL_LEASE_MGR_H
index a3462a5421d1120bed166d0aea939b7b8d6f37cd..e5f20b9e673e2177aa23b5bc446a692ee0078de4 100644 (file)
 #include <config.h>
 
 #include <asiolink/io_address.h>
+#include <dhcpsrv/tests/test_utils.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/host.h>
 #include <dhcpsrv/cql_connection.h>
 #include <dhcpsrv/cql_host_data_source.h>
-#include <dhcpsrv/cql_lease_mgr.h>
-#include <dhcpsrv/host.h>
-#include <dhcpsrv/host_data_source_factory.h>
+#include <dhcpsrv/cql_exchange.h>
 #include <dhcpsrv/tests/generic_host_data_source_unittest.h>
-#include <dhcpsrv/tests/test_utils.h>
 #include <dhcpsrv/testutils/cql_schema.h>
 #include <dhcpsrv/testutils/host_data_source_utils.h>
-#include <exceptions/exceptions.h>
+#include <dhcpsrv/host_data_source_factory.h>
 
 #include <gtest/gtest.h>
 
 #include <algorithm>
+#include <iostream>
 #include <sstream>
 #include <string>
 #include <utility>
 
-namespace {
-
 using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
+using namespace isc::data;
+using namespace std;
+
+namespace {
 
-/// @brief Fixture class for testing Cassandra host data source
 class CqlHostDataSourceTest : public GenericHostDataSourceTest {
 public:
     /// @brief Clears the database and opens connection to it.
@@ -56,11 +58,11 @@ public:
         try {
             HostDataSourceFactory::create(validCqlConnectionString());
         } catch (...) {
-            std::cerr << "*** ERROR: unable to open database. The test"
-                         "*** environment is broken and must be fixed before"
-                         "*** the CQL tests will run correctly."
-                         "*** The reason for the problem is described in the"
-                         "*** accompanying exception output.";
+            std::cerr << "*** ERROR: unable to open database. The test\n"
+                         "*** environment is broken and must be fixed before\n"
+                         "*** the CQL tests will run correctly.\n"
+                         "*** The reason for the problem is described in the\n"
+                         "*** accompanying exception output.\n";
             throw;
         }
 
@@ -88,9 +90,8 @@ public:
 
     /// @brief Destructor
     ///
-    /// Rolls back all pending transactions.  The deletion of myhdsptr_ will
-    /// close the database.  Then reopen it and delete everything created by the
-    /// test.
+    /// Rolls back all pending transactions.  The deletion of hdsptr_ will close
+    /// the database.  Then reopen it and delete everything created by the test.
     virtual ~CqlHostDataSourceTest() {
         destroyTest();
     }
@@ -117,6 +118,7 @@ public:
 /// opened: the fixtures assume that and check basic operations.
 
 TEST(CqlHostDataSource, OpenDatabase) {
+
     // Schema needs to be created for the test to work.
     destroyCqlSchema(false, true);
     createCqlSchema(false, true);
@@ -125,7 +127,7 @@ TEST(CqlHostDataSource, OpenDatabase) {
     //  If it fails, print the error message.
     try {
         HostDataSourceFactory::create(validCqlConnectionString());
-        EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
+        EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
         HostDataSourceFactory::destroy();
     } catch (const isc::Exception& ex) {
         FAIL() << "*** ERROR: unable to open database, reason:\n"
@@ -137,10 +139,10 @@ TEST(CqlHostDataSource, OpenDatabase) {
     // Check that lease manager open the database opens correctly with a longer
     // timeout.  If it fails, print the error message.
     try {
-        std::string connection_string = validCqlConnectionString() + std::string(" ") +
-                                        std::string(VALID_TIMEOUT);
+        string connection_string = validCqlConnectionString() + string(" ") +
+                                   string(VALID_TIMEOUT);
         HostDataSourceFactory::create(connection_string);
-        EXPECT_NO_THROW((void)HostDataSourceFactory::getHostDataSourcePtr());
+        EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
         HostDataSourceFactory::destroy();
     } catch (const isc::Exception& ex) {
         FAIL() << "*** ERROR: unable to open database, reason:\n"
@@ -157,40 +159,40 @@ TEST(CqlHostDataSource, OpenDatabase) {
     // (This is really a check on HostDataSourceFactory, but is convenient to
     // perform here.)
     EXPECT_THROW(HostDataSourceFactory::create(connectionString(
-                 NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
-                 InvalidParameter);
+        NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+        InvalidParameter);
     EXPECT_THROW(HostDataSourceFactory::create(connectionString(
-                 INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
-                 InvalidType);
+        INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+        InvalidType);
 
     // Check that invalid login data does not cause an exception, CQL should use
     // default values.
-    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                    INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
-    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                    VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
-    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                    VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
-    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                    VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
+    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
+    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
+    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
 
     // Check that invalid timeouts throw DbOperationError.
-    EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                 VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
-                 DbOperationError);
-    EXPECT_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                 VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
-                 DbOperationError);
+    EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
+        DbOperationError);
+    EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
+        DbOperationError);
 
     // Check that CQL allows the hostname to not be specified.
-    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(CQL_VALID_TYPE,
-                    NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+    EXPECT_NO_THROW(HostDataSourceFactory::create(connectionString(
+        CQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
 
     // Tidy up after the test
     destroyCqlSchema(false, true);
 }
 
-/// @brief Check conversion methods
+/// @brief Check conversion functions
 ///
 /// The server works using cltt and valid_filetime.  In the database, the
 /// information is stored as expire_time and valid-lifetime, which are
@@ -215,6 +217,11 @@ TEST(CqlConnection, checkTimeConversion) {
     EXPECT_EQ(cltt, converted_cltt);
 }
 
+// This test verifies that database backend can operate in Read-Only mode.
+TEST_F(CqlHostDataSourceTest, testReadOnlyDatabase) {
+    testReadOnlyDatabase(CQL_VALID_TYPE);
+}
+
 // Test verifies if a host reservation can be added and later retrieved by IPv4
 // address. Host uses hw address as identifier.
 TEST_F(CqlHostDataSourceTest, basic4HWAddr) {
@@ -257,6 +264,12 @@ TEST_F(CqlHostDataSourceTest, get4ByCircuitId) {
     testGet4ByIdentifier(Host::IDENT_CIRCUIT_ID);
 }
 
+// Test verifies if a host reservation can be added and later retrieved by
+// client-id.
+TEST_F(CqlHostDataSourceTest, get4ByClientId) {
+    testGet4ByIdentifier(Host::IDENT_CLIENT_ID);
+}
+
 // Test verifies if hardware address and client identifier are not confused.
 TEST_F(CqlHostDataSourceTest, hwaddrNotClientId1) {
     testHWAddrNotClientId();
@@ -278,12 +291,18 @@ TEST_F(CqlHostDataSourceTest, hostnameFQDN100) {
     testHostname("foo.example.org", 100);
 }
 
-// Test verifies if a host without any hostname specified can be stored and
-// later retrieved.
+// Test verifies if a host without any hostname specified can be stored and later
+// retrieved.
 TEST_F(CqlHostDataSourceTest, noHostname) {
     testHostname("", 1);
 }
 
+// Test verifies if a host with user context can be stored and later retrieved.
+TEST_F(CqlHostDataSourceTest, usercontext) {
+    string comment = "{ \"comment\": \"a host reservation\" }";
+    testUserContext(Element::fromJSON(comment));
+}
+
 // Test verifies if the hardware or client-id query can match hardware address.
 TEST_F(CqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
     /// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
@@ -364,30 +383,22 @@ TEST_F(CqlHostDataSourceTest, multipleReservationsDifferentOrder) {
     testMultipleReservationsDifferentOrder();
 }
 
-// Test verifies if multiple client classes for IPv4 can be stored.
-TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClasses4) {
-    /// @todo: Implement this test as part of #5503.
-
-    /// Add host reservation with a multiple v4 client-classes, retrieve it and
-    /// make sure that all client classes are retrieved properly.
+// Test that multiple client classes for IPv4 can be inserted and
+// retrieved for a given host reservation.
+TEST_F(CqlHostDataSourceTest, multipleClientClasses4) {
+    testMultipleClientClasses4();
 }
 
-// Test verifies if multiple client classes for IPv6 can be stored.
-TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClasses6) {
-    /// @todo: Implement this test as part of #5503.
-
-    /// Add host reservation with a multiple v6 client-classes, retrieve it and
-    /// make sure that all client classes are retrieved properly.
+// Test that multiple client classes for IPv6 can be inserted and
+// retrieved for a given host reservation.
+TEST_F(CqlHostDataSourceTest, multipleClientClasses6) {
+    testMultipleClientClasses6();
 }
 
-// Test verifies if multiple client classes for both IPv4 and IPv6 can be
-// stored.
-TEST_F(CqlHostDataSourceTest, DISABLED_multipleClientClassesBoth) {
-    /// @todo: Implement this test as part of #5503.
-
-    /// Add host reservation with a multiple v4 and v6 client-classes, retrieve
-    /// it and make sure that all client classes are retrieved properly. Also,
-    /// check that the classes are not confused.
+// Test that multiple client classes for both IPv4 and IPv6 can
+// be inserted and retrieved for a given host reservation.
+TEST_F(CqlHostDataSourceTest, multipleClientClassesBoth) {
+    testMultipleClientClassesBoth();
 }
 
 // Test if the same host can have reservations in different subnets (with the
@@ -409,8 +420,8 @@ TEST_F(CqlHostDataSourceTest, multipleSubnetsClientId) {
     testMultipleSubnets(10, Host::IDENT_DUID);
 }
 
-// Test if host reservations made for different IPv6 subnets are handled
-// correctly. The test logic is as follows:
+// Test if host reservations made for different IPv6 subnets are handled correctly.
+// The test logic is as follows:
 //
 // Insert 10 host reservations for different subnets. Make sure that
 // get6(subnet-id, ...) calls return correct reservation.
@@ -434,8 +445,8 @@ TEST_F(CqlHostDataSourceTest, addDuplicate6WithHWAddr) {
     testAddDuplicate6WithSameHWAddr();
 }
 
-// Test if the duplicate IPv4 host instances can't be inserted. The test logic
-// is as follows: try to add multiple instances of the same host reservation and
+// Test if the duplicate IPv4 host instances can't be inserted. The test logic is as
+// follows: try to add multiple instances of the same host reservation and
 // verify that the second and following attempts will throw exceptions.
 TEST_F(CqlHostDataSourceTest, addDuplicate4) {
     testAddDuplicate4();
@@ -444,13 +455,15 @@ TEST_F(CqlHostDataSourceTest, addDuplicate4) {
 // This test verifies that DHCPv4 options can be inserted in a binary format
 /// and retrieved from the CQL host database.
 TEST_F(CqlHostDataSourceTest, optionsReservations4) {
-    testOptionsReservations4(false);
+    string comment = "{ \"comment\": \"a host reservation\" }";
+    testOptionsReservations4(false, Element::fromJSON(comment));
 }
 
 // This test verifies that DHCPv6 options can be inserted in a binary format
 /// and retrieved from the CQL host database.
 TEST_F(CqlHostDataSourceTest, optionsReservations6) {
-    testOptionsReservations6(false);
+    string comment = "{ \"comment\": \"a host reservation\" }";
+    testOptionsReservations6(false, Element::fromJSON(comment));
 }
 
 // This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
@@ -462,13 +475,15 @@ TEST_F(CqlHostDataSourceTest, optionsReservations46) {
 // This test verifies that DHCPv4 options can be inserted in a textual format
 /// and retrieved from the CQL host database.
 TEST_F(CqlHostDataSourceTest, formattedOptionsReservations4) {
-    testOptionsReservations4(true);
+    string comment = "{ \"comment\": \"a host reservation\" }";
+    testOptionsReservations4(true, Element::fromJSON(comment));
 }
 
 // This test verifies that DHCPv6 options can be inserted in a textual format
 /// and retrieved from the CQL host database.
 TEST_F(CqlHostDataSourceTest, formattedOptionsReservations6) {
-    testOptionsReservations6(true);
+    string comment = "{ \"comment\": \"a host reservation\" }";
+    testOptionsReservations6(true, Element::fromJSON(comment));
 }
 
 // This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
@@ -517,10 +532,11 @@ TEST_F(CqlHostDataSourceTest, testAddRollback) {
     // retrieve the data from ipv6_reservations table. The query should
     // pass but return no host because the (insert) transaction is expected
     // to be rolled back.
-    ASSERT_THROW(
-        hdsptr_->get4(host->getIPv4SubnetID(), host->getIdentifierType(),
-                      &host->getIdentifier()[0], host->getIdentifier().size()),
-        DbOperationError);
+    ASSERT_THROW(hdsptr_->get4(host->getIPv4SubnetID(),
+                                  host->getIdentifierType(),
+                               &host->getIdentifier()[0],
+                               host->getIdentifier().size()),
+                               DbOperationError);
 }
 
 TEST_F(CqlHostDataSourceTest, DISABLED_stressTest) {
@@ -535,8 +551,7 @@ TEST_F(CqlHostDataSourceTest, DISABLED_stressTest) {
 
 // This test checks that siaddr, sname, file fields can be retrieved
 /// from a database for a host.
-/// @todo: Uncomment this after 5507 is implemented.
-TEST_F(CqlHostDataSourceTest, DISABLED_messageFields) {
+TEST_F(CqlHostDataSourceTest, messageFields) {
     testMessageFields4();
 }
 
@@ -575,13 +590,13 @@ TEST_F(CqlHostDataSourceTest, DISABLED_deleteById6Options) {
 // Tests that multiple reservations without IPv4 addresses can be
 // specified within a subnet.
 /// @todo: Uncomment this after #5506 is implemented.
-TEST_F(CqlHostDataSourceTest, DISABLED_testMultipleHostsNoAddress4) {
+TEST_F(CqlHostDataSourceTest, testMultipleHostsNoAddress4) {
     testMultipleHostsNoAddress4();
 }
 
 // Tests that multiple hosts can be specified within an IPv6 subnet.
 /// @todo: Uncomment this after #5506 is implemented.
-TEST_F(CqlHostDataSourceTest, DISABLED_testMultipleHosts6) {
+TEST_F(CqlHostDataSourceTest, testMultipleHosts6) {
     testMultipleHosts6();
 }
 
index a5ba99b0bdf389d465637253746f3ae9d9d0c2be..0d1a0bf036741c3480c27b00d8824d52ca4b1de5 100644 (file)
@@ -1,3 +1,4 @@
+// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC")
 // Copyright (C) 2015-2017 Deutsche Telekom AG.
 //
 // Authors: Razvan Becheriu <razvan.becheriu@qualitance.com>
 
 #include <config.h>
 
-#include <gtest/gtest.h>
-
 #include <asiolink/io_address.h>
+#include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/cql_connection.h>
 #include <dhcpsrv/cql_lease_mgr.h>
-#include <dhcpsrv/lease_mgr_factory.h>
-#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 #include <dhcpsrv/tests/test_utils.h>
+#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 #include <dhcpsrv/testutils/cql_schema.h>
 #include <exceptions/exceptions.h>
 
+#include <gtest/gtest.h>
+
 #include <algorithm>
+#include <iostream>
 #include <sstream>
 #include <string>
 #include <utility>
@@ -37,13 +39,16 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
+using namespace std;
 
 namespace {
 
+
 /// @brief Test fixture class for testing Cassandra Lease Manager
 ///
 /// Opens the database prior to each test and closes it afterwards.
 /// All pending transactions are deleted prior to closure.
+
 class CqlLeaseMgrTest : public GenericLeaseMgrTest {
 public:
     /// @brief Clears the database and opens connection to it.
@@ -87,19 +92,19 @@ public:
 
     /// @brief Destructor
     ///
-    /// Rolls back all pending transactions. The deletion of lmptr_ will close
-    /// the database. Then reopen it and delete everything created by the test.
+    /// Rolls back all pending transactions.  The deletion of lmptr_ will close
+    /// the database.  Then reopen it and delete everything created by the test.
     virtual ~CqlLeaseMgrTest() {
         destroyTest();
     }
 
     /// @brief Reopen the database
     ///
-    /// Closes the database and re-open it. Anything committed should be
+    /// Closes the database and re-open it.  Anything committed should be
     /// visible.
     ///
-    /// Parameter is ignored for CQL backend as the v4 and v6 leases share the
-    /// same keyspace.
+    /// Parameter is ignored for CQL backend as the v4 and v6 leases share
+    /// the same database.
     void reopen(Universe) {
         LeaseMgrFactory::destroy();
         LeaseMgrFactory::create(validCqlConnectionString());
@@ -326,13 +331,13 @@ public:
 
 /// @brief Check that database can be opened
 ///
-/// This test checks if the CqlLeaseMgr can be instantiated. This happens
-/// only if the database can be opened. Note that this is not part of the
-/// CqlLeaseMgr test fixure set. This test checks that the database can be
+/// This test checks if the CqlLeaseMgr can be instantiated.  This happens
+/// only if the database can be opened.  Note that this is not part of the
+/// CqlLeaseMgr test fixure set.  This test checks that the database can be
 /// opened: the fixtures assume that and check basic operations.
-/// Unlike other backend implementations, this one doesn't check for lacking
-/// parameters. In that scenario, Cassandra defaults to configured parameters.
+
 TEST(CqlOpenTest, OpenDatabase) {
+
     // Schema needs to be created for the test to work.
     destroyCqlSchema(false, true);
     createCqlSchema(false, true);
@@ -351,13 +356,12 @@ TEST(CqlOpenTest, OpenDatabase) {
     }
 
     // Check that lease manager open the database opens correctly with a longer
-    // timeout. If it fails, print the error message.
+    // timeout.  If it fails, print the error message.
     try {
-        std::string connection_string = validCqlConnectionString() +
-                                        std::string(" ") +
-                                        std::string(VALID_TIMEOUT);
+        string connection_string = validCqlConnectionString() + string(" ") +
+                                   string(VALID_TIMEOUT);
         LeaseMgrFactory::create(connection_string);
-        EXPECT_NO_THROW((void)LeaseMgrFactory::instance());
+        EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
         LeaseMgrFactory::destroy();
     } catch (const isc::Exception& ex) {
         FAIL() << "*** ERROR: unable to open database, reason:\n"
@@ -373,37 +377,38 @@ TEST(CqlOpenTest, OpenDatabase) {
     // Check that wrong specification of backend throws an exception.
     // (This is really a check on LeaseMgrFactory, but is convenient to
     // perform here.)
-    EXPECT_THROW(
-        LeaseMgrFactory::create(connectionString(NULL, VALID_NAME, VALID_HOST,
-                                                 INVALID_USER, VALID_PASSWORD)),
+    EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+        NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
         InvalidParameter);
-    EXPECT_THROW(
-        LeaseMgrFactory::create(connectionString(
-            INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+
+    EXPECT_THROW(LeaseMgrFactory::create(connectionString(
+        INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
         InvalidType);
 
     // Check that invalid login data does not cause an exception, CQL should use
     // default values.
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
+
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
+
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
 
-    // Check that invalid timeouts throw DbOperationError.
+    // Check for invalid timeouts
     EXPECT_THROW(LeaseMgrFactory::create(connectionString(
-                     CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
-                     VALID_PASSWORD, INVALID_TIMEOUT_1)),
-                 DbOperationError);
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
+        DbOperationError);
+
     EXPECT_THROW(LeaseMgrFactory::create(connectionString(
-                     CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
-                     VALID_PASSWORD, INVALID_TIMEOUT_2)),
-                 DbOperationError);
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
+        DbOperationError);
 
-    // Check that CQL allows the hostname to not be specified.
+    // Check for missing parameters
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
 
@@ -411,22 +416,25 @@ TEST(CqlOpenTest, OpenDatabase) {
     // default values.
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)));
+
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)));
+
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)));
+
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
         CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)));
 
     // Check that invalid timeouts throw DbOperationError.
     EXPECT_THROW(LeaseMgrFactory::create(connectionString(
-                     CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
-                     VALID_PASSWORD, INVALID_TIMEOUT_1)),
-                 DbOperationError);
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD,
+        INVALID_TIMEOUT_1)),
+        DbOperationError);
     EXPECT_THROW(LeaseMgrFactory::create(connectionString(
-                     CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER,
-                     VALID_PASSWORD, INVALID_TIMEOUT_2)),
-                 DbOperationError);
+        CQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD,
+        INVALID_TIMEOUT_2)),
+        DbOperationError);
 
     // Check that CQL allows the hostname to not be specified.
     EXPECT_NO_THROW(LeaseMgrFactory::create(connectionString(
@@ -444,9 +452,9 @@ TEST_F(CqlLeaseMgrTest, getType) {
     EXPECT_EQ(std::string("cql"), lmptr_->getType());
 }
 
-/// @brief Check conversion methods
+/// @brief Check conversion functions
 ///
-/// The server works using cltt and valid_filetime. In the database, the
+/// The server works using cltt and valid_filetime.  In the database, the
 /// information is stored as expire_time and valid-lifetime, which are
 /// related by
 ///
@@ -461,13 +469,13 @@ TEST_F(CqlLeaseMgrTest, checkTimeConversion) {
     // Convert to the database time.
     CqlExchange::convertToDatabaseTime(cltt, valid_lft, cql_expire);
 
-    // Convert back.
+    // Convert back
     time_t converted_cltt = 0;
     CqlExchange::convertFromDatabaseTime(cql_expire, valid_lft, converted_cltt);
     EXPECT_EQ(cltt, converted_cltt);
 }
 
-/// @brief Check getName() returns correct keyspace name.
+/// @brief Check getName() returns correct database name
 TEST_F(CqlLeaseMgrTest, getName) {
     EXPECT_EQ(std::string("keatest"), lmptr_->getName());
 }
@@ -475,7 +483,7 @@ TEST_F(CqlLeaseMgrTest, getName) {
 /// @brief Check that getVersion() returns the expected version
 TEST_F(CqlLeaseMgrTest, checkVersion) {
     // Check version
-    VersionPair version;
+    pair<uint32_t, uint32_t> version;
     ASSERT_NO_THROW(version = lmptr_->getVersion());
     EXPECT_EQ(CQL_SCHEMA_VERSION_MAJOR, version.first);
     EXPECT_EQ(CQL_SCHEMA_VERSION_MINOR, version.second);
@@ -567,10 +575,19 @@ TEST_F(CqlLeaseMgrTest, getLease4ClientIdSubnetId) {
     testGetLease4ClientIdSubnetId();
 }
 
+// This test checks that all IPv4 leases for a specified subnet id are returned.
+TEST_F(CqlLeaseMgrTest, getLeases4SubnetId) {
+    testGetLeases4SubnetId();
+}
+
+// This test checks that all IPv4 leases are returned.
+TEST_F(CqlLeaseMgrTest, getLeases4) {
+    testGetLeases4();
+}
+
 /// @brief Basic Lease4 Checks
 ///
-/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,
-/// subnet_id),
+/// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
 /// updateLease4() and deleteLease can handle NULL client-id.
 /// (client-id is optional and may not be present)
 TEST_F(CqlLeaseMgrTest, lease4NullClientId) {
@@ -585,6 +602,22 @@ TEST_F(CqlLeaseMgrTest, lease4InvalidHostname) {
     testLease4InvalidHostname();
 }
 
+/// @brief Check that the expired DHCPv4 leases can be retrieved.
+///
+/// This test adds a number of leases to the lease database and marks
+/// some of them as expired. Then it queries for expired leases and checks
+/// whether only expired leases are returned, and that they are returned in
+/// the order from most to least expired. It also checks that the lease
+/// which is marked as 'reclaimed' is not returned.
+TEST_F(CqlLeaseMgrTest, getExpiredLeases4) {
+    testCqlGetExpiredLeases4();
+}
+
+/// @brief Check that expired reclaimed DHCPv4 leases are removed.
+TEST_F(CqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
+    testDeleteExpiredReclaimedLeases4();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 /// LEASE6 /////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
@@ -692,17 +725,6 @@ TEST_F(CqlLeaseMgrTest, testLease6HWTypeAndSource) {
     testLease6HWTypeAndSource();
 }
 
-/// @brief Check that the expired DHCPv4 leases can be retrieved.
-///
-/// This test adds a number of leases to the lease database and marks
-/// some of them as expired. Then it queries for expired leases and checks
-/// whether only expired leases are returned, and that they are returned in
-/// the order from most to least expired. It also checks that the lease
-/// which is marked as 'reclaimed' is not returned.
-TEST_F(CqlLeaseMgrTest, getExpiredLeases4) {
-    testCqlGetExpiredLeases4();
-}
-
 /// @brief Check that the expired DHCPv6 leases can be retrieved.
 ///
 /// This test adds a number of leases to the lease database and marks
@@ -719,11 +741,6 @@ TEST_F(CqlLeaseMgrTest, deleteExpiredReclaimedLeases6) {
     testDeleteExpiredReclaimedLeases6();
 }
 
-/// @brief Check that expired reclaimed DHCPv4 leases are removed.
-TEST_F(CqlLeaseMgrTest, deleteExpiredReclaimedLeases4) {
-    testDeleteExpiredReclaimedLeases4();
-}
-
 // Verifies that IPv4 lease statistics can be recalculated.
 /// @todo: uncomment this once stats recalculation is implemented
 /// for Cassandra (see #5487)
@@ -753,4 +770,3 @@ TEST_F(CqlLeaseMgrTest, DISABLED_wipeLeases6) {
 }
 
 }  // namespace
-
index d7d0034fa773c4ca41a4123f8eb63d58218b6ad2..3ffd453036808a5ad309bf0530730d168bf979c0 100644 (file)
@@ -77,7 +77,7 @@ public:
 
     /// @brief Destructor
     ///
-    /// Rolls back all pending transactions.  The deletion of myhdsptr_ will close
+    /// Rolls back all pending transactions.  The deletion of hdsptr_ will close
     /// the database.  Then reopen it and delete everything created by the test.
     virtual ~MySqlHostDataSourceTest() {
         destroyTest();
index 0a4ffb8542a067e66d096a7b493e9f66dfa689c9..1d0aac8eeaa3877dd5183c6829cee86c4605c79c 100644 (file)
@@ -77,7 +77,7 @@ public:
 
     /// @brief Destructor
     ///
-    /// Rolls back all pending transactions.  The deletion of myhdsptr_ will close
+    /// Rolls back all pending transactions.  The deletion of hdsptr_ will close
     /// the database.  Then reopen it and delete everything created by the test.
     virtual ~PgSqlHostDataSourceTest() {
         destroyTest();
index fa84bbb99b20003858679a8f2041a494be1050ba..de63852039dc3320183b0619e18cdb47e885acb3 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <asiolink/io_address.h>
 #include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/pgsql_connection.h>
 #include <dhcpsrv/pgsql_lease_mgr.h>
 #include <dhcpsrv/tests/test_utils.h>
 #include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
 
 #include <gtest/gtest.h>
 
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <utility>
+
 using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
@@ -24,6 +31,7 @@ using namespace std;
 
 namespace {
 
+
 /// @brief Test fixture class for testing PostgreSQL Lease Manager
 ///
 /// Opens the database prior to each test and closes it afterwards.
@@ -31,11 +39,8 @@ namespace {
 
 class PgSqlLeaseMgrTest : public GenericLeaseMgrTest {
 public:
-    /// @brief Constructor
-    ///
-    /// Deletes everything from the database and opens it.
-    PgSqlLeaseMgrTest() {
-
+    /// @brief Clears the database and opens connection to it.
+    void initializeTest() {
         // Ensure schema is the correct one.
         destroyPgSQLSchema();
         createPgSQLSchema();
@@ -51,17 +56,34 @@ public:
                          "*** accompanying exception output.\n";
             throw;
         }
+
         lmptr_ = &(LeaseMgrFactory::instance());
     }
 
+    /// @brief Destroys the LM and the schema.
+    void destroyTest() {
+        try {
+            lmptr_->rollback();
+        } catch (...) {
+            // Rollback may fail if backend is in read only mode. That's ok.
+        }
+        LeaseMgrFactory::destroy();
+        destroyPgSQLSchema();
+    }
+
+    /// @brief Constructor
+    ///
+    /// Deletes everything from the database and opens it.
+    PgSqlLeaseMgrTest() {
+        initializeTest();
+    }
+
     /// @brief Destructor
     ///
     /// Rolls back all pending transactions.  The deletion of lmptr_ will close
     /// the database.  Then reopen it and delete everything created by the test.
     virtual ~PgSqlLeaseMgrTest() {
-        lmptr_->rollback();
-        LeaseMgrFactory::destroy();
-        destroyPgSQLSchema();
+        destroyTest();
     }
 
     /// @brief Reopen the database
@@ -69,14 +91,13 @@ public:
     /// Closes the database and re-open it.  Anything committed should be
     /// visible.
     ///
-    /// Parameter is ignored for Postgres backend as the v4 and v6 leases share
+    /// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases share
     /// the same database.
     void reopen(Universe) {
         LeaseMgrFactory::destroy();
         LeaseMgrFactory::create(validPgSQLConnectionString());
         lmptr_ = &(LeaseMgrFactory::instance());
     }
-
 };
 
 /// @brief Check that database can be opened
@@ -96,7 +117,7 @@ TEST(PgSqlOpenTest, OpenDatabase) {
     // If it fails, print the error message.
     try {
         LeaseMgrFactory::create(validPgSQLConnectionString());
-        EXPECT_NO_THROW((void) LeaseMgrFactory::instance());
+        EXPECT_NO_THROW((void)LeaseMgrFactory::instance());
         LeaseMgrFactory::destroy();
     } catch (const isc::Exception& ex) {
         FAIL() << "*** ERROR: unable to open database, reason:\n"
@@ -159,6 +180,7 @@ TEST(PgSqlOpenTest, OpenDatabase) {
     EXPECT_THROW(LeaseMgrFactory::create(connectionString(
         PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
         DbInvalidTimeout);
+
     EXPECT_THROW(LeaseMgrFactory::create(connectionString(
         PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
         DbInvalidTimeout);
@@ -293,7 +315,7 @@ TEST_F(PgSqlLeaseMgrTest, getLeases4) {
 /// @brief Basic Lease4 Checks
 ///
 /// Checks that the addLease, getLease4(by address), getLease4(hwaddr,subnet_id),
-/// updateLease4() and deleteLease (IPv4 address) can handle NULL client-id.
+/// updateLease4() and deleteLease can handle NULL client-id.
 /// (client-id is optional and may not be present)
 TEST_F(PgSqlLeaseMgrTest, lease4NullClientId) {
     testLease4NullClientId();
@@ -397,10 +419,39 @@ TEST_F(PgSqlLeaseMgrTest, updateLease6) {
     testUpdateLease6();
 }
 
+/// @brief DHCPv4 Lease recreation tests
+///
+/// Checks that the lease can be created, deleted and recreated with
+/// different parameters. It also checks that the re-created lease is
+/// correctly stored in the lease database.
+TEST_F(PgSqlLeaseMgrTest, testRecreateLease4) {
+    testRecreateLease4();
+}
+
+/// @brief DHCPv6 Lease recreation tests
+///
+/// Checks that the lease can be created, deleted and recreated with
+/// different parameters. It also checks that the re-created lease is
+/// correctly stored in the lease database.
+TEST_F(PgSqlLeaseMgrTest, testRecreateLease6) {
+    testRecreateLease6();
+}
+
+/// @brief Checks that null DUID is not allowed.
 TEST_F(PgSqlLeaseMgrTest, nullDuid) {
     testNullDuid();
 }
 
+/// @brief Tests whether memfile can store and retrieve hardware addresses
+TEST_F(PgSqlLeaseMgrTest, testLease6Mac) {
+    testLease6MAC();
+}
+
+/// @brief Tests whether memfile can store and retrieve hardware addresses
+TEST_F(PgSqlLeaseMgrTest, testLease6HWTypeAndSource) {
+    testLease6HWTypeAndSource();
+}
+
 /// @brief Check that the expired DHCPv6 leases can be retrieved.
 ///
 /// This test adds a number of leases to the lease database and marks
@@ -412,6 +463,11 @@ TEST_F(PgSqlLeaseMgrTest, getExpiredLeases6) {
     testGetExpiredLeases6();
 }
 
+/// @brief Check that expired reclaimed DHCPv6 leases are removed.
+TEST_F(PgSqlLeaseMgrTest, deleteExpiredReclaimedLeases6) {
+    testDeleteExpiredReclaimedLeases6();
+}
+
 // Verifies that IPv4 lease statistics can be recalculated.
 TEST_F(PgSqlLeaseMgrTest, recountLeaseStats4) {
     testRecountLeaseStats4();
@@ -432,4 +488,4 @@ TEST_F(PgSqlLeaseMgrTest, DISABLED_wipeLeases6) {
     testWipeLeases6();
 }
 
-}; // namespace
+}  // namespace