From: Razvan Becheriu Date: Mon, 19 Feb 2018 14:14:38 +0000 (+0200) Subject: enabled more tests, implemented hwaddr, hwtype and hwaddr_source in pgsql X-Git-Tag: kea5574_base~10^2~1^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e9e8389d45e5a17e5e6caa581bf94b2e9b177dd4;p=thirdparty%2Fkea.git enabled more tests, implemented hwaddr, hwtype and hwaddr_source in pgsql --- diff --git a/src/lib/dhcpsrv/cfg_option.cc b/src/lib/dhcpsrv/cfg_option.cc index 83fc8589a7..05c489b603 100644 --- a/src/lib/dhcpsrv/cfg_option.cc +++ b/src/lib/dhcpsrv/cfg_option.cc @@ -171,7 +171,7 @@ CfgOption::mergeInternal(const OptionSpaceContaineraddr_.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(&(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(&(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(&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 hwaddr_; ///< Hardware address - uint8_t hwaddr_buffer_[HWAddr::MAX_HWADDR_LEN]; - ///< Hardware address buffer - unsigned long hwaddr_length_; ///< Hardware address length - std::vector 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 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 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(&(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 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 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 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 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(&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(&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 diff --git a/src/lib/dhcpsrv/mysql_lease_mgr.h b/src/lib/dhcpsrv/mysql_lease_mgr.h index 8d075a2938..ac7fc7bcf8 100644 --- a/src/lib/dhcpsrv/mysql_lease_mgr.h +++ b/src/lib/dhcpsrv/mysql_lease_mgr.h @@ -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 diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.cc b/src/lib/dhcpsrv/pgsql_lease_mgr.cc index 8e208acc1d..1ebd37edad 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.cc +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.cc @@ -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 - (lease->valid_lft_); - bind_array.add(valid_lft_str_); + valid_lifetime_str_ = boost::lexical_cast(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 - (lease->subnet_id_); + subnet_id_str_ = boost::lexical_cast(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 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 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 - (lease->valid_lft_); - bind_array.add(valid_lft_str_); + valid_lifetime_str_ = boost::lexical_cast(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 - (lease->subnet_id_); + subnet_id_str_ = boost::lexical_cast(lease->subnet_id_); bind_array.add(subnet_id_str_); - preferred_lft_str_ = boost::lexical_cast - (lease_->preferred_lft_); - bind_array.add(preferred_lft_str_); + preferred_lifetime_str_ = boost::lexical_cast(lease_->preferred_lft_); + bind_array.add(preferred_lifetime_str_); lease_type_str_ = boost::lexical_cast(lease_->type_); bind_array.add(lease_type_str_); @@ -576,14 +584,44 @@ public: prefix_len_str_ = boost::lexical_cast (static_cast(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 + (static_cast(lease_->hwaddr_->htype_)); + hwaddr_source_str_ = boost::lexical_cast + (static_cast(lease_->hwaddr_->source_)); + } else { + hwtype_str_ = boost::lexical_cast + (static_cast(HTYPE_UNDEFINED)); + hwaddr_source_str_ = boost::lexical_cast + (static_cast(HWAddr::HWADDR_SOURCE_UNKNOWN)); + } + + bind_array.add(hwtype_str_); + + bind_array.add(hwaddr_source_str_); + state_str_ = boost::lexical_cast(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 duid_; - uint8_t duid_buffer_[DUID::MAX_DUID_LEN]; + size_t duid_length_; + vector 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 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_; //@} }; diff --git a/src/lib/dhcpsrv/pgsql_lease_mgr.h b/src/lib/dhcpsrv/pgsql_lease_mgr.h index d79b4f7fb5..bb2155d27a 100644 --- a/src/lib/dhcpsrv/pgsql_lease_mgr.h +++ b/src/lib/dhcpsrv/pgsql_lease_mgr.h @@ -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 diff --git a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc index a3462a5421..e5f20b9e67 100644 --- a/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_host_data_source_unittest.cc @@ -18,32 +18,34 @@ #include #include +#include +#include +#include #include #include -#include -#include -#include +#include #include -#include #include #include -#include +#include #include #include +#include #include #include #include -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(); } diff --git a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc index a5ba99b0bd..0d1a0bf036 100644 --- a/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/cql_lease_mgr_unittest.cc @@ -1,3 +1,4 @@ +// Copyright (C) 2012-2018 Internet Systems Consortium, Inc. ("ISC") // Copyright (C) 2015-2017 Deutsche Telekom AG. // // Authors: Razvan Becheriu @@ -17,18 +18,19 @@ #include -#include - #include +#include #include #include -#include -#include #include +#include #include #include +#include + #include +#include #include #include #include @@ -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 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 - diff --git a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc index d7d0034fa7..3ffd453036 100644 --- a/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/mysql_host_data_source_unittest.cc @@ -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(); diff --git a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc index 0a4ffb8542..1d0aac8eea 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -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(); diff --git a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc index fa84bbb99b..de63852039 100644 --- a/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_lease_mgr_unittest.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -16,6 +17,12 @@ #include +#include +#include +#include +#include +#include + 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