/// None of the fields in the host reservation are modified -
/// the host data is only read.
///
- /// @return pointer to newly constructed bind_array containing the
+ /// @return pointer to newly constructed bind_array containing the
/// bound values extracted from host
///
/// @throw DbOperationError if bind_array cannot be populated.
- PsqlBindArrayPtr
+ PsqlBindArrayPtr
createBindForSend(const HostPtr& host) {
if (!host) {
isc_throw(BadValue, "createBindForSend:: host object is NULL");
// Store the host to ensure bound values remain in scope
host_ = host;
- // Bind the host data to the array
+ // Bind the host data to the array
PsqlBindArrayPtr bind_array(new PsqlBindArray());
try {
// host_id : is auto_incremented skip it
// dhcp6_subnet_id : INT NULL
bind_array->add(host->getIPv6SubnetID());
- // ipv4_address : BIGINT NULL
+ // ipv4_address : BIGINT NULL
bind_array->add(host->getIPv4Reservation());
-
+
// hostname : VARCHAR(255) NULL
bind_array->bindString(host->getHostname());
// host_id INT NOT NULL
// @todo going to have to deal with uint64_t versus INT etc...
HostID host_id;
- getColumnValue(r, row, HOST_ID_COL, host_id);
+ getColumnValue(r, row, HOST_ID_COL, host_id);
// dhcp_identifier : BYTEA NOT NULL
uint8_t identifier_value[DHCP_IDENTIFIER_MAX_LEN];
static_cast<Host::IdentifierType>(type);
// dhcp4_subnet_id : INT NULL
- uint32_t subnet_id;
- getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
+ uint32_t subnet_id;
+ getColumnValue(r, row, DHCP4_SUBNET_ID_COL, subnet_id);
SubnetID dhcp4_subnet_id = static_cast<SubnetID>(subnet_id);
// dhcp6_subnet_id : INT NULL
- getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
+ getColumnValue(r, row, DHCP6_SUBNET_ID_COL, subnet_id);
SubnetID dhcp6_subnet_id = static_cast<SubnetID>(subnet_id);
// ipv4_address : BIGINT NULL
- uint32_t addr4;
- getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
+ uint32_t addr4;
+ getColumnValue(r, row, IPV4_ADDRESS_COL, addr4);
isc::asiolink::IOAddress ipv4_reservation(addr4);
// hostname : VARCHAR(255) NULL
host.reset(new Host(identifier_value, identifier_len,
identifier_type, dhcp4_subnet_id,
dhcp6_subnet_id, ipv4_reservation, hostname,
- dhcp4_client_classes, dhcp6_client_classes));
+ dhcp4_client_classes, dhcp6_client_classes));
host->setHostId(host_id);
} catch (const isc::Exception& ex) {
isc_throw(DbOperationError, "Could not create host: " << ex.what());
}
-
+
return(host);
};
GET_HOST_DHCPID, // Gets hosts by host identifier
#endif
GET_HOST_ADDR, // Gets hosts by IPv4 address
-#if 0
GET_HOST_SUBID4_DHCPID, // Gets host by IPv4 SubnetID, HW address/DUID
+#if 0
GET_HOST_SUBID6_DHCPID, // Gets host by IPv6 SubnetID, HW address/DUID
+#endif
GET_HOST_SUBID_ADDR, // Gets host by IPv4 SubnetID and IPv4 address
+#if 0
GET_HOST_PREFIX, // Gets host by IPv6 prefix
#endif
GET_VERSION, // Obtain version number
/// @param bind Vector of MYSQL_BIND objects to be used when making the
/// query.
/// @param return_last_id flag indicating whether or not the insert
- /// returns the primary key of from the row inserted via " RETURNING
+ /// returns the primary key of from the row inserted via " RETURNING
/// <primary key> as pid" clause on the INSERT statement. The RETURNING
/// clause causes the INSERT to return a result set that should consist
/// of a single row with one column, the value of the primary key.
/// Defaults to false.
///
/// @returns 0 if return_last_id is false, otherwise it returns the
- /// the value in the result set in the first col of the first row.
+ /// the value in the result set in the first col of the first row.
///
/// @throw isc::dhcp::DuplicateEntry Database throws duplicate entry error
uint64_t addStatement(PgSqlHostDataSourceImpl::StatementIndex stindex,
- PsqlBindArrayPtr& bind,
+ PsqlBindArrayPtr& bind,
const bool return_last_id = false);
#if 0
/// retrieve hosts from the database.
PgSqlTaggedStatement tagged_statements[] = {
// Inserts a host into the 'hosts' table. Returns the inserted host id.
- {PgSqlHostDataSourceImpl::INSERT_HOST,
- { OID_INT8, OID_BYTEA, OID_INT2,
+ { 8, // PgSqlHostDataSourceImpl::INSERT_HOST,
+ { OID_BYTEA, OID_INT2,
OID_INT4, OID_INT4, OID_INT8, OID_VARCHAR,
- OID_VARCHAR, OID_VARCHAR },
- "INSERT INTO hosts(host_id, dhcp_identifier, dhcp_identifier_type, "
+ OID_VARCHAR, OID_VARCHAR }, "insert_host",
+ "INSERT INTO hosts(dhcp_identifier, dhcp_identifier_type, "
"dhcp4_subnet_id, dhcp6_subnet_id, ipv4_address, hostname, "
"dhcp4_client_classes, dhcp6_client_classes) "
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING host_id"},
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING host_id"},
#if 0
// Inserts a single IPv6 reservation into 'reservations' table.
// Retrieves host information along with the DHCPv4 options associated with
// it. Left joining the dhcp4_options table results in multiple rows being
// returned for the same host. The host is retrieved by IPv4 address.
- {PgSqlHostDataSourceImpl::GET_HOST_ADDR,
- { OID_INT8 },
+ { 1, // PgSqlHostDataSourceImpl::GET_HOST_ADDR,
+ { OID_INT8 }, "get_host_addr",
"SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
"h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
"h.dhcp4_client_classes, h.dhcp6_client_classes, "
"o.persistent "
"FROM hosts AS h "
"LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
- "WHERE ipv4_address = ? "
+ "WHERE ipv4_address = $1 "
"ORDER BY h.host_id, o.option_id"},
-#if 0
// Retrieves host information and DHCPv4 options using subnet identifier
// and client's identifier. Left joining the dhcp4_options table results in
// multiple rows being returned for the same host.
- {PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
- "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
- "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
- "o.option_id, o.code, o.value, o.formatted_value, o.space, "
- "o.persistent "
- "FROM hosts AS h "
- "LEFT JOIN dhcp4_options AS o "
- "ON h.host_id = o.host_id "
- "WHERE h.dhcp4_subnet_id = ? AND h.dhcp_identifier_type = ? "
- " AND h.dhcp_identifier = ? "
- "ORDER BY h.host_id, o.option_id"},
+ { 3, //PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
+ { OID_INT4, OID_INT2, OID_BYTEA }, "get_host_subid4_dhcpid",
+ "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
+ "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "o.option_id, o.code, o.value, o.formatted_value, o.space, "
+ "o.persistent "
+ "FROM hosts AS h "
+ "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
+ "WHERE h.dhcp4_subnet_id = $1 AND h.dhcp_identifier_type = $2 "
+ " AND h.dhcp_identifier = $3 "
+ "ORDER BY h.host_id, o.option_id"},
+#if 0
// Retrieves host information, IPv6 reservations and DHCPv6 options
// associated with a host. The number of rows returned is a multiplication
// of number of IPv6 reservations and DHCPv6 options.
"WHERE h.dhcp6_subnet_id = ? AND h.dhcp_identifier_type = ? "
"AND h.dhcp_identifier = ? "
"ORDER BY h.host_id, o.option_id, r.reservation_id"},
+#endif
// Retrieves host information and DHCPv4 options for the host using subnet
// identifier and IPv4 reservation. Left joining the dhcp4_options table
// results in multiple rows being returned for the host. The number of
// rows depends on the number of options defined for the host.
- {PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
- "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
- "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
- "h.dhcp4_client_classes, h.dhcp6_client_classes, "
- "o.option_id, o.code, o.value, o.formatted_value, o.space, "
- "o.persistent "
- "FROM hosts AS h "
- "LEFT JOIN dhcp4_options AS o "
- "ON h.host_id = o.host_id "
- "WHERE h.dhcp4_subnet_id = ? AND h.ipv4_address = ? "
- "ORDER BY h.host_id, o.option_id"},
+ { 2, //PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
+ { OID_INT4, OID_INT8 }, "get_host_subid_addr",
+ "SELECT h.host_id, h.dhcp_identifier, h.dhcp_identifier_type, "
+ "h.dhcp4_subnet_id, h.dhcp6_subnet_id, h.ipv4_address, h.hostname, "
+ "h.dhcp4_client_classes, h.dhcp6_client_classes, "
+ "o.option_id, o.code, o.value, o.formatted_value, o.space, "
+ "o.persistent "
+ "FROM hosts AS h "
+ "LEFT JOIN dhcp4_options AS o ON h.host_id = o.host_id "
+ "WHERE h.dhcp4_subnet_id = $1 AND h.ipv4_address = $2 "
+ "ORDER BY h.host_id, o.option_id"},
+#if 0
// Retrieves host information, IPv6 reservations and DHCPv6 options
// associated with a host using prefix and prefix length. This query
#endif
// Retrieves MySQL schema version.
- {PgSqlHostDataSourceImpl::GET_VERSION, { OID_NONE },
- "SELECT version, minor FROM schema_version"},
+ { 0, //PgSqlHostDataSourceImpl::GET_VERSION,
+ { OID_NONE }, "get_version",
+ "SELECT version, minor FROM schema_version"},
// Marks the end of the statements table.
- {PgSqlHostDataSourceImpl::NUM_STATEMENTS, { 0 }, NULL, NULL}
+ {0, { 0 }, NULL, NULL}
};
PgSqlHostDataSourceImpl::
// Add the subnet id.
bind_array->add(subnet_id);
- // Add the identifier value.
- bind_array->add(identifier_begin, identifier_len);
-
// Add the Identifier type.
bind_array->add(static_cast<uint8_t>(identifier_type));
+ // Add the identifier value.
+ bind_array->add(identifier_begin, identifier_len);
+
ConstHostCollection collection;
getHostCollection(stindex, bind_array, exchange, collection, true);
DHCPSRV_PGSQL_HOST_DB_GET_VERSION);
PgSqlResult r(PQexecPrepared(conn_, "get_version", 0, NULL, NULL, NULL, 0));
- conn_.checkStatementError(r, tagged_statements[GET_VERSION]);
+ conn_.checkStatementError(r, tagged_statements[GET_VERSION]);
istringstream tmp;
uint32_t version;
return (ConstHostPtr());
}
-#if 1
-ConstHostPtr
-PgSqlHostDataSource::get4(const SubnetID&,
- const Host::IdentifierType&,
- const uint8_t*,
- const size_t) const {
-
- return (HostPtr());
-}
-#else
ConstHostPtr
PgSqlHostDataSource::get4(const SubnetID& subnet_id,
const Host::IdentifierType& identifier_type,
const size_t identifier_len) const {
return (impl_->getHost(subnet_id, identifier_type, identifier_begin,
- identifier_len, PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
- impl_->host_exchange_));
+ identifier_len,
+ PgSqlHostDataSourceImpl::GET_HOST_SUBID4_DHCPID,
+ impl_->host_exchange_));
}
-#endif
-#if 1
-ConstHostPtr
-PgSqlHostDataSource::get4(const SubnetID&,
- const asiolink::IOAddress&) const {
- return(HostPtr());
-}
-#else
ConstHostPtr
PgSqlHostDataSource::get4(const SubnetID& subnet_id,
const asiolink::IOAddress& address) const {
ConstHostCollection collection;
impl_->getHostCollection(PgSqlHostDataSourceImpl::GET_HOST_SUBID_ADDR,
- inbind, impl_->host_exchange_, collection, true);
+ bind_array, impl_->host_exchange_, collection,
+ true);
// Return single record if present, else clear the host.
ConstHostPtr result;
return (result);
}
-#endif
#if 1
ConstHostPtr
--- /dev/null
+// Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/tests/test_utils.h>
+#include <exceptions/exceptions.h>
+#include <dhcpsrv/host.h>
+#include <dhcpsrv/pgsql_connection.h>
+#include <dhcpsrv/pgsql_host_data_source.h>
+#include <dhcpsrv/tests/generic_host_data_source_unittest.h>
+#include <dhcpsrv/testutils/pgsql_schema.h>
+#include <dhcpsrv/host_data_source_factory.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;
+using namespace isc::dhcp::test;
+using namespace std;
+
+namespace {
+
+class PgSqlHostDataSourceTest : public GenericHostDataSourceTest {
+public:
+ /// @brief Constructor
+ ///
+ /// Deletes everything from the database and opens it.
+ PgSqlHostDataSourceTest() {
+
+ // Ensure schema is the correct one.
+ destroyPgSQLSchema();
+ createPgSQLSchema();
+
+ // Connect to the database
+ try {
+ HostDataSourceFactory::create(validPgSQLConnectionString());
+ } catch (...) {
+ std::cerr << "*** ERROR: unable to open database. The test\n"
+ "*** environment is broken and must be fixed before\n"
+ "*** the PostgreSQL tests will run correctly.\n"
+ "*** The reason for the problem is described in the\n"
+ "*** accompanying exception output.\n";
+ throw;
+ }
+
+ hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ }
+
+ /// @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.
+ virtual ~PgSqlHostDataSourceTest() {
+ hdsptr_->rollback();
+ HostDataSourceFactory::destroy();
+ destroyPgSQLSchema();
+ }
+
+ /// @brief Reopen the database
+ ///
+ /// Closes the database and re-open it. Anything committed should be
+ /// visible.
+ ///
+ /// Parameter is ignored for PostgreSQL backend as the v4 and v6 leases share
+ /// the same database.
+ void reopen(Universe) {
+ HostDataSourceFactory::destroy();
+ HostDataSourceFactory::create(validPgSQLConnectionString());
+ hdsptr_ = HostDataSourceFactory::getHostDataSourcePtr();
+ }
+
+};
+
+/// @brief Check that database can be opened
+///
+/// This test checks if the PgSqlHostDataSource can be instantiated. This happens
+/// only if the database can be opened. Note that this is not part of the
+/// PgSqlLeaseMgr test fixure set. This test checks that the database can be
+/// opened: the fixtures assume that and check basic operations.
+
+TEST(PgSqlHostDataSource, OpenDatabase) {
+
+ // Schema needs to be created for the test to work.
+ destroyPgSQLSchema();
+ createPgSQLSchema();
+
+ // Check that lease manager open the database opens correctly and tidy up.
+ // If it fails, print the error message.
+ try {
+ HostDataSourceFactory::create(validPgSQLConnectionString());
+ EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
+ HostDataSourceFactory::destroy();
+ } catch (const isc::Exception& ex) {
+ FAIL() << "*** ERROR: unable to open database, reason:\n"
+ << " " << ex.what() << "\n"
+ << "*** The test environment is broken and must be fixed\n"
+ << "*** before the PostgreSQL tests will run correctly.\n";
+ }
+
+ // Check that lease manager open the database opens correctly with a longer
+ // timeout. If it fails, print the error message.
+ try {
+ string connection_string = validPgSQLConnectionString() + string(" ") +
+ string(VALID_TIMEOUT);
+ HostDataSourceFactory::create(connection_string);
+ EXPECT_NO_THROW((void) HostDataSourceFactory::getHostDataSourcePtr());
+ HostDataSourceFactory::destroy();
+ } catch (const isc::Exception& ex) {
+ FAIL() << "*** ERROR: unable to open database, reason:\n"
+ << " " << ex.what() << "\n"
+ << "*** The test environment is broken and must be fixed\n"
+ << "*** before the PostgreSQL tests will run correctly.\n";
+ }
+
+ // Check that attempting to get an instance of the lease manager when
+ // none is set throws an exception.
+ EXPECT_FALSE(HostDataSourceFactory::getHostDataSourcePtr());
+
+ // Check that wrong specification of backend throws an exception.
+ // (This is really a check on LeaseMgrFactory, but is convenient to
+ // perform here.)
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ 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);
+
+ // Check that invalid login data causes an exception.
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
+ DbOpenError);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
+ DbInvalidTimeout);
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
+ DbInvalidTimeout);
+
+ // Check for missing parameters
+ EXPECT_THROW(HostDataSourceFactory::create(connectionString(
+ PGSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+ NoDatabaseName);
+
+ // Tidy up after the test
+ destroyPgSQLSchema();
+}
+
+// Test verifies if a host reservation can be added and later retrieved by IPv4
+// address. Host uses hw address as identifier.
+TEST_F(PgSqlHostDataSourceTest, basic4HWAddr) {
+ testBasic4(Host::IDENT_HWADDR);
+}
+
+// Test verifies if a host reservation can be added and later retrieved by IPv4
+// address. Host uses client-id (DUID) as identifier.
+TEST_F(PgSqlHostDataSourceTest, basic4ClientId) {
+ testBasic4(Host::IDENT_DUID);
+}
+
+// Test verifies that multiple hosts can be added and later retrieved by their
+// reserved IPv4 address. This test uses HW addresses as identifiers.
+TEST_F(PgSqlHostDataSourceTest, getByIPv4HWaddr) {
+ testGetByIPv4(Host::IDENT_HWADDR);
+}
+
+// Test verifies that multiple hosts can be added and later retrieved by their
+// reserved IPv4 address. This test uses client-id (DUID) as identifiers.
+TEST_F(PgSqlHostDataSourceTest, getByIPv4ClientId) {
+ testGetByIPv4(Host::IDENT_DUID);
+}
+
+// Test verifies if a host reservation can be added and later retrieved by
+// hardware address.
+TEST_F(PgSqlHostDataSourceTest, get4ByHWaddr) {
+ testGet4ByIdentifier(Host::IDENT_HWADDR);
+}
+
+// Test verifies if a host reservation can be added and later retrieved by
+// DUID.
+TEST_F(PgSqlHostDataSourceTest, get4ByDUID) {
+ testGet4ByIdentifier(Host::IDENT_DUID);
+}
+
+// Test verifies if a host reservation can be added and later retrieved by
+// circuit id.
+TEST_F(PgSqlHostDataSourceTest, get4ByCircuitId) {
+ testGet4ByIdentifier(Host::IDENT_CIRCUIT_ID);
+}
+
+// Test verifies if hardware address and client identifier are not confused.
+TEST_F(PgSqlHostDataSourceTest, hwaddrNotClientId1) {
+ testHWAddrNotClientId();
+}
+
+// Test verifies if hardware address and client identifier are not confused.
+TEST_F(PgSqlHostDataSourceTest, hwaddrNotClientId2) {
+ testClientIdNotHWAddr();
+}
+
+// Test verifies if a host with FQDN hostname can be stored and later retrieved.
+TEST_F(PgSqlHostDataSourceTest, hostnameFQDN) {
+ testHostname("foo.example.org", 1);
+}
+
+// Test verifies if 100 hosts with unique FQDN hostnames can be stored and later
+// retrieved.
+TEST_F(PgSqlHostDataSourceTest, hostnameFQDN100) {
+ testHostname("foo.example.org", 100);
+}
+
+// Test verifies if a host without any hostname specified can be stored and
+// later retrieved.
+TEST_F(PgSqlHostDataSourceTest, noHostname) {
+ testHostname("", 1);
+}
+
+// Test verifies if the hardware or client-id query can match hardware address.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
+ /// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
+ /// be discussed.
+ ///
+ /// @todo: Add host reservation with hardware address X, try to retrieve
+ /// host for hardware address X or client identifier Y, verify that the
+ /// reservation is returned.
+}
+
+// Test verifies if the hardware or client-id query can match client-id.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId2) {
+ /// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
+ /// be discussed.
+ ///
+ /// @todo: Add host reservation with client identifier Y, try to retrieve
+ /// host for hardware address X or client identifier Y, verify that the
+ /// reservation is returned.
+}
+
+#if 0
+// Test verifies that host with IPv6 address and DUID can be added and
+// later retrieved by IPv6 address.
+TEST_F(PgSqlHostDataSourceTest, get6AddrWithDuid) {
+ testGetByIPv6(Host::IDENT_DUID, false);
+}
+
+// Test verifies that host with IPv6 address and HWAddr can be added and
+// later retrieved by IPv6 address.
+TEST_F(PgSqlHostDataSourceTest, get6AddrWithHWAddr) {
+ testGetByIPv6(Host::IDENT_HWADDR, false);
+}
+
+// Test verifies that host with IPv6 prefix and DUID can be added and
+// later retrieved by IPv6 prefix.
+TEST_F(PgSqlHostDataSourceTest, get6PrefixWithDuid) {
+ testGetByIPv6(Host::IDENT_DUID, true);
+}
+
+// Test verifies that host with IPv6 prefix and HWAddr can be added and
+// later retrieved by IPv6 prefix.
+TEST_F(PgSqlHostDataSourceTest, get6PrefixWithHWaddr) {
+ testGetByIPv6(Host::IDENT_HWADDR, true);
+}
+
+// Test verifies if a host reservation can be added and later retrieved by
+// hardware address.
+TEST_F(PgSqlHostDataSourceTest, get6ByHWaddr) {
+ testGet6ByHWAddr();
+}
+
+// Test verifies if a host reservation can be added and later retrieved by
+// client identifier.
+TEST_F(PgSqlHostDataSourceTest, get6ByClientId) {
+ testGet6ByClientId();
+}
+
+// Test verifies if a host reservation can be stored with both IPv6 address and
+// prefix.
+TEST_F(PgSqlHostDataSourceTest, addr6AndPrefix) {
+ testAddr6AndPrefix();
+}
+
+// Tests if host with multiple IPv6 reservations can be added and then
+// retrieved correctly. Test checks reservations comparing.
+TEST_F(PgSqlHostDataSourceTest, multipleReservations){
+ testMultipleReservations();
+}
+
+// Tests if compareIPv6Reservations() method treats same pool of reservations
+// but added in different order as equal.
+TEST_F(PgSqlHostDataSourceTest, multipleReservationsDifferentOrder){
+ testMultipleReservationsDifferentOrder();
+}
+
+// Test verifies if multiple client classes for IPv4 can be stored.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_multipleClientClasses4) {
+ /// @todo: Implement this test as part of #4213.
+
+ /// Add host reservation with a multiple v4 client-classes, retrieve it and
+ /// make sure that all client classes are retrieved properly.
+}
+
+// Test verifies if multiple client classes for IPv6 can be stored.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_multipleClientClasses6) {
+ /// @todo: Implement this test as part of #4213.
+
+ /// Add host reservation with a multiple v6 client-classes, retrieve it and
+ /// make sure that all client classes are retrieved properly.
+}
+
+// Test verifies if multiple client classes for both IPv4 and IPv6 can be stored.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_multipleClientClassesBoth) {
+ /// @todo: Implement this test as part of #4213.
+
+ /// 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 if the same host can have reservations in different subnets (with the
+// same hardware address). The test logic is as follows:
+// Insert 10 host reservations for a given physical host (the same
+// hardware address), but for different subnets (different subnet-ids).
+// Make sure that getAll() returns them all correctly.
+TEST_F(PgSqlHostDataSourceTest, multipleSubnetsHWAddr) {
+ testMultipleSubnets(10, Host::IDENT_HWADDR);
+}
+
+// Test if the same host can have reservations in different subnets (with the
+// same client identifier). The test logic is as follows:
+//
+// Insert 10 host reservations for a given physical host (the same
+// client-identifier), but for different subnets (different subnet-ids).
+// Make sure that getAll() returns them correctly.
+TEST_F(PgSqlHostDataSourceTest, multipleSubnetsClientId) {
+ testMultipleSubnets(10, Host::IDENT_DUID);
+}
+
+// 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.
+TEST_F(PgSqlHostDataSourceTest, subnetId6) {
+ testSubnetId6(10, Host::IDENT_HWADDR);
+}
+
+// Test if the duplicate 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.
+// Hosts with same DUID.
+TEST_F(PgSqlHostDataSourceTest, addDuplicate6WithDUID) {
+ testAddDuplicate6WithSameDUID();
+}
+
+// Test if the duplicate 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.
+// Hosts with same HWAddr.
+TEST_F(PgSqlHostDataSourceTest, 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
+// verify that the second and following attempts will throw exceptions.
+TEST_F(PgSqlHostDataSourceTest, addDuplicate4) {
+ testAddDuplicate4();
+}
+
+// This test verifies that DHCPv4 options can be inserted in a binary format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, optionsReservations4) {
+ testOptionsReservations4(false);
+}
+
+// This test verifies that DHCPv6 options can be inserted in a binary format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, optionsReservations6) {
+ testOptionsReservations6(false);
+}
+
+// This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
+/// binary format and retrieved with a single query to the database.
+TEST_F(PgSqlHostDataSourceTest, optionsReservations46) {
+ testOptionsReservations46(false);
+}
+
+// This test verifies that DHCPv4 options can be inserted in a textual format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations4) {
+ testOptionsReservations4(true);
+}
+
+// This test verifies that DHCPv6 options can be inserted in a textual format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations6) {
+ testOptionsReservations6(true);
+}
+
+// This test verifies that DHCPv4 and DHCPv6 options can be inserted in a
+// textual format and retrieved with a single query to the database.
+TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations46) {
+ testOptionsReservations46(true);
+}
+
+// This test checks transactional insertion of the host information
+// into the database. The failure to insert host information at
+// any stage should cause the whole transaction to be rolled back.
+TEST_F(PgSqlHostDataSourceTest, testAddRollback) {
+ // Make sure we have the pointer to the host data source.
+ ASSERT_TRUE(hdsptr_);
+
+ // To test the transaction rollback mechanism we need to cause the
+ // insertion of host information to fail at some stage. The 'hosts'
+ // table should be updated correctly but the failure should occur
+ // when inserting reservations or options. The simplest way to
+ // achieve that is to simply drop one of the tables. To do so, we
+ // connect to the database and issue a DROP query.
+ PgSqlConnection::ParameterMap params;
+ params["name"] = "keatest";
+ params["user"] = "keatest";
+ params["password"] = "keatest";
+ PgSqlConnection conn(params);
+ ASSERT_NO_THROW(conn.openDatabase());
+ int status = mysql_query(conn.mysql_,
+ "DROP TABLE IF EXISTS ipv6_reservations");
+ ASSERT_EQ(0, status) << mysql_error(conn.mysql_);
+
+ // Create a host with a reservation.
+ HostPtr host = initializeHost6("2001:db8:1::1", Host::IDENT_HWADDR, false);
+ // Let's assign some DHCPv4 subnet to the host, because we will use the
+ // DHCPv4 subnet to try to retrieve the host after failed insertion.
+ host->setIPv4SubnetID(SubnetID(4));
+
+ // There is no ipv6_reservations table, so the insertion should fail.
+ ASSERT_THROW(hdsptr_->add(host), DbOperationError);
+
+ // Even though we have created a DHCPv6 host, we can't use get6()
+ // method to retrieve the host from the database, because the
+ // query would expect that the ipv6_reservations table is present.
+ // Therefore, the query would fail. Instead, we use the get4 method
+ // which uses the same client identifier, but doesn't attempt to
+ // 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.
+ ConstHostPtr from_hds = hdsptr_->get4(host->getIPv4SubnetID(),
+ host->getIdentifierType(),
+ &host->getIdentifier()[0],
+ host->getIdentifier().size());
+ EXPECT_FALSE(from_hds);
+}
+#endif
+
+}; // Of anonymous namespace