]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1074] added unittests
authorRazvan Becheriu <razvan@isc.org>
Mon, 13 Jan 2020 11:51:08 +0000 (13:51 +0200)
committerRazvan Becheriu <razvan@isc.org>
Wed, 5 Feb 2020 21:00:32 +0000 (23:00 +0200)
src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc

index 0dbc0f46beb98e6a8c62c4433f361082851247ef..08608fecba29ecc5746b6882ff2574bd8133fc60 100644 (file)
@@ -17,6 +17,7 @@
 #include <dhcpsrv/host_data_source_factory.h>
 #include <pgsql/pgsql_connection.h>
 #include <pgsql/testutils/pgsql_schema.h>
+#include <util/multi_threading_mgr.h>
 
 #include <gtest/gtest.h>
 
@@ -33,6 +34,7 @@ using namespace isc::db::test;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::data;
+using namespace isc::util;
 using namespace std;
 
 namespace {
@@ -58,6 +60,8 @@ public:
         }
 
         hdsptr_ = HostMgr::instance().getHostDataSource();
+
+        MultiThreadingMgr::instance().setMode(false);
     }
 
     /// @brief Destroys the HDS and the schema.
@@ -154,6 +158,90 @@ public:
 /// 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 host manager open the database opens correctly and tidy up.
