From: Razvan Becheriu Date: Mon, 13 Jan 2020 11:51:08 +0000 (+0200) Subject: [#1074] added unittests X-Git-Tag: Kea-1.7.5~85 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf03df625dcb903ef396ddf454f5fa5f79eb3337;p=thirdparty%2Fkea.git [#1074] added unittests --- 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 0dbc0f46be..08608fecba 100644 --- a/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc +++ b/src/lib/dhcpsrv/tests/pgsql_host_data_source_unittest.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -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