+    //  If it fails, print the error message.
+    try {
+        HostMgr::create();
+        EXPECT_NO_THROW(HostMgr::addBackend(validPgSQLConnectionString()));
+        HostMgr::delBackend("postgresql");
+    } 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 host 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);
+        HostMgr::create();
+        EXPECT_NO_THROW(HostMgr::addBackend(connection_string));
+        HostMgr::delBackend("postgresql");
+    } 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 host data source when
+    // none is set throws an exception.
+    EXPECT_FALSE(HostMgr::instance().getHostDataSource());
+
+    // Check that wrong specification of backend throws an exception.
+    // (This is really a check on HostDataSourceFactory, but is convenient to
+    // perform here.)
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        NULL, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+        InvalidParameter);
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        INVALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+        InvalidType);
+
+    // Check that invalid login data causes an exception.
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, INVALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD)),
+        DbOpenError);
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
+        DbOpenError);
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+        DbOpenError);
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, INVALID_PASSWORD)),
+        DbOpenError);
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_1)),
+        DbInvalidTimeout);
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, VALID_NAME, VALID_HOST, VALID_USER, VALID_PASSWORD, INVALID_TIMEOUT_2)),
+        DbInvalidTimeout);
+
+    // Check for missing parameters
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, NULL, VALID_HOST, INVALID_USER, VALID_PASSWORD)),
+        NoDatabaseName);
+
+    // Tidy up after the test
+    destroyPgSQLSchema();
+}
+
+/// @brief Check that database can be opened with Multi-Threading
+///
+/// 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
+/// PgSqlHostMgr test fixture set.  This test checks that the database can be
+/// opened: the fixtures assume that and check basic operations.
+TEST(PgSqlHostDataSource, OpenDatabaseMultiThreading) {
+    // Enable Multi-Threading.
+    MultiThreadingMgr::instance().setMode(true);
 
     // Schema needs to be created for the test to work.
     destroyPgSQLSchema();
@@ -262,179 +350,409 @@ TEST(PgSqlHostDataSource, NoCallbackOnOpenFail) {
     destroyPgSQLSchema();
 }
 
+/// @brief Make sure open failures do NOT invoke db lost callback
+/// The db lost callback should only be invoked after successfully
+/// opening the DB and then subsequently losing it. Failing to
+/// open should be handled directly by the application layer.
+/// There is simply no good way to break the connection in a
+/// unit test environment.  So testing the callback invocation
+/// in a unit test is next to impossible. That has to be done
+/// as a system test.
+TEST(PgSqlHostDataSource, NoCallbackOnOpenFailMultiThreading) {
+    // Enable Multi-Threading.
+    MultiThreadingMgr::instance().setMode(true);
+
+    // Schema needs to be created for the test to work.
+    destroyPgSQLSchema();
+    createPgSQLSchema();
+
+    callback_called = false;
+    DatabaseConnection::db_lost_callback = db_lost_callback;
+    HostMgr::create();
+    EXPECT_THROW(HostMgr::addBackend(connectionString(
+        PGSQL_VALID_TYPE, VALID_NAME, INVALID_HOST, VALID_USER, VALID_PASSWORD)),
+                 DbOpenError);
+
+    EXPECT_FALSE(callback_called);
+    destroyPgSQLSchema();
+}
+
 // This test verifies that database backend can operate in Read-Only mode.
 TEST_F(PgSqlHostDataSourceTest, testReadOnlyDatabase) {
     testReadOnlyDatabase(PGSQL_VALID_TYPE);
 }
 
+// This test verifies that database backend can operate in Read-Only mode.
+TEST_F(PgSqlHostDataSourceTest, testReadOnlyDatabaseMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testReadOnlyDatabase(PGSQL_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(PgSqlHostDataSourceTest, basic4HWAddr) {
     testBasic4(Host::IDENT_HWADDR);
 }
 
+// Test verifies if a host reservation can be added and later retrieved by IPv4
+// address. Host uses hw address as identifier.
+TEST_F(PgSqlHostDataSourceTest, basic4HWAddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testBasic4(Host::IDENT_HWADDR);
+}
+
 // Verifies that IPv4 host reservation with options can have a the global
 // subnet id value
 TEST_F(PgSqlHostDataSourceTest, globalSubnetId4) {
     testGlobalSubnetId4();
 }
 
+// Verifies that IPv4 host reservation with options can have a the global
+// subnet id value
+TEST_F(PgSqlHostDataSourceTest, globalSubnetId4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGlobalSubnetId4();
+}
+
 // Verifies that IPv6 host reservation with options can have a the global
 // subnet id value
 TEST_F(PgSqlHostDataSourceTest, globalSubnetId6) {
     testGlobalSubnetId6();
 }
 
+// Verifies that IPv6 host reservation with options can have a the global
+// subnet id value
+TEST_F(PgSqlHostDataSourceTest, globalSubnetId6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGlobalSubnetId6();
+}
+
 // Verifies that IPv4 host reservation with options can have a max value
 // for  dhcp4_subnet id
 TEST_F(PgSqlHostDataSourceTest, maxSubnetId4) {
     testMaxSubnetId4();
 }
 
+// Verifies that IPv4 host reservation with options can have a max value
+// for  dhcp4_subnet id
+TEST_F(PgSqlHostDataSourceTest, maxSubnetId4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMaxSubnetId4();
+}
+
 // Verifies that IPv6 host reservation with options can have a max value
 // for  dhcp6_subnet id
 TEST_F(PgSqlHostDataSourceTest, maxSubnetId6) {
     testMaxSubnetId6();
 }
 
+// Verifies that IPv6 host reservation with options can have a max value
+// for  dhcp6_subnet id
+TEST_F(PgSqlHostDataSourceTest, maxSubnetId6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMaxSubnetId6();
+}
+
 // Verifies that IPv4 host reservations in the same subnet can be retrieved
 TEST_F(PgSqlHostDataSourceTest, getAll4BySubnet) {
     testGetAll4();
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAll4BySubnetMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetAll4();
+}
+
 // Verifies that IPv6 host reservations in the same subnet can be retrieved
 TEST_F(PgSqlHostDataSourceTest, getAll6BySubnet) {
     testGetAll6();
 }
 
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAll6BySubnetMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetAll6();
+}
+
 // Verifies that host reservations with the same hostname can be retrieved
 TEST_F(PgSqlHostDataSourceTest, getAllbyHostname) {
     testGetAllbyHostname();
 }
 
+// Verifies that host reservations with the same hostname can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAllbyHostnameMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetAllbyHostname();
+}
+
 // Verifies that IPv4 host reservations with the same hostname and in
 // the same subnet can be retrieved
 TEST_F(PgSqlHostDataSourceTest, getAllbyHostnameSubnet4) {
     testGetAllbyHostnameSubnet4();
 }
 
+// Verifies that IPv4 host reservations with the same hostname and in
+// the same subnet can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAllbyHostnameSubnet4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetAllbyHostnameSubnet4();
+}
+
 // Verifies that IPv6 host reservations with the same hostname and in
 // the same subnet can be retrieved
 TEST_F(PgSqlHostDataSourceTest, getAllbyHostnameSubnet6) {
     testGetAllbyHostnameSubnet6();
 }
 
+// Verifies that IPv6 host reservations with the same hostname and in
+// the same subnet can be retrieved
+TEST_F(PgSqlHostDataSourceTest, getAllbyHostnameSubnet6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetAllbyHostnameSubnet6();
+}
+
 // Verifies that IPv4 host reservations in the same subnet can be retrieved
 // by pages.
 TEST_F(PgSqlHostDataSourceTest, getPage4) {
     testGetPage4();
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+// by pages.
+TEST_F(PgSqlHostDataSourceTest, getPage4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetPage4();
+}
+
 // Verifies that IPv6 host reservations in the same subnet can be retrieved
 // by pages.
 TEST_F(PgSqlHostDataSourceTest, getPage6) {
     testGetPage6();
 }
 
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+// by pages.
+TEST_F(PgSqlHostDataSourceTest, getPage6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetPage6();
+}
+
 // Verifies that IPv4 host reservations in the same subnet can be retrieved
 // by pages without truncation from the limit.
 TEST_F(PgSqlHostDataSourceTest, getPageLimit4) {
     testGetPageLimit4(Host::IDENT_DUID);
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+// by pages without truncation from the limit.
+TEST_F(PgSqlHostDataSourceTest, getPageLimit4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetPageLimit4(Host::IDENT_DUID);
+}
+
 // Verifies that IPv6 host reservations in the same subnet can be retrieved
 // by pages without truncation from the limit.
 TEST_F(PgSqlHostDataSourceTest, getPageLimit6) {
     testGetPageLimit6(Host::IDENT_HWADDR);
 }
 
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+// by pages without truncation from the limit.
+TEST_F(PgSqlHostDataSourceTest, getPageLimit6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetPageLimit6(Host::IDENT_HWADDR);
+}
+
 // Verifies that IPv4 host reservations in the same subnet can be retrieved
 // by pages even with multiple subnets.
 TEST_F(PgSqlHostDataSourceTest, getPage4Subnets) {
     testGetPage4Subnets();
 }
 
+// Verifies that IPv4 host reservations in the same subnet can be retrieved
+// by pages even with multiple subnets.
+TEST_F(PgSqlHostDataSourceTest, getPage4SubnetsMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetPage4Subnets();
+}
+
 // Verifies that IPv6 host reservations in the same subnet can be retrieved
 // by pages even with multiple subnets.
 TEST_F(PgSqlHostDataSourceTest, getPage6Subnets) {
     testGetPage6Subnets();
 }
 
+// Verifies that IPv6 host reservations in the same subnet can be retrieved
+// by pages even with multiple subnets.
+TEST_F(PgSqlHostDataSourceTest, getPage6SubnetsMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetPage6Subnets();
+}
+
 // 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 if a host reservation can be added and later retrieved by IPv4
+// address. Host uses client-id (DUID) as identifier.
+TEST_F(PgSqlHostDataSourceTest, basic4ClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 HW addresses as identifiers.
+TEST_F(PgSqlHostDataSourceTest, getByIPv4HWaddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 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, getByIPv4ClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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
+// hardware address.
+TEST_F(PgSqlHostDataSourceTest, get4ByHWaddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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
+// DUID.
+TEST_F(PgSqlHostDataSourceTest, get4ByDUIDMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 a host reservation can be added and later retrieved by
+// circuit id.
+TEST_F(PgSqlHostDataSourceTest, get4ByCircuitIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGet4ByIdentifier(Host::IDENT_CIRCUIT_ID);
+}
+
 // Test verifies if a host reservation can be added and later retrieved by
 // client-id.
 TEST_F(PgSqlHostDataSourceTest, get4ByClientId) {
     testGet4ByIdentifier(Host::IDENT_CLIENT_ID);
 }
 
+// Test verifies if a host reservation can be added and later retrieved by
+// client-id.
+TEST_F(PgSqlHostDataSourceTest, get4ByClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGet4ByIdentifier(Host::IDENT_CLIENT_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, hwaddrNotClientId1MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testHWAddrNotClientId();
+}
+
 // Test verifies if hardware address and client identifier are not confused.
 TEST_F(PgSqlHostDataSourceTest, hwaddrNotClientId2) {
     testClientIdNotHWAddr();
 }
 
+// Test verifies if hardware address and client identifier are not confused.
+TEST_F(PgSqlHostDataSourceTest, hwaddrNotClientId2MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 a host with FQDN hostname can be stored and later retrieved.
+TEST_F(PgSqlHostDataSourceTest, hostnameFQDNMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 100 hosts with unique FQDN hostnames can be stored and later
+// retrieved.
+TEST_F(PgSqlHostDataSourceTest, hostnameFQDN100MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 a host without any hostname specified can be stored and later
+// retrieved.
+TEST_F(PgSqlHostDataSourceTest, noHostnameMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testHostname("", 1);
+}
+
 // Test verifies if a host with user context can be stored and later retrieved.
 TEST_F(PgSqlHostDataSourceTest, usercontext) {
     string comment = "{ \"comment\": \"a host reservation\" }";
     testUserContext(Element::fromJSON(comment));
 }
 
+// Test verifies if a host with user context can be stored and later retrieved.
+TEST_F(PgSqlHostDataSourceTest, usercontextMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
     /// @todo: The logic behind ::get4(subnet_id, hwaddr, duid) call needs to
@@ -445,6 +763,17 @@ TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId1) {
     /// reservation is returned.
 }
 
+// Test verifies if the hardware or client-id query can match hardware address.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId1MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    /// @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
@@ -455,63 +784,144 @@ TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId2) {
     /// reservation is returned.
 }
 
+// Test verifies if the hardware or client-id query can match client-id.
+TEST_F(PgSqlHostDataSourceTest, DISABLED_hwaddrOrClientId2MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    /// @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.
+}
+
 // 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 DUID can be added and
+// later retrieved by IPv6 address.
+TEST_F(PgSqlHostDataSourceTest, get6AddrWithDuidMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 address and HWAddr can be added and
+// later retrieved by IPv6 address.
+TEST_F(PgSqlHostDataSourceTest, get6AddrWithHWAddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 DUID can be added and
+// later retrieved by IPv6 prefix.
+TEST_F(PgSqlHostDataSourceTest, get6PrefixWithDuidMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 that host with IPv6 prefix and HWAddr can be added and
+// later retrieved by IPv6 prefix.
+TEST_F(PgSqlHostDataSourceTest, get6PrefixWithHWaddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetByIPv6(Host::IDENT_HWADDR, true);
+}
+
 // Test verifies that host with IPv6 prefix reservation can be retrieved
 // by subnet id and prefix value.
 TEST_F(PgSqlHostDataSourceTest, get6SubnetPrefix) {
     testGetBySubnetIPv6();
 }
 
+// Test verifies that host with IPv6 prefix reservation can be retrieved
+// by subnet id and prefix value.
+TEST_F(PgSqlHostDataSourceTest, get6SubnetPrefixMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGetBySubnetIPv6();
+}
+
 // 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
+// hardware address.
+TEST_F(PgSqlHostDataSourceTest, get6ByHWaddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 added and later retrieved by
+// client identifier.
+TEST_F(PgSqlHostDataSourceTest, get6ByClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testGet6ByClientId();
+}
+
 // Test verifies if a host reservation can be stored with both IPv6 address and
 // prefix.
 TEST_F(PgSqlHostDataSourceTest, addr6AndPrefix) {
     testAddr6AndPrefix();
 }
 
+// Test verifies if a host reservation can be stored with both IPv6 address and
+// prefix.
+TEST_F(PgSqlHostDataSourceTest, addr6AndPrefixMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testAddr6AndPrefix();
+}
+
 // Tests if host with multiple IPv6 reservations can be added and then
 // retrieved correctly. Test checks reservations comparing.
-TEST_F(PgSqlHostDataSourceTest, multipleReservations){
+TEST_F(PgSqlHostDataSourceTest, multipleReservations) {
     testMultipleReservations();
 }
 
+// Tests if host with multiple IPv6 reservations can be added and then
+// retrieved correctly. Test checks reservations comparing.
+TEST_F(PgSqlHostDataSourceTest, multipleReservationsMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleReservations();
+}
+
+// Tests if compareIPv6Reservations() method treats same pool of reservations
+// but added in different order as equal.
+TEST_F(PgSqlHostDataSourceTest, multipleReservationsDifferentOrder) {
+    testMultipleReservationsDifferentOrder();
+}
+
 // Tests if compareIPv6Reservations() method treats same pool of reservations
 // but added in different order as equal.
-TEST_F(PgSqlHostDataSourceTest, multipleReservationsDifferentOrder){
+TEST_F(PgSqlHostDataSourceTest, multipleReservationsDifferentOrderMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
     testMultipleReservationsDifferentOrder();
 }
 
@@ -521,18 +931,39 @@ TEST_F(PgSqlHostDataSourceTest, multipleClientClasses4) {
     testMultipleClientClasses4();
 }
 
+// Test that multiple client classes for IPv4 can be inserted and
+// retrieved for a given host reservation.
+TEST_F(PgSqlHostDataSourceTest, multipleClientClasses4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleClientClasses4();
+}
+
 // Test that multiple client classes for IPv6 can be inserted and
 // retrieved for a given host reservation.
 TEST_F(PgSqlHostDataSourceTest, multipleClientClasses6) {
     testMultipleClientClasses6();
 }
 
+// Test that multiple client classes for IPv6 can be inserted and
+// retrieved for a given host reservation.
+TEST_F(PgSqlHostDataSourceTest, multipleClientClasses6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleClientClasses6();
+}
+
 // Test that multiple client classes for both IPv4 and IPv6 can
 // be inserted and retrieved for a given host reservation.
 TEST_F(PgSqlHostDataSourceTest, multipleClientClassesBoth) {
     testMultipleClientClassesBoth();
 }
 
+// Test that multiple client classes for both IPv4 and IPv6 can
+// be inserted and retrieved for a given host reservation.
+TEST_F(PgSqlHostDataSourceTest, multipleClientClassesBothMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleClientClassesBoth();
+}
+
 // 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
@@ -542,6 +973,16 @@ TEST_F(PgSqlHostDataSourceTest, multipleSubnetsHWAddr) {
     testMultipleSubnets(10, Host::IDENT_HWADDR);
 }
 
+// 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, multipleSubnetsHWAddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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:
 //
@@ -552,6 +993,17 @@ TEST_F(PgSqlHostDataSourceTest, multipleSubnetsClientId) {
     testMultipleSubnets(10, Host::IDENT_DUID);
 }
 
+// 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, multipleSubnetsClientIdMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleSubnets(10, Host::IDENT_DUID);
+}
+
 // Test if host reservations made for different IPv6 subnets are handled correctly.
 // The test logic is as follows:
 //
@@ -561,6 +1013,16 @@ TEST_F(PgSqlHostDataSourceTest, subnetId6) {
     testSubnetId6(10, Host::IDENT_HWADDR);
 }
 
+// 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, subnetId6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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.
@@ -569,6 +1031,15 @@ 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 DUID.
+TEST_F(PgSqlHostDataSourceTest, addDuplicate6WithDUIDMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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.
@@ -577,6 +1048,15 @@ TEST_F(PgSqlHostDataSourceTest, addDuplicate6WithHWAddr) {
     testAddDuplicate6WithSameHWAddr();
 }
 
+// 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, addDuplicate6WithHWAddrMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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.
@@ -584,6 +1064,14 @@ TEST_F(PgSqlHostDataSourceTest, addDuplicate4) {
     testAddDuplicate4();
 }
 
+// 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, addDuplicate4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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) {
@@ -591,6 +1079,14 @@ TEST_F(PgSqlHostDataSourceTest, optionsReservations4) {
     testOptionsReservations4(false, Element::fromJSON(comment));
 }
 
+// This test verifies that DHCPv4 options can be inserted in a binary format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, optionsReservations4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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 PostgreSQL host database.
 TEST_F(PgSqlHostDataSourceTest, optionsReservations6) {
@@ -598,12 +1094,27 @@ TEST_F(PgSqlHostDataSourceTest, optionsReservations6) {
     testOptionsReservations6(false, Element::fromJSON(comment));
 }
 
+// This test verifies that DHCPv6 options can be inserted in a binary format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, optionsReservations6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    string comment = "{ \"comment\": \"a host reservation\" }";
+    testOptionsReservations6(false, Element::fromJSON(comment));
+}
+
 // 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 and DHCPv6 options can be inserted in a
+/// binary format and retrieved with a single query to the database.
+TEST_F(PgSqlHostDataSourceTest, optionsReservations46MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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) {
@@ -611,6 +1122,14 @@ TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations4) {
     testOptionsReservations4(true, Element::fromJSON(comment));
 }
 
+// This test verifies that DHCPv4 options can be inserted in a textual format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(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 PostgreSQL host database.
 TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations6) {
@@ -618,12 +1137,27 @@ TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations6) {
     testOptionsReservations6(true, Element::fromJSON(comment));
 }
 
+// This test verifies that DHCPv6 options can be inserted in a textual format
+/// and retrieved from the PostgreSQL host database.
+TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(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
 // textual format and retrieved with a single query to the database.
 TEST_F(PgSqlHostDataSourceTest, formattedOptionsReservations46) {
     testOptionsReservations46(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, formattedOptionsReservations46MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    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.
@@ -673,48 +1207,150 @@ TEST_F(PgSqlHostDataSourceTest, testAddRollback) {
     EXPECT_FALSE(from_hds);
 }
 
+// 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, testAddRollbackMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    // 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());
+
+    PgSqlResult r(PQexec(conn, "DROP TABLE IF EXISTS ipv6_reservations"));
+    ASSERT_TRUE (PQresultStatus(r) == PGRES_COMMAND_OK)
+                 << " drop command failed :" << PQerrorMessage(conn);
+
+    // Create a host with a reservation.
+    HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::1",
+                                        Host::IDENT_HWADDR, false, "randomKey");
+    // 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);
+}
+
 // This test checks that siaddr, sname, file fields can be retrieved
 /// from a database for a host.
 TEST_F(PgSqlHostDataSourceTest, messageFields) {
     testMessageFields4();
 }
 
+// This test checks that siaddr, sname, file fields can be retrieved
+/// from a database for a host.
+TEST_F(PgSqlHostDataSourceTest, messageFieldsMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMessageFields4();
+}
+
 // Check that delete(subnet-id, addr4) works.
 TEST_F(PgSqlHostDataSourceTest, deleteByAddr4) {
     testDeleteByAddr4();
 }
 
+// Check that delete(subnet-id, addr4) works.
+TEST_F(PgSqlHostDataSourceTest, deleteByAddr4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteByAddr4();
+}
+
 // Check that delete(subnet4-id, identifier-type, identifier) works.
 TEST_F(PgSqlHostDataSourceTest, deleteById4) {
     testDeleteById4();
 }
 
+// Check that delete(subnet4-id, identifier-type, identifier) works.
+TEST_F(PgSqlHostDataSourceTest, deleteById4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteById4();
+}
+
 // Check that delete(subnet4-id, identifier-type, identifier) works,
 // even when options are present.
 TEST_F(PgSqlHostDataSourceTest, deleteById4Options) {
     testDeleteById4Options();
 }
 
+// Check that delete(subnet4-id, identifier-type, identifier) works,
+// even when options are present.
+TEST_F(PgSqlHostDataSourceTest, deleteById4OptionsMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteById4Options();
+}
+
 // Check that delete(subnet6-id, identifier-type, identifier) works.
 TEST_F(PgSqlHostDataSourceTest, deleteById6) {
     testDeleteById6();
 }
 
+// Check that delete(subnet6-id, identifier-type, identifier) works.
+TEST_F(PgSqlHostDataSourceTest, deleteById6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteById6();
+}
+
 // Check that delete(subnet6-id, identifier-type, identifier) works,
 // even when options are present.
 TEST_F(PgSqlHostDataSourceTest, deleteById6Options) {
     testDeleteById6Options();
 }
 
+// Check that delete(subnet6-id, identifier-type, identifier) works,
+// even when options are present.
+TEST_F(PgSqlHostDataSourceTest, deleteById6OptionsMultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testDeleteById6Options();
+}
+
 // Tests that multiple reservations without IPv4 addresses can be
 // specified within a subnet.
 TEST_F(PgSqlHostDataSourceTest, testMultipleHostsNoAddress4) {
     testMultipleHostsNoAddress4();
 }
 
+// Tests that multiple reservations without IPv4 addresses can be
+// specified within a subnet.
+TEST_F(PgSqlHostDataSourceTest, testMultipleHostsNoAddress4MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleHostsNoAddress4();
+}
+
 // Tests that multiple hosts can be specified within an IPv6 subnet.
 TEST_F(PgSqlHostDataSourceTest, testMultipleHosts6) {
     testMultipleHosts6();
 }
 
+// Tests that multiple hosts can be specified within an IPv6 subnet.
+TEST_F(PgSqlHostDataSourceTest, testMultipleHosts6MultiThreading) {
+    MultiThreadingMgr::instance().setMode(true);
+    testMultipleHosts6();
+}
+
 }  // namespace