// Copyright (C) 2015-2023 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace isc::asiolink; using namespace isc::db; using namespace isc::db::test; using namespace isc::util; using namespace isc::data; namespace ph = std::placeholders; namespace isc { namespace dhcp { namespace test { GenericHostDataSourceTest::GenericHostDataSourceTest() : GenericBackendTest(), hdsptr_() { } GenericHostDataSourceTest::~GenericHostDataSourceTest() { hdsptr_.reset(); } bool GenericHostDataSourceTest::compareHostsForSort4(const ConstHostPtr& host1, const ConstHostPtr& host2) { if (host1->getIPv4SubnetID() < host2->getIPv4SubnetID()) { return true; } return false; } bool GenericHostDataSourceTest::compareHostsForSort6(const ConstHostPtr& host1, const ConstHostPtr& host2) { if (host1->getIPv6SubnetID() < host2->getIPv6SubnetID()) { return true; } return false; } bool GenericHostDataSourceTest::compareHostsIdentifier(const ConstHostPtr& host1, const ConstHostPtr& host2) { auto host1_i = host1->getIdentifier(); auto host2_i = host2->getIdentifier(); auto count1 = host1_i.size(); auto count2 = host2_i.size(); if (count1 > count2) { count1 = count2; } for (uint8_t i = 0; i < count1; ++i) { if (host1_i[i] != host2_i[i]) { return (host1_i[i] < host2_i[i]); } } return false; } DuidPtr GenericHostDataSourceTest::HWAddrToDuid(const HWAddrPtr& hwaddr) { if (!hwaddr) { return (DuidPtr()); } return (DuidPtr(new DUID(hwaddr->hwaddr_))); } HWAddrPtr GenericHostDataSourceTest::DuidToHWAddr(const DuidPtr& duid) { if (!duid) { return (HWAddrPtr()); } return (HWAddrPtr(new HWAddr(duid->getDuid(), HTYPE_ETHER))); } void GenericHostDataSourceTest::addTestOptions(const HostPtr& host, const bool formatted, const AddedOptions& added_options, ConstElementPtr user_context) const { OptionDefSpaceContainer defs; if ((added_options == DHCP4_ONLY) || (added_options == DHCP4_AND_DHCP6)) { // Add DHCPv4 options. CfgOptionPtr opts = host->getCfgOption4(); OptionDescriptor desc = createOption(Option::V4, DHO_BOOT_FILE_NAME, true, false, formatted, "my-boot-file"); desc.setContext(user_context); opts->add(desc, DHCP4_OPTION_SPACE); opts->add(createOption(Option::V4, DHO_DEFAULT_IP_TTL, false, false, formatted, 64), DHCP4_OPTION_SPACE); opts->add(createOption(Option::V4, 1, false, false, formatted, 312131), "vendor-encapsulated-options-space"); opts->add(createAddressOption(254, false, false, formatted, "192.0.2.3"), DHCP4_OPTION_SPACE); opts->add(createEmptyOption(Option::V4, 1, true, false), "isc"); opts->add(createAddressOption(2, false, false, formatted, "10.0.0.5", "10.0.0.3", "10.0.3.4"), "isc"); auto def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, DHO_VENDOR_ENCAPSULATED_OPTIONS); opts->add(OptionDescriptor(def->optionFactory(Option::V4, DHO_VENDOR_ENCAPSULATED_OPTIONS, OptionBuffer()), true, false), DHCP4_OPTION_SPACE); // Add definitions for DHCPv4 non-standard options. defs.addItem(OptionDefinitionPtr(new OptionDefinition( "vendor-encapsulated-1", 1, "vendor-encapsulated-options-space", "uint32"))); defs.addItem(OptionDefinitionPtr(new OptionDefinition( "option-254", 254, DHCP4_OPTION_SPACE, "ipv4-address", true))); defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-1", 1, "isc", "empty"))); defs.addItem(OptionDefinitionPtr(new OptionDefinition("isc-2", 2, "isc", "ipv4-address", true))); } if ((added_options == DHCP6_ONLY) || (added_options == DHCP4_AND_DHCP6)) { // Add DHCPv6 options. CfgOptionPtr opts = host->getCfgOption6(); OptionDescriptor desc = createOption(Option::V6, D6O_BOOTFILE_URL, true, false, formatted, "my-boot-file"); desc.setContext(user_context); opts->add(desc, DHCP6_OPTION_SPACE); opts->add(createOption(Option::V6, D6O_INFORMATION_REFRESH_TIME, false, false, formatted, 3600), DHCP6_OPTION_SPACE); opts->add(createVendorOption(Option::V6, false, false, formatted, 2495), DHCP6_OPTION_SPACE); opts->add(createAddressOption(1024, false, false, formatted, "2001:db8:1::1"), DHCP6_OPTION_SPACE); opts->add(createEmptyOption(Option::V6, 1, true, false), "isc2"); opts->add(createAddressOption(2, false, false, formatted, "3000::1", "3000::2", "3000::3"), "isc2"); desc = createOption(Option::V6, DOCSIS3_V6_TFTP_SERVERS, true, false, true, "3000:1::234"); opts->add(desc, "vendor-4491"); // Add definitions for DHCPv6 non-standard options. defs.addItem(OptionDefinitionPtr(new OptionDefinition( "option-1024", 1024, DHCP6_OPTION_SPACE, "ipv6-address", true))); defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-1", 1, "isc2", "empty"))); defs.addItem(OptionDefinitionPtr(new OptionDefinition("option-2", 2, "isc2", "ipv6-address", true))); } // Register created "runtime" option definitions. They will be used by a // host data source to convert option data into the appropriate option // classes when the options are retrieved. LibDHCP::setRuntimeOptionDefs(defs); } void GenericHostDataSourceTest::addIPv6Address(const HostPtr& host, const std::string& address) const { host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress(address))); } void GenericHostDataSourceTest::testReadOnlyDatabase(const char* valid_db_type) { ASSERT_TRUE(hdsptr_); // The database is initially opened in "read-write" mode. We can // insert some data to the database. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false); ASSERT_TRUE(host); ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv6SubnetID(); // Make sure that the host has been inserted and that the data can be // retrieved. ConstHostPtr host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(host_by_id); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // Close the database connection and reopen in "read-only" mode as // specified by the "VALID_READONLY_DB" parameter. HostMgr::create(); HostMgr::addBackend(connectionString( valid_db_type, VALID_NAME, VALID_HOST, VALID_READONLY_USER, VALID_PASSWORD, VALID_READONLY_DB)); hdsptr_ = HostMgr::instance().getHostDataSource(); ASSERT_NE(hdsptr_->getParameters(), DatabaseConnection::ParameterMap()); // Check that an attempt to insert new host would result in // exception. HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", Host::IDENT_DUID, false); ASSERT_TRUE(host2); ASSERT_THROW(hdsptr_->add(host2), ReadOnlyDb); ASSERT_THROW(hdsptr_->commit(), ReadOnlyDb); ASSERT_THROW(hdsptr_->rollback(), ReadOnlyDb); // Reading from the database should still be possible, though. host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(host_by_id); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); } void GenericHostDataSourceTest::testBasic4(const Host::IdentifierType& id) { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservation. HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", id); ASSERT_TRUE(host); // Make sure the host is generate properly. SubnetID subnet = host->getIPv4SubnetID(); // Try to add it to the host data source. ASSERT_NO_THROW(hdsptr_->add(host)); // This should not return anything ConstHostPtr from_hds = hdsptr_->get4(subnet, IOAddress("10.10.10.10")); ASSERT_FALSE(from_hds); // This time it should return a host from_hds = hdsptr_->get4(subnet, IOAddress("192.0.2.1")); ASSERT_TRUE(from_hds); // Finally, let's check if what we got makes any sense. HostDataSourceUtils::compareHosts(host, from_hds); } void GenericHostDataSourceTest::testGlobalSubnetId4() { std::vector ident; ident = HostDataSourceUtils::generateIdentifier(); SubnetID subnet_id4 = SUBNET_ID_GLOBAL; HostPtr host(new Host(&ident[0], ident.size(), Host::IDENT_DUID, subnet_id4, SUBNET_ID_UNUSED, IOAddress("0.0.0.0"))); ASSERT_NO_THROW(addTestOptions(host, true, DHCP4_ONLY)); (hdsptr_->add(host)); //ASSERT_NO_THROW(hdsptr_->add(host)); // get4(subnet_id, identifier_type, identifier, identifier_size) ConstHostPtr host_by_id = hdsptr_->get4(subnet_id4, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // Now try to delete it: del4(subnet4-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del4(subnet_id4, Host::IDENT_DUID, &ident[0], ident.size())); host_by_id = hdsptr_->get4(subnet_id4, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); EXPECT_FALSE(host_by_id); } void GenericHostDataSourceTest::testGlobalSubnetId6() { std::vector ident; ident = HostDataSourceUtils::generateIdentifier(); SubnetID subnet_id6 = SUBNET_ID_GLOBAL; HostPtr host(new Host(&ident[0], ident.size(), Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_id6, IOAddress("0.0.0.0"))); ASSERT_NO_THROW(addTestOptions(host, true, DHCP6_ONLY)); ASSERT_NO_THROW(hdsptr_->add(host)); // get6(subnet_id, identifier_type, identifier, identifier_size) ConstHostPtr host_by_id = hdsptr_->get6(subnet_id6, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // Now try to delete it: del6(subnet6-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del6(subnet_id6, Host::IDENT_DUID, &ident[0], ident.size())); host_by_id = hdsptr_->get4(subnet_id6, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); EXPECT_FALSE(host_by_id); } void GenericHostDataSourceTest::testMaxSubnetId4() { std::vector ident; ident = HostDataSourceUtils::generateIdentifier(); SubnetID subnet_id4 = SUBNET_ID_MAX; HostPtr host(new Host(&ident[0], ident.size(), Host::IDENT_DUID, subnet_id4, SUBNET_ID_UNUSED, IOAddress("0.0.0.0"))); ASSERT_NO_THROW(addTestOptions(host, true, DHCP4_ONLY)); ASSERT_NO_THROW(hdsptr_->add(host)); // get4(subnet_id, identifier_type, identifier, identifier_size) ConstHostPtr host_by_id = hdsptr_->get4(subnet_id4, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // Now try to delete it: del4(subnet4-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del4(subnet_id4, Host::IDENT_DUID, &ident[0], ident.size())); host_by_id = hdsptr_->get4(subnet_id4, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); EXPECT_FALSE(host_by_id); } void GenericHostDataSourceTest::testMaxSubnetId6() { std::vector ident; ident = HostDataSourceUtils::generateIdentifier(); SubnetID subnet_id6 = SUBNET_ID_MAX; HostPtr host(new Host(&ident[0], ident.size(), Host::IDENT_DUID, SUBNET_ID_UNUSED, subnet_id6, IOAddress("0.0.0.0"))); ASSERT_NO_THROW(addTestOptions(host, true, DHCP6_ONLY)); ASSERT_NO_THROW(hdsptr_->add(host)); // get6(subnet_id, identifier_type, identifier, identifier_size) ConstHostPtr host_by_id = hdsptr_->get6(subnet_id6, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // Now try to delete it: del6(subnet6-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del6(subnet_id6, Host::IDENT_DUID, &ident[0], ident.size())); host_by_id = hdsptr_->get4(subnet_id6, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); EXPECT_FALSE(host_by_id); } void GenericHostDataSourceTest::testGetAll4() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a couple of hosts... const Host::IdentifierType& id = Host::IDENT_HWADDR; HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", id); HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", id); HostPtr host3 = HostDataSourceUtils::initializeHost4("192.0.2.3", id); HostPtr host4 = HostDataSourceUtils::initializeHost4("192.0.2.4", id); // Set them in the same subnets. SubnetID subnet4 = host1->getIPv4SubnetID(); host2->setIPv4SubnetID(subnet4); host3->setIPv4SubnetID(subnet4); host4->setIPv4SubnetID(subnet4); SubnetID subnet6 = host1->getIPv6SubnetID(); host2->setIPv6SubnetID(subnet6); host3->setIPv6SubnetID(subnet6); host4->setIPv6SubnetID(subnet6); // ... and add them to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); // And then try to retrieve them back. ConstHostCollection from_hds = hdsptr_->getAll4(subnet4); // Make sure we got something back. ASSERT_EQ(4, from_hds.size()); HostDataSourceUtils::compareHosts(host1, from_hds[0]); HostDataSourceUtils::compareHosts(host2, from_hds[1]); HostDataSourceUtils::compareHosts(host3, from_hds[2]); HostDataSourceUtils::compareHosts(host4, from_hds[3]); } void GenericHostDataSourceTest::testGetAll6() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a couple of hosts... const Host::IdentifierType& id = Host::IDENT_DUID; HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", id, false); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", id, false); HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3", id, false); HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4", id, false); // Set them in the same subnets. SubnetID subnet4 = host1->getIPv4SubnetID(); host2->setIPv4SubnetID(subnet4); host3->setIPv4SubnetID(subnet4); host4->setIPv4SubnetID(subnet4); SubnetID subnet6 = host1->getIPv6SubnetID(); host2->setIPv6SubnetID(subnet6); host3->setIPv6SubnetID(subnet6); host4->setIPv6SubnetID(subnet6); // ... and add them to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); // And then try to retrieve them back. ConstHostCollection from_hds = hdsptr_->getAll6(subnet6); // Make sure we got something back. ASSERT_EQ(4, from_hds.size()); HostDataSourceUtils::compareHosts(host1, from_hds[0]); HostDataSourceUtils::compareHosts(host2, from_hds[1]); HostDataSourceUtils::compareHosts(host3, from_hds[2]); HostDataSourceUtils::compareHosts(host4, from_hds[3]); } void GenericHostDataSourceTest::testGetAllbyHostname() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... Host::IdentifierType id = Host::IDENT_HWADDR; HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", id); host1->setHostname("host"); id = Host::IDENT_DUID; HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", id); host2->setHostname("Host"); HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::1", id, false); host3->setHostname("hOSt"); HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::2", id, false); host4->setHostname("host.example.com"); // Now add them all to the host data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); // Retrieve unknown name. ConstHostCollection from_hds = hdsptr_->getAllbyHostname("foo"); EXPECT_TRUE(from_hds.empty()); // Retrieve one reservation. from_hds = hdsptr_->getAllbyHostname("host.example.com"); ASSERT_EQ(1, from_hds.size()); HostDataSourceUtils::compareHosts(host4, from_hds[0]); // Retrieve all reservations with host hostname. from_hds = hdsptr_->getAllbyHostname("host"); EXPECT_EQ(3, from_hds.size()); bool got1 = false; bool got2 = false; bool got3 = false; for (auto host : from_hds) { if (host->getIdentifierType() == Host::IDENT_HWADDR) { EXPECT_FALSE(got1); got1 = true; HostDataSourceUtils::compareHosts(host1, host); } else if (host->getIPv4Reservation().isV4Zero()) { EXPECT_FALSE(got3); got3 = true; HostDataSourceUtils::compareHosts(host3, host); } else { EXPECT_FALSE(got2); got2 = true; HostDataSourceUtils::compareHosts(host2, host); } } EXPECT_TRUE(got1); EXPECT_TRUE(got2); EXPECT_TRUE(got3); } void GenericHostDataSourceTest::testGetAllbyHostnameSubnet4() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... Host::IdentifierType id = Host::IDENT_HWADDR; HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", id); host1->setHostname("host"); id = Host::IDENT_DUID; HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", id); host2->setHostname("Host"); CfgOptionPtr opts = host2->getCfgOption4(); OptionDescriptor desc = createOption(Option::V4, DHO_BOOT_FILE_NAME, true, false, false, "my-boot-file"); opts->add(desc, DHCP4_OPTION_SPACE); HostPtr host3 = HostDataSourceUtils::initializeHost4("192.0.2.3", id); host3->setHostname("hOSt"); HostPtr host4 = HostDataSourceUtils::initializeHost4("192.0.2.4", id); host4->setHostname("host.example.com"); HostPtr host5 = HostDataSourceUtils::initializeHost4("192.0.2.5", id); // Set them in the same subnet at the exception of host5. SubnetID subnet4 = host1->getIPv4SubnetID(); host2->setIPv4SubnetID(subnet4); host3->setIPv4SubnetID(subnet4); host4->setIPv4SubnetID(subnet4); SubnetID subnet6 = host1->getIPv6SubnetID(); host2->setIPv6SubnetID(subnet6); host3->setIPv6SubnetID(subnet6); host4->setIPv6SubnetID(subnet6); // Now add them all to the host data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); ASSERT_NO_THROW(hdsptr_->add(host5)); // Retrieve unknown name. ConstHostCollection from_hds = hdsptr_->getAllbyHostname4("foo", subnet4); EXPECT_TRUE(from_hds.empty()); // Retrieve one reservation. from_hds = hdsptr_->getAllbyHostname4("host.example.com", subnet4); ASSERT_EQ(1, from_hds.size()); HostDataSourceUtils::compareHosts(host4, from_hds[0]); // Check that the subnet is checked. from_hds = hdsptr_->getAllbyHostname4("host.example.com", subnet4 + 1); EXPECT_TRUE(from_hds.empty()); // Retrieve all reservations with host hostname. from_hds = hdsptr_->getAllbyHostname4("host", subnet4); EXPECT_EQ(3, from_hds.size()); bool got1 = false; bool got2 = false; bool got3 = false; for (auto host : from_hds) { if (host->getIdentifierType() == Host::IDENT_HWADDR) { EXPECT_FALSE(got1); got1 = true; HostDataSourceUtils::compareHosts(host1, host); } else if (!host->getCfgOption4()->empty()) { EXPECT_FALSE(got2); got2 = true; HostDataSourceUtils::compareHosts(host2, host); } else { EXPECT_FALSE(got3); got3 = true; HostDataSourceUtils::compareHosts(host3, host); } } EXPECT_TRUE(got1); EXPECT_TRUE(got2); EXPECT_TRUE(got3); } void GenericHostDataSourceTest::testGetAllbyHostnameSubnet6() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... Host::IdentifierType id = Host::IDENT_HWADDR; HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", id, false); host1->setHostname("host"); id = Host::IDENT_DUID; HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", id, false); host2->setHostname("Host"); CfgOptionPtr opts = host2->getCfgOption6(); OptionDescriptor desc = createOption(Option::V6, D6O_BOOTFILE_URL, true, false, true, "my-boot-file"); opts->add(desc, DHCP6_OPTION_SPACE); HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8::3", id, false); host3->setHostname("hOSt"); HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8::4", id, false); host4->setHostname("host.example.com"); HostPtr host5 = HostDataSourceUtils::initializeHost6("2001:db8::5", id, false); // Set them in the same subnet at the exception of host5. SubnetID subnet4 = host1->getIPv4SubnetID(); host2->setIPv4SubnetID(subnet4); host3->setIPv4SubnetID(subnet4); host4->setIPv4SubnetID(subnet4); SubnetID subnet6 = host1->getIPv6SubnetID(); host2->setIPv6SubnetID(subnet6); host3->setIPv6SubnetID(subnet6); host4->setIPv6SubnetID(subnet6); // Now add them all to the host data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); ASSERT_NO_THROW(hdsptr_->add(host5)); // Retrieve unknown name. ConstHostCollection from_hds = hdsptr_->getAllbyHostname6("foo", subnet6); EXPECT_TRUE(from_hds.empty()); // Retrieve one reservation. from_hds = hdsptr_->getAllbyHostname6("host.example.com", subnet6); ASSERT_EQ(1, from_hds.size()); HostDataSourceUtils::compareHosts(host4, from_hds[0]); // Check that the subnet is checked. from_hds = hdsptr_->getAllbyHostname6("host.example.com", subnet6 + 1); EXPECT_TRUE(from_hds.empty()); // Retrieve all reservations with host hostname. from_hds = hdsptr_->getAllbyHostname6("host", subnet6); EXPECT_EQ(3, from_hds.size()); bool got1 = false; bool got2 = false; bool got3 = false; for (auto host : from_hds) { if (host->getIdentifierType() == Host::IDENT_HWADDR) { EXPECT_FALSE(got1); got1 = true; HostDataSourceUtils::compareHosts(host1, host); } else if (!host->getCfgOption6()->empty()) { EXPECT_FALSE(got2); got2 = true; HostDataSourceUtils::compareHosts(host2, host); } else { EXPECT_FALSE(got3); got3 = true; HostDataSourceUtils::compareHosts(host3, host); } } EXPECT_TRUE(got1); EXPECT_TRUE(got2); EXPECT_TRUE(got3); } void GenericHostDataSourceTest::testGetPage4() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... IOAddress addr("192.0.2.0"); SubnetID subnet4(4); SubnetID subnet6(6); const Host::IdentifierType& id = Host::IDENT_DUID; for (unsigned i = 0; i < 25; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost4(addr.toText(), id); host->setIPv4SubnetID(subnet4); host->setIPv6SubnetID(subnet6); ASSERT_NO_THROW(hdsptr_->add(host)); } // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(10); ConstHostCollection page; ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(10, page.size()); host_id = page[9]->getHostId(); ASSERT_NE(0, host_id); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(10, page.size()); host_id = page[9]->getHostId(); ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(5, page.size()); host_id = page[4]->getHostId(); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); host_id = 0; // Other subnets are empty. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet6, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); } void GenericHostDataSourceTest::testGetPage6() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... IOAddress addr("2001:db8:1::"); SubnetID subnet4(4); SubnetID subnet6(6); const Host::IdentifierType& id = Host::IDENT_HWADDR; for (unsigned i = 0; i < 25; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost6(addr.toText(), id, false); host->setIPv4SubnetID(subnet4); host->setIPv6SubnetID(subnet6); ASSERT_NO_THROW(hdsptr_->add(host)); } // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(10); ConstHostCollection page; ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(10, page.size()); host_id = page[9]->getHostId(); ASSERT_NE(0, host_id); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(10, page.size()); host_id = page[9]->getHostId(); ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(5, page.size()); host_id = page[4]->getHostId(); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); host_id = 0; // Other subnets are empty. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet4, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); } void GenericHostDataSourceTest::testGetPageLimit4(const Host::IdentifierType& id) { // From the ticket: add 5 hosts each with 3 options. // call getPage4 with limit of 4. // The first page should return 4 hosts, // the second should return one host. // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... IOAddress addr("192.0.2.0"); SubnetID subnet4(4); SubnetID subnet6(6); for (unsigned i = 0; i < 5; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost4(addr.toText(), id); host->setIPv4SubnetID(subnet4); host->setIPv6SubnetID(subnet6); // Add DHCPv4 options. CfgOptionPtr opts = host->getCfgOption4(); OptionDescriptor desc = createOption(Option::V4, DHO_BOOT_FILE_NAME, true, false, false, "my-boot-file"); opts->add(desc, DHCP4_OPTION_SPACE); opts->add(createOption(Option::V4, DHO_DEFAULT_IP_TTL, false, true, false, 64 + i), DHCP4_OPTION_SPACE); opts->add(createEmptyOption(Option::V4, 1, true, true), "isc"); ASSERT_NO_THROW(hdsptr_->add(host)); } // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(4); ConstHostCollection page; ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(4, page.size()); host_id = page[3]->getHostId(); ASSERT_NE(0, host_id); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(1, page.size()); host_id = page[0]->getHostId(); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); } void GenericHostDataSourceTest::testGetPageLimit6(const Host::IdentifierType& id) { // From the ticket: add several v6 hosts with multiple address/prefix // reservations and multiple options. // Get hosts by page with page size 1. // Make sure all address/prefix reservations are returned. // Make sure all options are returned as expected. // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... IOAddress addr("2001:db8:1::"); SubnetID subnet4(4); SubnetID subnet6(6); vector hosts; for (unsigned i = 0; i < 5; ++i) { addr = IOAddress::increase(addr); ostringstream pref; pref << "2001:db8:2:" << 10 + i << "::"; HostPtr host = HostDataSourceUtils::initializeHost6(addr.toText(), id, false); host->setIPv4SubnetID(subnet4); host->setIPv6SubnetID(subnet6); // Add address/prefix. addr = IOAddress::increase(addr); IPv6Resrv resva(IPv6Resrv::TYPE_NA, addr, 128); host->addReservation(resva); IPv6Resrv resvp(IPv6Resrv::TYPE_PD, IOAddress(pref.str()), 64); host->addReservation(resvp); // Add DHCPv6 options. CfgOptionPtr opts = host->getCfgOption6(); OptionDescriptor desc = createOption(Option::V6, D6O_BOOTFILE_URL, true, false, false, "my-boot-file"); opts->add(desc, DHCP6_OPTION_SPACE); opts->add(createOption(Option::V6, D6O_INFORMATION_REFRESH_TIME, false, true, false, 3600 + i), DHCP6_OPTION_SPACE); opts->add(createAddressOption(D6O_SIP_SERVERS_ADDR, false, false, false, addr.toText()), DHCP6_OPTION_SPACE); ASSERT_NO_THROW(hdsptr_->add(host)); hosts.push_back(host); } // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(4); ConstHostCollection page; ConstHostCollection all_pages; ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(4, page.size()); host_id = page[3]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(1, page.size()); host_id = page[0]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 5; ++i) { HostDataSourceUtils::compareHosts(hosts[i], all_pages[i]); } } void GenericHostDataSourceTest::testGetPage4Subnets() { // From the ticket: add one host to subnet1, add one host to subnet2. // repeat 5 times. Get hosts from subnet1 with page size 3. // Make sure the right hosts are returned and in expected page // sizes (3, then 2). // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... const Host::IdentifierType& id = Host::IDENT_HWADDR; IOAddress addr("192.0.2.0"); SubnetID subnet4(4); SubnetID subnet6(6); vector hosts; for (unsigned i = 0; i < 10; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost4(addr.toText(), id); host->setIPv4SubnetID(subnet4 + (i & 1)); host->setIPv6SubnetID(subnet6 + (i & 1)); ASSERT_NO_THROW(hdsptr_->add(host)); hosts.push_back(host); } // First subnet. // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(3); ConstHostCollection page; ConstHostCollection all_pages; ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(2, page.size()); host_id = page[1]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 5; ++i) { HostDataSourceUtils::compareHosts(hosts[i * 2], all_pages[i]); } all_pages.clear(); // Second subnet. ++subnet4; // Get first page. idx = 0; host_id = 0; ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(2, page.size()); host_id = page[1]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage4(subnet4, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 5; ++i) { HostDataSourceUtils::compareHosts(hosts[i * 2 + 1], all_pages[i]); } } void GenericHostDataSourceTest::testGetPage6Subnets() { // From the ticket: add one host to subnet1, add one host to subnet2. // repeat 5 times. Get hosts from subnet1 with page size 3. // Make sure the right hosts are returned and in expected page // sizes (3, then 2). // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... const Host::IdentifierType& id = Host::IDENT_DUID; IOAddress addr("2001:db8:1::"); SubnetID subnet4(4); SubnetID subnet6(6); vector hosts; for (unsigned i = 0; i < 10; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost6(addr.toText(), id, false); host->setIPv4SubnetID(subnet4 + (i & 1)); host->setIPv6SubnetID(subnet6 + (i & 1)); ASSERT_NO_THROW(hdsptr_->add(host)); hosts.push_back(host); } // First subnet. // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(3); ConstHostCollection page; ConstHostCollection all_pages; ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(2, page.size()); host_id = page[1]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 5; ++i) { HostDataSourceUtils::compareHosts(hosts[i * 2], all_pages[i]); } all_pages.clear(); // Second subnet. ++subnet6; // Get first page. idx = 0; host_id = 0; ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second and last pages. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(2, page.size()); host_id = page[1]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage6(subnet6, idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 5; ++i) { HostDataSourceUtils::compareHosts(hosts[i * 2 + 1], all_pages[i]); } } void GenericHostDataSourceTest::testGetPage4All() { // From the ticket: add one host to subnet1, add one host to subnet2. // repeat 4 times. Get all hosts with page size 3. // Make sure all hosts are returned and in expected page // sizes (3, 3, then 2). // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... const Host::IdentifierType& id = Host::IDENT_HWADDR; IOAddress addr("192.0.2.0"); SubnetID subnet4(4); SubnetID subnet6(6); vector hosts; for (unsigned i = 0; i < 8; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost4(addr.toText(), id); host->setIPv4SubnetID(subnet4 + (i & 1)); host->setIPv6SubnetID(subnet6 + (i & 1)); ASSERT_NO_THROW(hdsptr_->add(host)); hosts.push_back(host); } // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(3); ConstHostCollection page; ConstHostCollection all_pages; ASSERT_NO_THROW(page = hdsptr_->getPage4(idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second page. ASSERT_NO_THROW(page = hdsptr_->getPage4(idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get last page. ASSERT_NO_THROW(page = hdsptr_->getPage4(idx, host_id, page_size)); ASSERT_EQ(2, page.size()); host_id = page[1]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage4(idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 8; ++i) { HostDataSourceUtils::compareHosts(hosts[i], all_pages[i]); } } void GenericHostDataSourceTest::testGetPage6All() { // From the ticket: add one host to subnet1, add one host to subnet2. // repeat 4 times. Get all hosts with page size 3. // Make sure all hosts are returned and in expected page // sizes (3, 3, then 2). // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create some hosts... const Host::IdentifierType& id = Host::IDENT_DUID; IOAddress addr("2001:db8:1::"); SubnetID subnet4(4); SubnetID subnet6(6); vector hosts; for (unsigned i = 0; i < 8; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost6(addr.toText(), id, false); host->setIPv4SubnetID(subnet4 + (i & 1)); host->setIPv6SubnetID(subnet6 + (i & 1)); ASSERT_NO_THROW(hdsptr_->add(host)); hosts.push_back(host); } // Get first page. size_t idx(1); uint64_t host_id(0); HostPageSize page_size(3); ConstHostCollection page; ConstHostCollection all_pages; ASSERT_NO_THROW(page = hdsptr_->getPage6(idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); ASSERT_NE(0, host_id); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get second page. ASSERT_NO_THROW(page = hdsptr_->getPage6(idx, host_id, page_size)); ASSERT_EQ(3, page.size()); host_id = page[2]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Get last page. ASSERT_NO_THROW(page = hdsptr_->getPage6(idx, host_id, page_size)); ASSERT_EQ(2, page.size()); host_id = page[1]->getHostId(); std::copy(page.begin(), page.end(), std::back_inserter(all_pages)); // Verify we have everything. ASSERT_NO_THROW(page = hdsptr_->getPage6(idx, host_id, page_size)); ASSERT_EQ(0, page.size()); // hosts are sorted by generated host_id (which is an auto increment for // MySql and PostgreSql) so the hosts must be sorted by host identifier std::sort(all_pages.begin(), all_pages.end(), compareHostsIdentifier); // Verify we got what we expected. for (size_t i = 0; i < 8; ++i) { HostDataSourceUtils::compareHosts(hosts[i], all_pages[i]); } } void GenericHostDataSourceTest::testGetByIPv4(const Host::IdentifierType& id) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a couple of hosts... HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", id); HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", id); HostPtr host3 = HostDataSourceUtils::initializeHost4("192.0.2.3", id); HostPtr host4 = HostDataSourceUtils::initializeHost4("192.0.2.4", id); // ... and add them to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); SubnetID subnet1 = host1->getIPv4SubnetID(); SubnetID subnet2 = host2->getIPv4SubnetID(); SubnetID subnet3 = host3->getIPv4SubnetID(); SubnetID subnet4 = host4->getIPv4SubnetID(); // And then try to retrieve them back. ConstHostPtr from_hds1 = hdsptr_->get4(subnet1, IOAddress("192.0.2.1")); ConstHostPtr from_hds2 = hdsptr_->get4(subnet2, IOAddress("192.0.2.2")); ConstHostPtr from_hds3 = hdsptr_->get4(subnet3, IOAddress("192.0.2.3")); ConstHostPtr from_hds4 = hdsptr_->get4(subnet4, IOAddress("192.0.2.4")); // Make sure we got something back. ASSERT_TRUE(from_hds1); ASSERT_TRUE(from_hds2); ASSERT_TRUE(from_hds3); ASSERT_TRUE(from_hds4); // Then let's check that what we got seems correct. HostDataSourceUtils::compareHosts(host1, from_hds1); HostDataSourceUtils::compareHosts(host2, from_hds2); HostDataSourceUtils::compareHosts(host3, from_hds3); HostDataSourceUtils::compareHosts(host4, from_hds4); // Ok, finally let's check that getting by a different address // will not work. EXPECT_FALSE(hdsptr_->get4(subnet1, IOAddress("192.0.1.5"))); } void GenericHostDataSourceTest::testGet4ByIdentifier( const Host::IdentifierType& identifier_type) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", identifier_type); HostPtr host2 = HostDataSourceUtils::initializeHost4("192.0.2.2", identifier_type); // Sanity check: make sure the hosts have different identifiers.. ASSERT_FALSE(host1->getIdentifier() == host2->getIdentifier()); // Try to add both of them to the host data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); SubnetID subnet1 = host1->getIPv4SubnetID(); SubnetID subnet2 = host2->getIPv4SubnetID(); ConstHostPtr from_hds1 = hdsptr_->get4(subnet1, identifier_type, &host1->getIdentifier()[0], host1->getIdentifier().size()); ConstHostPtr from_hds2 = hdsptr_->get4(subnet2, identifier_type, &host2->getIdentifier()[0], host2->getIdentifier().size()); // Now let's check if we got what we expected. ASSERT_TRUE(from_hds1); ASSERT_TRUE(from_hds2); HostDataSourceUtils::compareHosts(host1, from_hds1); HostDataSourceUtils::compareHosts(host2, from_hds2); } void GenericHostDataSourceTest::testHWAddrNotClientId() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host with HW address HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_HWADDR); ASSERT_TRUE(host->getHWAddress()); ASSERT_FALSE(host->getDuid()); // Try to add it to the host data source. ASSERT_NO_THROW(hdsptr_->add(host)); SubnetID subnet = host->getIPv4SubnetID(); DuidPtr duid = HWAddrToDuid(host->getHWAddress()); // Get the host by HW address (should succeed) ConstHostPtr by_hwaddr = hdsptr_->get4(subnet, Host::IDENT_HWADDR, &host->getIdentifier()[0], host->getIdentifier().size()); // Get the host by DUID (should fail) ConstHostPtr by_duid = hdsptr_->get4(subnet, Host::IDENT_DUID, &host->getIdentifier()[0], host->getIdentifier().size()); // Now let's check if we got what we expected. EXPECT_TRUE(by_hwaddr); EXPECT_FALSE(by_duid); } void GenericHostDataSourceTest::testClientIdNotHWAddr() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host with client-id HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID); ASSERT_FALSE(host->getHWAddress()); ASSERT_TRUE(host->getDuid()); // Try to add it to the host data source. ASSERT_NO_THROW(hdsptr_->add(host)); SubnetID subnet = host->getIPv4SubnetID(); HWAddrPtr hwaddr = DuidToHWAddr(host->getDuid()); // Get the host by DUID (should succeed) ConstHostPtr by_duid = hdsptr_->get4(subnet, Host::IDENT_DUID, &host->getIdentifier()[0], host->getIdentifier().size()); // Get the host by HW address (should fail) ConstHostPtr by_hwaddr = hdsptr_->get4(subnet, Host::IDENT_HWADDR, &host->getIdentifier()[0], host->getIdentifier().size()); // Now let's check if we got what we expected. EXPECT_TRUE(by_duid); EXPECT_FALSE(by_hwaddr); } void GenericHostDataSourceTest::testHostname(std::string name, int num) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Initialize the address to 192.0.2.0 (this will be bumped // up to 192.0.2.1 in the first iteration) IOAddress addr("192.0.2.0"); vector hosts; // Prepare a vector of hosts with unique hostnames for (int i = 0; i < num; ++i) { addr = IOAddress::increase(addr); HostPtr host = HostDataSourceUtils::initializeHost4(addr.toText(), Host::IDENT_DUID); stringstream hostname; hostname.str(""); if (num > 1) { hostname << i; } hostname << name; host->setHostname(hostname.str()); hosts.push_back(host); } // Now add them all to the host data source. for (vector::const_iterator it = hosts.begin(); it != hosts.end(); ++it) { // Try to add both of the to the host data source. ASSERT_NO_THROW(hdsptr_->add(*it)); } // And finally retrieve them one by one and check // if the hostname was preserved. for (vector::const_iterator it = hosts.begin(); it != hosts.end(); ++it) { ConstHostPtr from_hds; ASSERT_NO_THROW(from_hds = hdsptr_->get4((*it)->getIPv4SubnetID(), (*it)->getIPv4Reservation())); ASSERT_TRUE(from_hds); EXPECT_EQ((*it)->getHostname(), from_hds->getHostname()); } } void GenericHostDataSourceTest::testUserContext(ConstElementPtr user_context) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservation. HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID); ASSERT_TRUE(host); // Make sure the host is generated properly. host->setContext(user_context); SubnetID subnet = host->getIPv4SubnetID(); // Try to add it to the host data source. ASSERT_NO_THROW(hdsptr_->add(host)); // Retrieve it. ConstHostPtr from_hds = hdsptr_->get4(subnet, IOAddress("192.0.2.1")); ASSERT_TRUE(from_hds); // Finally, let's check if what we got makes any sense. HostDataSourceUtils::compareHosts(host, from_hds); // Retry with IPv6 host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_HWADDR, false); ASSERT_TRUE(host); ASSERT_TRUE(host->getHWAddress()); host->setContext(user_context); host->setHostname("foo.example.com"); subnet = host->getIPv6SubnetID(); ASSERT_NO_THROW(hdsptr_->add(host)); from_hds = hdsptr_->get6(subnet, Host::IDENT_HWADDR, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds); HostDataSourceUtils::compareHosts(host, from_hds); } void GenericHostDataSourceTest::testMultipleSubnets(int subnets, const Host::IdentifierType& id) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", id); host->setIPv6SubnetID(SUBNET_ID_UNUSED); for (int i = 0; i < subnets; ++i) { host->setIPv4SubnetID(i + 1000); ASSERT_NO_THROW(hdsptr_->add(host)); } // Now check that the reservations can be retrieved by IPv4 address from // each subnet separately. for (int i = 0; i < subnets; ++i) { // Try to retrieve the host by IPv4 address. ConstHostPtr from_hds = hdsptr_->get4(i + 1000, host->getIPv4Reservation()); ASSERT_TRUE(from_hds); EXPECT_EQ(i + 1000, from_hds->getIPv4SubnetID()); // Try to retrieve the host by either HW address of client-id from_hds = hdsptr_->get4(i + 1000, id, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds); EXPECT_EQ(i + 1000, from_hds->getIPv4SubnetID()); } // Now check that they can be retrieved all at once, by IPv4 address. ConstHostCollection all_by_addr = hdsptr_->getAll4(IOAddress("192.0.2.1")); ASSERT_EQ(subnets, all_by_addr.size()); // Verify that the values returned are proper. int i = 0; for (ConstHostCollection::const_iterator it = all_by_addr.begin(); it != all_by_addr.end(); ++it) { EXPECT_EQ(IOAddress("192.0.2.1"), (*it)->getIPv4Reservation()); EXPECT_EQ(1000 + i++, (*it)->getIPv4SubnetID()); } // Finally, check that the hosts can be retrieved by HW address or DUID ConstHostCollection all_by_id = hdsptr_->getAll( id, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_EQ(subnets, all_by_id.size()); // Check that the returned values are as expected. i = 0; for (ConstHostCollection::const_iterator it = all_by_id.begin(); it != all_by_id.end(); ++it) { EXPECT_EQ(IOAddress("192.0.2.1"), (*it)->getIPv4Reservation()); EXPECT_EQ(1000 + i++, (*it)->getIPv4SubnetID()); } } void GenericHostDataSourceTest::testGet6ByHWAddr() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservations. HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_HWADDR, false); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", Host::IDENT_HWADDR, false); // Sanity check: make sure the hosts have different HW addresses. ASSERT_TRUE(host1->getHWAddress()); ASSERT_TRUE(host2->getHWAddress()); HostDataSourceUtils::compareHwaddrs(host1, host2, false); // Try to add both of them to the host data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); SubnetID subnet1 = host1->getIPv6SubnetID(); SubnetID subnet2 = host2->getIPv6SubnetID(); ConstHostPtr from_hds1 = hdsptr_->get6(subnet1, Host::IDENT_HWADDR, &host1->getIdentifier()[0], host1->getIdentifier().size()); ConstHostPtr from_hds2 = hdsptr_->get6(subnet2, Host::IDENT_HWADDR, &host2->getIdentifier()[0], host2->getIdentifier().size()); // Now let's check if we got what we expected. ASSERT_TRUE(from_hds1); ASSERT_TRUE(from_hds2); HostDataSourceUtils::compareHosts(host1, from_hds1); HostDataSourceUtils::compareHosts(host2, from_hds2); } void GenericHostDataSourceTest::testGet6ByClientId() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservations. HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", Host::IDENT_DUID, false); // Sanity check: make sure the hosts have different HW addresses. ASSERT_TRUE(host1->getDuid()); ASSERT_TRUE(host2->getDuid()); HostDataSourceUtils::compareDuids(host1, host2, false); // Try to add both of them to the host data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); SubnetID subnet1 = host1->getIPv6SubnetID(); SubnetID subnet2 = host2->getIPv6SubnetID(); ConstHostPtr from_hds1 = hdsptr_->get6(subnet1, Host::IDENT_DUID, &host1->getIdentifier()[0], host1->getIdentifier().size()); ConstHostPtr from_hds2 = hdsptr_->get6(subnet2, Host::IDENT_DUID, &host2->getIdentifier()[0], host2->getIdentifier().size()); // Now let's check if we got what we expected. ASSERT_TRUE(from_hds1); ASSERT_TRUE(from_hds2); HostDataSourceUtils::compareHosts(host1, from_hds1); HostDataSourceUtils::compareHosts(host2, from_hds2); } void GenericHostDataSourceTest::testSubnetId6(int subnets, Host::IdentifierType id) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); HostPtr host; IOAddress current_address("2001:db8::"); ASSERT_LT(subnets, std::numeric_limits::max()) << "Too many subnets. Broken test?"; for (int i = 0; i < subnets; ++i) { // Last boolean value set to false indicates that the same identifier // must be used for each generated host. host = HostDataSourceUtils::initializeHost6(current_address.toText(), id, true, false, ""); host->setIPv4SubnetID(i + 1000); host->setIPv6SubnetID(i + 1000); // Check that the same host can have reservations in multiple subnets. EXPECT_NO_THROW(hdsptr_->add(host)); // Increase address to make sure we don't assign the same address // in different subnets. current_address = offsetAddress(current_address, (uint128_t(1) << 80)); } // Check that the reservations can be retrieved from each subnet separately. for (int i = 0; i < subnets; ++i) { // Try to retrieve the host ConstHostPtr from_hds = hdsptr_->get6(i + 1000, id, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds) << "failed for i=" << i; EXPECT_EQ(i + 1000, from_hds->getIPv6SubnetID()); } // Check that the hosts can all be retrieved by HW address or DUID ConstHostCollection all_by_id = hdsptr_->getAll(id, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_EQ(subnets, all_by_id.size()); // Check that the returned values are as expected. int i = 0; for (ConstHostCollection::const_iterator it = all_by_id.begin(); it != all_by_id.end(); ++it) { EXPECT_EQ(IOAddress("0.0.0.0"), (*it)->getIPv4Reservation()); EXPECT_EQ(1000 + i++, (*it)->getIPv6SubnetID()); } } void GenericHostDataSourceTest::testGetByIPv6(Host::IdentifierType id, bool prefix) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a couple of hosts... HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8:1::", id, prefix, "key##1"); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8:2::", id, prefix, "key##2"); HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8:3::", id, prefix, "key##3"); HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8:4::", id, prefix, "key##4"); // ... and add them to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); // Are we talking about addresses or prefixes? uint8_t len = prefix ? 64 : 128; // And then try to retrieve them back. ConstHostPtr from_hds1 = hdsptr_->get6(IOAddress("2001:db8:1::"), len); ConstHostPtr from_hds2 = hdsptr_->get6(IOAddress("2001:db8:2::"), len); ConstHostPtr from_hds3 = hdsptr_->get6(IOAddress("2001:db8:3::"), len); ConstHostPtr from_hds4 = hdsptr_->get6(IOAddress("2001:db8:4::"), len); // Make sure we got something back. ASSERT_TRUE(from_hds1); ASSERT_TRUE(from_hds2); ASSERT_TRUE(from_hds3); ASSERT_TRUE(from_hds4); // Then let's check that what we got seems correct. HostDataSourceUtils::compareHosts(host1, from_hds1); HostDataSourceUtils::compareHosts(host2, from_hds2); HostDataSourceUtils::compareHosts(host3, from_hds3); HostDataSourceUtils::compareHosts(host4, from_hds4); // Ok, finally let's check that getting by a different address // will not work. EXPECT_FALSE(hdsptr_->get6(IOAddress("2001:db8::5"), len)); } void GenericHostDataSourceTest::testGetBySubnetIPv6() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a couple of hosts... HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_DUID, true); addIPv6Address(host1, "2001:db8:1::10"); ASSERT_NO_THROW(addTestOptions(host1, true, DHCP6_ONLY)); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8:2::", Host::IDENT_DUID, true); addIPv6Address(host2, "2001:db8:1::20"); HostPtr host3 = HostDataSourceUtils::initializeHost6("2001:db8:3::", Host::IDENT_DUID, true); addIPv6Address(host3, "2001:db8:1::30"); HostPtr host4 = HostDataSourceUtils::initializeHost6("2001:db8:4::", Host::IDENT_DUID, true); addIPv6Address(host4, "2001:db8:1::40"); // ... and add them to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); ASSERT_NO_THROW(hdsptr_->add(host2)); ASSERT_NO_THROW(hdsptr_->add(host3)); ASSERT_NO_THROW(hdsptr_->add(host4)); // And then try to retrieve them back. ConstHostPtr from_hds1 = hdsptr_->get6(host1->getIPv6SubnetID(), IOAddress("2001:db8:1::")); ConstHostPtr from_hds2 = hdsptr_->get6(host2->getIPv6SubnetID(), IOAddress("2001:db8:2::")); ConstHostPtr from_hds3 = hdsptr_->get6(host3->getIPv6SubnetID(), IOAddress("2001:db8:3::")); ConstHostPtr from_hds4 = hdsptr_->get6(host4->getIPv6SubnetID(), IOAddress("2001:db8:4::")); // Make sure we got something back. ASSERT_TRUE(from_hds1); ASSERT_TRUE(from_hds2); ASSERT_TRUE(from_hds3); ASSERT_TRUE(from_hds4); // Then let's check that what we got seems correct. HostDataSourceUtils::compareHosts(host1, from_hds1); HostDataSourceUtils::compareHosts(host2, from_hds2); HostDataSourceUtils::compareHosts(host3, from_hds3); HostDataSourceUtils::compareHosts(host4, from_hds4); } void GenericHostDataSourceTest::testAddDuplicate6WithSameDUID() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservations. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_DUID, true); // Add this reservation once. ASSERT_NO_THROW(hdsptr_->add(host)); // Then try to add it again, it should throw an exception. ASSERT_THROW(hdsptr_->add(host), DuplicateEntry); } void GenericHostDataSourceTest::testAddDuplicate6WithSameHWAddr() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservations. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_HWADDR, true); // Add this reservation once. ASSERT_NO_THROW(hdsptr_->add(host)); // Then try to add it again, it should throw an exception. ASSERT_THROW(hdsptr_->add(host), DuplicateEntry); } void GenericHostDataSourceTest::testAddDuplicateIPv6() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservation. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_HWADDR, true); // Add this reservation once. ASSERT_NO_THROW(hdsptr_->add(host)); // Create a host with a different identifier but the same IPv6 address. An attempt // to create the reservation for the same IPv6 address should fail. host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_HWADDR, true); EXPECT_THROW(hdsptr_->add(host), DuplicateEntry); } void GenericHostDataSourceTest::testAllowDuplicateIPv6() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); ASSERT_TRUE(hdsptr_->setIPReservationsUnique(false)); // Create a host reservations. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_HWADDR, true, true); addIPv6Address(host, "2001:db8:2::"); auto host_id = host->getHostId(); auto subnet_id = host->getIPv6SubnetID(); // Add this reservation once. ASSERT_NO_THROW(hdsptr_->add(host)); // Then try to add it again, it should throw an exception because the // HWADDR is the same. host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_HWADDR, true, false); addIPv6Address(host, "2001:db8:2::"); host->setHostId(++host_id); host->setIPv6SubnetID(subnet_id); ASSERT_THROW(hdsptr_->add(host), DuplicateEntry); // This time use a different host identifier and try again. // This update should succeed because we permitted to create // multiple IP reservations for the same IP address but different // identifier. host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_HWADDR, true, true); host->setHostId(++host_id); host->setIPv6SubnetID(subnet_id); ASSERT_NO_THROW(hdsptr_->add(host)); ConstHostCollection returned; ASSERT_NO_THROW(returned = hdsptr_->getAll6(host->getIPv6SubnetID(), IOAddress("2001:db8:1::"))); EXPECT_EQ(2, returned.size()); EXPECT_NE(returned[0]->getIdentifierAsText(), returned[1]->getIdentifierAsText()); // Let's now try to delete the hosts by subnet_id and address. bool deleted = false; ASSERT_NO_THROW(deleted = hdsptr_->del(subnet_id, IOAddress("2001:db8:1::"))); ASSERT_TRUE(deleted); ASSERT_NO_THROW(returned = hdsptr_->getAll6(host->getIPv6SubnetID(), IOAddress("2001:db8:1::"))); EXPECT_TRUE(returned.empty()); } void GenericHostDataSourceTest::testAddDuplicateIPv4() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservations. HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID); // Add this reservation once. ASSERT_NO_THROW(hdsptr_->add(host)); // Then try to add it again, it should throw an exception. ASSERT_THROW(hdsptr_->add(host), DuplicateEntry); // This time use a different host identifier and try again. // This update should be rejected because of duplicated // address. ASSERT_NO_THROW(host->setIdentifier("01:02:03:04:05:06", "hw-address")); ASSERT_THROW(hdsptr_->add(host), DuplicateEntry); // Modify address to avoid its duplication and make sure // we can now add the host. ASSERT_NO_THROW(host->setIPv4Reservation(IOAddress("192.0.2.3"))); EXPECT_NO_THROW(hdsptr_->add(host)); } void GenericHostDataSourceTest::testAllowDuplicateIPv4() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); ASSERT_TRUE(hdsptr_->setIPReservationsUnique(false)); // Create a host reservations. HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID, true); auto host_id = host->getHostId(); auto subnet_id = host->getIPv4SubnetID(); // Add this reservation once. ASSERT_NO_THROW(hdsptr_->add(host)); // Then try to add it again, it should throw an exception because the // DUID is the same. host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID, false); host->setHostId(++host_id); host->setIPv4SubnetID(subnet_id); ASSERT_THROW(hdsptr_->add(host), DuplicateEntry); // This time use a different host identifier and try again. // This update should succeed because we permitted to create // multiple IP reservations for the same IP address but different // identifier. host = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_DUID, true); host->setHostId(++host_id); host->setIPv4SubnetID(subnet_id); ASSERT_NO_THROW(hdsptr_->add(host)); ConstHostCollection returned; ASSERT_NO_THROW(returned = hdsptr_->getAll4(host->getIPv4SubnetID(), IOAddress("192.0.2.1"))); EXPECT_EQ(2, returned.size()); EXPECT_NE(returned[0]->getIdentifierAsText(), returned[1]->getIdentifierAsText()); // Let's now try to delete the hosts by subnet_id and address. bool deleted = false; ASSERT_NO_THROW(deleted = hdsptr_->del(subnet_id, IOAddress("192.0.2.1"))); ASSERT_TRUE(deleted); ASSERT_NO_THROW(returned = hdsptr_->getAll4(host->getIPv4SubnetID(), IOAddress("192.0.2.1"))); EXPECT_TRUE(returned.empty()); } void GenericHostDataSourceTest::testDisallowDuplicateIP() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // The backend does not support switching to the mode in which multiple // reservations for the same address can be created. EXPECT_FALSE(hdsptr_->setIPReservationsUnique(false)); // The default mode still can be used. EXPECT_TRUE(hdsptr_->setIPReservationsUnique(true)); } void GenericHostDataSourceTest::testAddr6AndPrefix() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host reservations with prefix reservation (prefix = true) HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8:1::", Host::IDENT_DUID, true); // Create IPv6 reservation (for an address) and add it to the host IPv6Resrv resv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::2"), 128); host->addReservation(resv); // Add this reservation ASSERT_NO_THROW(hdsptr_->add(host)); // Get this host by DUID ConstHostPtr from_hds = hdsptr_->get6(host->getIPv6SubnetID(), Host::IDENT_DUID, &host->getIdentifier()[0], host->getIdentifier().size()); // Make sure we got something back ASSERT_TRUE(from_hds); // Check if reservations are the same HostDataSourceUtils::compareReservations6(host->getIPv6Reservations(), from_hds->getIPv6Reservations()); } void GenericHostDataSourceTest::testMultipleReservations() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); uint8_t len = 128; HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false); // Add some reservations IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len); IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len); IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len); IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), len); host->addReservation(resv1); host->addReservation(resv2); host->addReservation(resv3); host->addReservation(resv4); ASSERT_NO_THROW(hdsptr_->add(host)); ConstHostPtr from_hds = hdsptr_->get6(IOAddress("2001:db8::1"), len); // Make sure we got something back ASSERT_TRUE(from_hds); // Check if hosts are the same HostDataSourceUtils::compareHosts(host, from_hds); } void GenericHostDataSourceTest::testMultipleReservationsDifferentOrder() { // Make sure we have the pointer to the host data source. ASSERT_TRUE(hdsptr_); uint8_t len = 128; HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false, "key##1"); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false, "key##1"); // Add some reservations IPv6Resrv resv1(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::6"), len); IPv6Resrv resv2(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::7"), len); IPv6Resrv resv3(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::8"), len); IPv6Resrv resv4(IPv6Resrv::TYPE_NA, IOAddress("2001:db8::9"), len); host1->addReservation(resv1); host1->addReservation(resv2); host1->addReservation(resv3); host1->addReservation(resv4); host2->addReservation(resv4); host2->addReservation(resv3); host2->addReservation(resv2); host2->addReservation(resv1); // Check if reservations are the same HostDataSourceUtils::compareReservations6(host1->getIPv6Reservations(), host2->getIPv6Reservations()); } void GenericHostDataSourceTest::testOptionsReservations4(const bool formatted, ConstElementPtr user_context) { HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.5", Host::IDENT_HWADDR); // Add a bunch of DHCPv4 and DHCPv6 options for the host. ASSERT_NO_THROW(addTestOptions(host, formatted, DHCP4_ONLY, user_context)); // Insert host and the options into respective tables. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv4SubnetID(); // getAll4(subnet_id) ConstHostCollection hosts_by_subnet = hdsptr_->getAll4(subnet_id); ASSERT_EQ(1, hosts_by_subnet.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_subnet.begin())); auto returned_host = *hosts_by_subnet.begin(); EXPECT_FALSE(returned_host->getCfgOption4()->isEncapsulated()); ASSERT_NO_THROW(returned_host->encapsulateOptions()); auto cfg_option = returned_host->getCfgOption4(); auto option43 = cfg_option->get(DHCP4_OPTION_SPACE, DHO_VENDOR_ENCAPSULATED_OPTIONS); ASSERT_TRUE(option43.option_); EXPECT_TRUE(cfg_option->get("vendor-encapsulated-options-space", 1).option_); auto option43_1 = option43.option_->getOption(1); EXPECT_TRUE(option43_1); // getAll4(address) ConstHostCollection hosts_by_addr = hdsptr_->getAll4(host->getIPv4Reservation()); ASSERT_EQ(1, hosts_by_addr.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_addr.begin())); // get4(subnet_id, identifier_type, identifier, identifier_size) ConstHostPtr host_by_id = hdsptr_->get4(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // get4(subnet_id, address) ConstHostPtr host_by_addr = hdsptr_->get4(subnet_id, IOAddress("192.0.2.5")); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_addr)); } void GenericHostDataSourceTest::testOptionsReservations6(const bool formatted, ConstElementPtr user_context) { HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false); // Add a bunch of DHCPv4 and DHCPv6 options for the host. ASSERT_NO_THROW(addTestOptions(host, formatted, DHCP6_ONLY, user_context)); // Insert host, options and IPv6 reservations into respective tables. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv6SubnetID(); // get6(subnet_id, identifier_type, identifier, identifier_size) ConstHostPtr host_by_id = hdsptr_->get6(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_id)); // get6(address, prefix_len) ConstHostPtr host_by_addr = hdsptr_->get6(IOAddress("2001:db8::1"), 128); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, host_by_addr)); } void GenericHostDataSourceTest::testOptionsReservations46(const bool formatted) { HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_HWADDR, false); // Add a bunch of DHCPv4 and DHCPv6 options for the host. ASSERT_NO_THROW(addTestOptions(host, formatted, DHCP4_AND_DHCP6)); // Insert host, options and IPv6 reservations into respective tables. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv6SubnetID(); // getAll6(subnet_id) ConstHostCollection hosts_by_subnet = hdsptr_->getAll6(subnet_id); EXPECT_EQ(1, hosts_by_subnet.size()); // Don't compare as getAll6() returns the v6 part only. // getAll(identifier_type, identifier, identifier_size) ConstHostCollection hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_EQ(1, hosts_by_id.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_id.begin())); } void GenericHostDataSourceTest::testMultipleClientClasses4() { ASSERT_TRUE(hdsptr_); // Create the Host object. HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.5", Host::IDENT_HWADDR); // Add v4 classes to the host. for (int i = 0; i < 4; ++i) { std::ostringstream os; os << "class4_" << i; host->addClientClass4(os.str()); } // Add the host. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv4SubnetID(); // Fetch the host via: // getAll(const Host::IdentifierType, const uint8_t* identifier_begin, // const size_t identifier_len) const; ConstHostCollection hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_EQ(1, hosts_by_id.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_id.begin())); // Fetch the host via // getAll4(const asiolink::IOAddress& address) const; hosts_by_id = hdsptr_->getAll4(IOAddress("192.0.2.5")); ASSERT_EQ(1, hosts_by_id.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_id.begin())); // Fetch the host via // get4(const SubnetID& subnet_id, const Host::IdentifierType& // identifier_type, // const uint8_t* identifier_begin, const size_t identifier_len) const; ConstHostPtr from_hds = hdsptr_->get4(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); // Fetch the host via: // get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const; from_hds = hdsptr_->get4(subnet_id, IOAddress("192.0.2.5")); ASSERT_TRUE(from_hds); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); } void GenericHostDataSourceTest::testMultipleClientClasses6() { ASSERT_TRUE(hdsptr_); // Create the Host object. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_HWADDR, false); // Add v6 classes to the host. for (int i = 0; i < 4; ++i) { std::ostringstream os; os << "class6_" << i; host->addClientClass6(os.str()); } // Add the host. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv6SubnetID(); // getAll(const Host::IdentifierType& identifier_type, // const uint8_t* identifier_begin, // const size_t identifier_len) const; ConstHostCollection hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_EQ(1, hosts_by_id.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_id.begin())); // Fetch the host via: // get6(const SubnetID& subnet_id, const Host::IdentifierType& // identifier_type, // const uint8_t* identifier_begin, const size_t identifier_len) const; ConstHostPtr from_hds = hdsptr_->get6(subnet_id, Host::IDENT_HWADDR, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); // Fetch the host via: // get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const; from_hds = hdsptr_->get6(IOAddress("2001:db8::1"), 128); ASSERT_TRUE(from_hds); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); } void GenericHostDataSourceTest::testMultipleClientClassesBoth() { /// Add host reservation with a multiple v4 and v6 client-classes, /// retrieve it and make sure that all client classes are retrieved /// properly. ASSERT_TRUE(hdsptr_); // Create the Host object. HostPtr host = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_HWADDR, false); // Add v4 classes to the host. for (int i = 0; i < 4; ++i) { std::ostringstream os; os << "class4_" << i; host->addClientClass4(os.str()); } // Add v6 classes to the host. for (int i = 0; i < 4; ++i) { std::ostringstream os; os << "class6_" << i; host->addClientClass6(os.str()); } // Add the host. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv6SubnetID(); // Fetch the host from the source. ConstHostPtr from_hds = hdsptr_->get6(subnet_id, Host::IDENT_HWADDR, &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds); // Verify they match. ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); } void GenericHostDataSourceTest::testMessageFields4() { ASSERT_TRUE(hdsptr_); // Create the Host object. HostPtr host = HostDataSourceUtils::initializeHost4("192.0.2.5", Host::IDENT_HWADDR); // And assign values for DHCPv4 message fields. ASSERT_NO_THROW({ host->setNextServer(IOAddress("10.1.1.1")); host->setServerHostname("server-name.example.org"); host->setBootFileName("bootfile.efi"); }); // Add the host. ASSERT_NO_THROW(hdsptr_->add(host)); // Subnet id will be used in queries to the database. SubnetID subnet_id = host->getIPv4SubnetID(); // Fetch the host via: // getAll(const Host::IdentifierType, const uint8_t* identifier_begin, // const size_t identifier_len) const; ConstHostCollection hosts_by_id = hdsptr_->getAll(host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_EQ(1, hosts_by_id.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_id.begin())); // Fetch the host via // getAll4(const asiolink::IOAddress& address) const; hosts_by_id = hdsptr_->getAll4(IOAddress("192.0.2.5")); ASSERT_EQ(1, hosts_by_id.size()); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, *hosts_by_id.begin())); // Fetch the host via // get4(const SubnetID& subnet_id, const Host::IdentifierType& // identifier_type, // const uint8_t* identifier_begin, const size_t identifier_len) const; ConstHostPtr from_hds = hdsptr_->get4(subnet_id, host->getIdentifierType(), &host->getIdentifier()[0], host->getIdentifier().size()); ASSERT_TRUE(from_hds); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); // Fetch the host via: // get4(const SubnetID& subnet_id, const asiolink::IOAddress& address) const; from_hds = hdsptr_->get4(subnet_id, IOAddress("192.0.2.5")); ASSERT_TRUE(from_hds); ASSERT_NO_FATAL_FAILURE(HostDataSourceUtils::compareHosts(host, from_hds)); } void GenericHostDataSourceTest::stressTest(unsigned int nOfHosts /* = 0xfffdU */) { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Make sure the variable part of the generated address fits in a 16-bit // field. ASSERT_LE(nOfHosts, 0xfffdU); // Create hosts. std::vector hosts; hosts.reserve(nOfHosts); for (unsigned int i = 0x0001U; i < 0x0001U + nOfHosts; ++i) { /// @todo: Check if this is written in hexadecimal format. std::stringstream ss; std::string n_host; ss << std::hex << i; ss >> n_host; const std::string prefix = std::string("2001:db8::") + n_host; hosts.push_back(HostDataSourceUtils::initializeHost6(prefix, Host::IDENT_HWADDR, false, "key##1")); IPv6ResrvRange range = hosts.back()->getIPv6Reservations(); ASSERT_EQ(1, std::distance(range.first, range.second)); EXPECT_TRUE(HostDataSourceUtils::reservationExists (IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress(prefix)), range)); } const size_t hosts_size = hosts.size(); std::cout << "Starting to add hosts..." << std::endl; struct timespec start, end; start = (struct timespec){0, 0}; end = (struct timespec){0, 0}; clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start); for (std::vector::const_iterator it = hosts.begin(); it != hosts.end(); it++) { ASSERT_NO_THROW(hdsptr_->add(*it)); } clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); double s = static_cast(end.tv_sec - start.tv_sec) + static_cast(end.tv_nsec - start.tv_nsec) / 1e9; std::cout << "Adding " << hosts_size << (hosts_size == 1 ? " host" : " hosts") << " took " << std::fixed << std::setprecision(2) << s << " seconds." << std::endl; // And then try to retrieve them back. std::cout << "Starting to retrieve hosts..." << std::endl; start = (struct timespec){0, 0}; end = (struct timespec){0, 0}; clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start); for (std::vector::const_iterator it = hosts.begin(); it != hosts.end(); it++) { IPv6ResrvRange range = (*it)->getIPv6Reservations(); // This get6() call is particularly useful to test because it involves a // subquery for MySQL and PostgreSQL. ConstHostPtr from_hds = hdsptr_->get6(range.first->second.getPrefix(), 128); ASSERT_TRUE(from_hds); HostDataSourceUtils::compareHosts(*it, from_hds); } clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); s = static_cast(end.tv_sec - start.tv_sec) + static_cast(end.tv_nsec - start.tv_nsec) / 1e9; std::cout << "Retrieving " << hosts_size << (hosts_size == 1 ? " host" : " hosts") << " took " << std::fixed << std::setprecision(2) << s << " seconds." << std::endl; } void GenericHostDataSourceTest::testDeleteByAddr4() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a v4 host... HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_HWADDR); SubnetID subnet1 = host1->getIPv4SubnetID(); // ... and add it to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); // And then try to retrieve it back. ConstHostPtr before = hdsptr_->get4(subnet1, IOAddress("192.0.2.1")); // Now try to delete it: del(subnet-id, addr4) EXPECT_TRUE(hdsptr_->del(subnet1, IOAddress("192.0.2.1"))); // Check if it's still there. ConstHostPtr after = hdsptr_->get4(subnet1, IOAddress("192.0.2.1")); // Make sure the host was there before... EXPECT_TRUE(before); // ... and that it's gone after deletion. EXPECT_FALSE(after); // An attempt to delete it should not cause an exception. It // should return false. bool result = false; EXPECT_NO_THROW(result = hdsptr_->del(subnet1, IOAddress("192.0.2.1"))); EXPECT_FALSE(result); } void GenericHostDataSourceTest::testDeleteById4() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a v4 host... HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_HWADDR); SubnetID subnet1 = host1->getIPv4SubnetID(); // ... and add it to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); // And then try to retrieve it back. ConstHostPtr before = hdsptr_->get4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Now try to delete it: del4(subnet4-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); // Check if it's still there. ConstHostPtr after = hdsptr_->get4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Make sure the host was there before... EXPECT_TRUE(before); // ... and that it's gone after deletion. EXPECT_FALSE(after); // An attempt to delete it should not cause an exception. It // should return false. bool result = false; EXPECT_NO_THROW(result = hdsptr_->del4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); EXPECT_FALSE(result); } // Test checks when a IPv4 host with options is deleted that the options are // deleted as well. void GenericHostDataSourceTest::testDeleteById4Options() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a v4 host... HostPtr host1 = HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_HWADDR); // Add a bunch of DHCPv4 and DHCPv6 options for the host. ASSERT_NO_THROW(addTestOptions(host1, true, DHCP4_ONLY)); // Insert host and the options into respective tables. SubnetID subnet1 = host1->getIPv4SubnetID(); // ... and add it to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); // There must be some options EXPECT_NE(0, countDBOptions4()); // And then try to retrieve it back. ConstHostPtr before = hdsptr_->get4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Now try to delete it: del4(subnet4-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); // Check if it's still there. ConstHostPtr after = hdsptr_->get4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Make sure the host was there before... EXPECT_TRUE(before); // ... and that it's gone after deletion. EXPECT_FALSE(after); // Check the options are indeed gone. EXPECT_EQ(0, countDBOptions4()); // An attempt to delete it should not cause an exception. It // should return false. bool result = false; EXPECT_NO_THROW(result = hdsptr_->del4(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); EXPECT_FALSE(result); } void GenericHostDataSourceTest::testDeleteById6() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a v6 host... HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false, "key##1"); SubnetID subnet1 = host1->getIPv6SubnetID(); // ... and add it to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); // And then try to retrieve it back. ConstHostPtr before = hdsptr_->get6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Now try to delete it: del4(subnet4-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); // Check if it's still there. ConstHostPtr after = hdsptr_->get6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Make sure the host was there before... EXPECT_TRUE(before); // ... and that it's gone after deletion. EXPECT_FALSE(after); // An attempt to delete it should not cause an exception. It // should return false. bool result = false; EXPECT_NO_THROW(result = hdsptr_->del6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); EXPECT_FALSE(result); } void GenericHostDataSourceTest::testDeleteById6Options() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Let's create a v6 host... HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false); SubnetID subnet1 = host1->getIPv6SubnetID(); ASSERT_NO_THROW(addTestOptions(host1, true, DHCP6_ONLY)); // ... and add it to the data source. ASSERT_NO_THROW(hdsptr_->add(host1)); // Check that the options are stored... EXPECT_NE(0, countDBOptions6()); // ... and so are v6 reservations. EXPECT_NE(0, countDBReservations6()); // And then try to retrieve it back. ConstHostPtr before = hdsptr_->get6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Now try to delete it: del4(subnet4-id, identifier-type, identifier) EXPECT_TRUE(hdsptr_->del6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); // Check if it's still there. ConstHostPtr after = hdsptr_->get6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size()); // Make sure the host was there before... EXPECT_TRUE(before); // ... and that it's gone after deletion. EXPECT_FALSE(after); // Check the options are indeed gone. EXPECT_EQ(0, countDBOptions6()); // Check the options are indeed gone. EXPECT_EQ(0, countDBReservations6()); // An attempt to delete it should not cause an exception. It // should return false. bool result = false; EXPECT_NO_THROW(result = hdsptr_->del6(subnet1, host1->getIdentifierType(), &host1->getIdentifier()[0], host1->getIdentifier().size())); EXPECT_FALSE(result); } void GenericHostDataSourceTest::testMultipleHostsNoAddress4() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create a host with zero IPv4 address. HostPtr host1 = HostDataSourceUtils::initializeHost4("0.0.0.0", Host::IDENT_HWADDR); host1->setIPv4SubnetID(1); host1->setIPv6SubnetID(SUBNET_ID_UNUSED); // Add the host to the database. ASSERT_NO_THROW(hdsptr_->add(host1)); // An attempt to add this host again should fail due to client identifier // duplication. ASSERT_THROW(hdsptr_->add(host1), DuplicateEntry); // Create another host with zero IPv4 address. Adding this host to the // database should be successful because zero addresses are not counted // in the unique index. HostPtr host2 = HostDataSourceUtils::initializeHost4("0.0.0.0", Host::IDENT_HWADDR); host2->setIPv4SubnetID(1); host2->setIPv6SubnetID(SUBNET_ID_UNUSED); ASSERT_NO_THROW(hdsptr_->add(host2)); } void GenericHostDataSourceTest::testMultipleHosts6() { // Make sure we have a pointer to the host data source. ASSERT_TRUE(hdsptr_); // Create first host. HostPtr host1 = HostDataSourceUtils::initializeHost6("2001:db8::1", Host::IDENT_DUID, false); host1->setIPv4SubnetID(SUBNET_ID_UNUSED); host1->setIPv6SubnetID(1); // Add the host to the database. ASSERT_NO_THROW(hdsptr_->add(host1)); // An attempt to add this host again should fail due to client identifier // duplication. ASSERT_THROW(hdsptr_->add(host1), DuplicateEntry); HostPtr host2 = HostDataSourceUtils::initializeHost6("2001:db8::2", Host::IDENT_DUID, false); host2->setIPv4SubnetID(SUBNET_ID_UNUSED); host2->setIPv6SubnetID(1); // Add the host to the database. ASSERT_NO_THROW(hdsptr_->add(host2)); } void HostMgrDbLostCallbackTest::testNoCallbackOnOpenFailure() { isc::db::DatabaseConnection::db_lost_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1); // Set the connectivity recovered callback. isc::db::DatabaseConnection::db_recovered_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1); // Set the connectivity failed callback. isc::db::DatabaseConnection::db_failed_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1); // Connect to the host backend. ASSERT_THROW(HostMgr::addBackend(invalidConnectString()), DbOpenError); io_service_->poll(); EXPECT_EQ(0, db_lost_callback_called_); EXPECT_EQ(0, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); } void HostMgrDbLostCallbackTest::testDbLostAndRecoveredCallback() { // Set the connectivity lost callback. isc::db::DatabaseConnection::db_lost_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1); // Set the connectivity recovered callback. isc::db::DatabaseConnection::db_recovered_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1); // Set the connectivity failed callback. isc::db::DatabaseConnection::db_failed_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1); std::string access = validConnectString(); CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Create the HostMgr. HostMgr::create(); // Find the most recently opened socket. Our SQL client's socket should // be the next one. int last_open_socket = findLastSocketFd(); // Fill holes. FillFdHoles holes(last_open_socket); // Connect to the host backend. ASSERT_NO_THROW(HostMgr::addBackend(access)); // Find the SQL client socket. int sql_socket = findLastSocketFd(); ASSERT_TRUE(sql_socket > last_open_socket); // Verify we can execute a query. We don't care about the answer. ConstHostCollection hosts; ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"))); // Now close the sql socket out from under backend client ASSERT_EQ(0, close(sql_socket)); // A query should fail with DbConnectionUnusable. ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")), DbConnectionUnusable); io_service_->poll(); // Our lost and recovered connectivity callback should have been invoked. EXPECT_EQ(1, db_lost_callback_called_); EXPECT_EQ(1, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); } void HostMgrDbLostCallbackTest::testDbLostAndFailedCallback() { // Set the connectivity lost callback. isc::db::DatabaseConnection::db_lost_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1); // Set the connectivity recovered callback. isc::db::DatabaseConnection::db_recovered_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1); // Set the connectivity failed callback. isc::db::DatabaseConnection::db_failed_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1); std::string access = validConnectString(); CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Create the HostMgr. HostMgr::create(); // Find the most recently opened socket. Our SQL client's socket should // be the next one. int last_open_socket = findLastSocketFd(); // Fill holes. FillFdHoles holes(last_open_socket); // Connect to the host backend. ASSERT_NO_THROW(HostMgr::addBackend(access)); // Find the SQL client socket. int sql_socket = findLastSocketFd(); ASSERT_TRUE(sql_socket > last_open_socket); // Verify we can execute a query. We don't care about the answer. ConstHostCollection hosts; ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"))); access = invalidConnectString(); CfgMgr::instance().clear(); // by adding an invalid access will cause the manager factory to throw // resulting in failure to recreate the manager CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Now close the sql socket out from under backend client ASSERT_EQ(0, close(sql_socket)); // A query should fail with DbConnectionUnusable. ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")), DbConnectionUnusable); io_service_->poll(); // Our lost and failed connectivity callback should have been invoked. EXPECT_EQ(1, db_lost_callback_called_); EXPECT_EQ(0, db_recovered_callback_called_); EXPECT_EQ(1, db_failed_callback_called_); } void HostMgrDbLostCallbackTest::testDbLostAndRecoveredAfterTimeoutCallback() { // Set the connectivity lost callback. isc::db::DatabaseConnection::db_lost_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1); // Set the connectivity recovered callback. isc::db::DatabaseConnection::db_recovered_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1); // Set the connectivity failed callback. isc::db::DatabaseConnection::db_failed_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1); std::string access = validConnectString(); std::string extra = " max-reconnect-tries=3 reconnect-wait-time=1"; access += extra; CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Create the HostMgr. HostMgr::create(); // Find the most recently opened socket. Our SQL client's socket should // be the next one. int last_open_socket = findLastSocketFd(); // Fill holes. FillFdHoles holes(last_open_socket); // Connect to the host backend. ASSERT_NO_THROW(HostMgr::addBackend(access)); // Find the SQL client socket. int sql_socket = findLastSocketFd(); ASSERT_TRUE(sql_socket > last_open_socket); // Verify we can execute a query. We don't care about the answer. ConstHostCollection hosts; ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"))); access = invalidConnectString(); access += extra; CfgMgr::instance().clear(); // by adding an invalid access will cause the manager factory to throw // resulting in failure to recreate the manager CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Now close the sql socket out from under backend client ASSERT_EQ(0, close(sql_socket)); // A query should fail with DbConnectionUnusable. ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")), DbConnectionUnusable); io_service_->poll(); // Our lost connectivity callback should have been invoked. EXPECT_EQ(1, db_lost_callback_called_); EXPECT_EQ(0, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); access = validConnectString(); access += extra; CfgMgr::instance().clear(); CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); sleep(1); io_service_->poll(); // Our lost and recovered connectivity callback should have been invoked. EXPECT_EQ(2, db_lost_callback_called_); EXPECT_EQ(1, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); sleep(1); io_service_->poll(); // No callback should have been invoked. EXPECT_EQ(2, db_lost_callback_called_); EXPECT_EQ(1, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); } void HostMgrDbLostCallbackTest::testDbLostAndFailedAfterTimeoutCallback() { // Set the connectivity lost callback. isc::db::DatabaseConnection::db_lost_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_lost_callback, this, ph::_1); // Set the connectivity recovered callback. isc::db::DatabaseConnection::db_recovered_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_recovered_callback, this, ph::_1); // Set the connectivity failed callback. isc::db::DatabaseConnection::db_failed_callback_ = std::bind(&HostMgrDbLostCallbackTest::db_failed_callback, this, ph::_1); std::string access = validConnectString(); std::string extra = " max-reconnect-tries=3 reconnect-wait-time=1"; access += extra; CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Create the HostMgr. HostMgr::create(); // Find the most recently opened socket. Our SQL client's socket should // be the next one. int last_open_socket = findLastSocketFd(); // Fill holes. FillFdHoles holes(last_open_socket); // Connect to the host backend. ASSERT_NO_THROW(HostMgr::addBackend(access)); // Find the SQL client socket. int sql_socket = findLastSocketFd(); ASSERT_TRUE(sql_socket > last_open_socket); // Verify we can execute a query. We don't care about the answer. ConstHostCollection hosts; ASSERT_NO_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"))); access = invalidConnectString(); access += extra; CfgMgr::instance().clear(); // by adding an invalid access will cause the manager factory to throw // resulting in failure to recreate the manager CfgMgr::instance().getCurrentCfg()->getCfgDbAccess()->setHostDbAccessString(access); // Now close the sql socket out from under backend client ASSERT_EQ(0, close(sql_socket)); // A query should fail with DbConnectionUnusable. ASSERT_THROW(hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")), DbConnectionUnusable); io_service_->poll(); // Our lost connectivity callback should have been invoked. EXPECT_EQ(1, db_lost_callback_called_); EXPECT_EQ(0, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); sleep(1); io_service_->poll(); // Our lost connectivity callback should have been invoked. EXPECT_EQ(2, db_lost_callback_called_); EXPECT_EQ(0, db_recovered_callback_called_); EXPECT_EQ(0, db_failed_callback_called_); sleep(1); io_service_->poll(); // Our lost and failed connectivity callback should have been invoked. EXPECT_EQ(3, db_lost_callback_called_); EXPECT_EQ(0, db_recovered_callback_called_); EXPECT_EQ(1, db_failed_callback_called_); } void // cppcheck-suppress unusedFunction HostMgrTest::SetUp() { // Remove all configuration which may be dangling from the previous test. CfgMgr::instance().clear(); // Recreate HostMgr instance. It drops any previous state. HostMgr::create(); // Create HW addresses from the template. const uint8_t mac_template[] = { 0x01, 0x02, 0x0A, 0xBB, 0x03, 0x00 }; for (uint8_t i = 0; i < 10; ++i) { std::vector vec(mac_template, mac_template + sizeof(mac_template)); vec[vec.size() - 1] = i; HWAddrPtr hwaddr(new HWAddr(vec, HTYPE_ETHER)); hwaddrs_.push_back(hwaddr); } // Create DUIDs from the template. const uint8_t duid_template[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00 }; for (uint8_t i = 0; i < 10; ++i) { std::vector vec(duid_template, duid_template + sizeof(mac_template)); vec[vec.size() - 1] = i; DuidPtr duid(new DUID(vec)); duids_.push_back(duid); } } CfgHostsPtr HostMgrTest::getCfgHosts() const { return (CfgMgr::instance().getStagingCfg()->getCfgHosts()); } void HostMgrTest::addHost4(BaseHostDataSource& data_source, const HWAddrPtr& hwaddr, const SubnetID& subnet_id, const IOAddress& address) { data_source.add(HostPtr(new Host(hwaddr->toText(false), "hw-address", subnet_id, SUBNET_ID_UNUSED, address))); } void HostMgrTest::addHost6(BaseHostDataSource& data_source, const DuidPtr& duid, const SubnetID& subnet_id, const IOAddress& address, const uint8_t prefix_len) { HostPtr new_host(new Host(duid->toText(), "duid", SubnetID(1), subnet_id, IOAddress::IPV4_ZERO_ADDRESS())); new_host->addReservation(IPv6Resrv(prefix_len == 128 ? IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD, address, prefix_len)); data_source.add(new_host); } void HostMgrTest::addHost6(BaseHostDataSource& data_source, const DuidPtr& duid, const SubnetID& subnet_id, const std::vector& addresses, const uint8_t prefix_len) { HostPtr new_host(new Host(duid->toText(), "duid", SubnetID(1), subnet_id, IOAddress::IPV4_ZERO_ADDRESS())); for (const IOAddress& address : addresses) { new_host->addReservation(IPv6Resrv(prefix_len == 128 ? IPv6Resrv::TYPE_NA : IPv6Resrv::TYPE_PD, address, prefix_len)); } data_source.add(new_host); } void HostMgrTest::testGetAll(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR, &hwaddrs_[1]->hwaddr_[0], hwaddrs_[1]->hwaddr_.size()); ASSERT_TRUE(hosts.empty()); // Add two reservations for the same HW address. They differ by the IP // address reserved and the IPv4 subnet. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[0], SubnetID(10), IOAddress("192.0.3.10")); CfgMgr::instance().commit(); // If there non-matching HW address is specified, nothing should be // returned. hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR, &hwaddrs_[1]->hwaddr_[0], hwaddrs_[1]->hwaddr_.size()); ASSERT_TRUE(hosts.empty()); // For the correct HW address, there should be two reservations. hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_EQ(2, hosts.size()); // We don't know the order in which the reservations are returned so // we have to match with any of the two reservations returned. // Look for the first reservation. bool found = false; for (unsigned i = 0; i < 2; ++i) { if (hosts[i]->getIPv4Reservation() == IOAddress("192.0.2.5")) { ASSERT_EQ(1, hosts[i]->getIPv4SubnetID()); found = true; } } if (!found) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.2.5" " not found using getAll method"; } // Look for the second reservation. found = false; for (unsigned i = 0; i < 2; ++i) { if (hosts[i]->getIPv4Reservation() == IOAddress("192.0.3.10")) { ASSERT_EQ(10, hosts[i]->getIPv4SubnetID()); found = true; } } if (!found) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10" " not found using getAll method"; } // Check handling of operation target. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Primary source target. hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { found = false; for (unsigned i = 0; i < hosts.size(); ++i) { if (hosts[i]->getIPv4Reservation() == IOAddress("192.0.2.5")) { ASSERT_EQ(1, hosts[i]->getIPv4SubnetID()); found = true; } } if (!found) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.2.5" " not found using getAll method with PRIMARY_SOURCE operation" " target"; } } if (is_second_source_primary) { found = false; for (unsigned i = 0; i < hosts.size(); ++i) { if (hosts[i]->getIPv4Reservation() == IOAddress("192.0.3.10")) { ASSERT_EQ(10, hosts[i]->getIPv4SubnetID()); found = true; } } if (!found) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10" " not found using getAll method with PRIMARY_SOURCE operation" " target"; } } // Alternate sources target. hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { found = false; for (unsigned i = 0; i < hosts.size(); ++i) { if (hosts[i]->getIPv4Reservation() == IOAddress("192.0.2.5")) { ASSERT_EQ(1, hosts[i]->getIPv4SubnetID()); found = true; } } if (!found) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.2.5" " not found using getAll method with PRIMARY_SOURCE operation" " target"; } } if (!is_second_source_primary) { found = false; for (unsigned i = 0; i < hosts.size(); ++i) { if (hosts[i]->getIPv4Reservation() == IOAddress("192.0.3.10")) { ASSERT_EQ(10, hosts[i]->getIPv4SubnetID()); found = true; } } if (!found) { ADD_FAILURE() << "Reservation for the IPv4 address 192.0.3.10" " not found using getAll method with PRIMARY_SOURCE operation" " target"; } } // Unspecified source target. hosts = HostMgr::instance().getAll(Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAll4BySubnet(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll4(SubnetID(1)); ASSERT_TRUE(hosts.empty()); // Add two reservations for the same subnet. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.6")); CfgMgr::instance().commit(); // If there non-matching subnet is specified, nothing should be returned. hosts = HostMgr::instance().getAll4(SubnetID(100)); ASSERT_TRUE(hosts.empty()); // For the correct subnet, there should be two reservations. hosts = HostMgr::instance().getAll4(SubnetID(1)); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv4SubnetID()); // Make sure that two different hosts were returned. EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText()); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); } if (is_second_source_primary) { EXPECT_EQ("192.0.2.6", hosts[hosts_in_primary_source-1]->getIPv4Reservation().toText()); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); } if (!is_second_source_primary) { EXPECT_EQ("192.0.2.6", hosts[2 - hosts_in_primary_source - 1]->getIPv4Reservation().toText()); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAll6BySubnet(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1)); ASSERT_TRUE(hosts.empty()); // Add two reservations for the same subnet. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::6")); CfgMgr::instance().commit(); // If there non-matching subnet is specified, nothing should be returned. hosts = HostMgr::instance().getAll6(SubnetID(100)); ASSERT_TRUE(hosts.empty()); // For the correct subnet, there should be two reservations. hosts = HostMgr::instance().getAll6(SubnetID(1)); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv6SubnetID()); // Make sure that two different hosts were returned. EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); EXPECT_TRUE(hosts[1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll6(SubnetID(1), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (is_second_source_primary) { EXPECT_TRUE(hosts[hosts_in_primary_source-1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll6(SubnetID(1), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (!is_second_source_primary) { EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll6(SubnetID(1), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAllbyHostname(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAllbyHostname("host"); ASSERT_TRUE(hosts.empty()); // Add two reservations with the same hostname. HostPtr host1(new Host(hwaddrs_[0]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.5"))); host1->setHostname("Host"); data_source1.add(host1); HostPtr host2(new Host(hwaddrs_[1]->toText(false), "hw-address", SubnetID(10), SUBNET_ID_UNUSED, IOAddress("192.0.3.10"))); host2->setHostname("hosT"); data_source2.add(host2); CfgMgr::instance().commit(); // If there non-matching hostname is specified, nothing should be // returned. hosts = HostMgr::instance().getAllbyHostname("foobar"); EXPECT_TRUE(hosts.empty()); // For the correct hostname, there should be two reservations. hosts = HostMgr::instance().getAllbyHostname("host"); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ(10, hosts[1]->getIPv4SubnetID()); // Make sure that hostname is correct including its case. EXPECT_EQ("Host", hosts[0]->getHostname()); EXPECT_EQ("hosT", hosts[1]->getHostname()); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAllbyHostname("host", HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); } if (is_second_source_primary) { EXPECT_EQ(10, hosts[hosts_in_primary_source-1]->getIPv4SubnetID()); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAllbyHostname("host", HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); } if (!is_second_source_primary) { EXPECT_EQ(10, hosts[2 - hosts_in_primary_source - 1]->getIPv4SubnetID()); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAllbyHostname("host", HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAllbyHostnameSubnet4(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1)); ASSERT_TRUE(hosts.empty()); // Add two reservations with the same hostname. HostPtr host1(new Host(hwaddrs_[0]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.5"))); host1->setHostname("Host"); data_source1.add(host1); HostPtr host2(new Host(hwaddrs_[1]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.6"))); host2->setHostname("hosT"); data_source2.add(host2); CfgMgr::instance().commit(); // If there non-matching hostname is specified, nothing should be // returned. hosts = HostMgr::instance().getAllbyHostname4("foobar", SubnetID(1)); EXPECT_TRUE(hosts.empty()); // If there non-matching subnet is specified, nothing should be // returned. hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(10)); EXPECT_TRUE(hosts.empty()); // For the correct hostname, there should be two reservations. hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1)); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv4SubnetID()); // Make sure that two different hosts were returned. EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText()); // Make sure that hostname is correct including its case. EXPECT_EQ("Host", hosts[0]->getHostname()); EXPECT_EQ("hosT", hosts[1]->getHostname()); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_EQ("Host", hosts[0]->getHostname()); } if (is_second_source_primary) { EXPECT_EQ("hosT", hosts[hosts_in_primary_source-1]->getHostname()); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_EQ("Host", hosts[0]->getHostname()); } if (!is_second_source_primary) { EXPECT_EQ("hosT", hosts[2 - hosts_in_primary_source - 1]->getHostname()); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAllbyHostname4("host", SubnetID(1), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAllbyHostnameSubnet6(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1)); ASSERT_TRUE(hosts.empty()); // Add two reservations with the same hostname. HostPtr host1(new Host(duids_[0]->toText(), "duid", SubnetID(1), SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS())); host1->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"), 128)); host1->setHostname("Host"); data_source1.add(host1); HostPtr host2(new Host(duids_[1]->toText(), "duid", SubnetID(1), SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS())); host2->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"), 128)); host2->setHostname("hosT"); data_source2.add(host2); CfgMgr::instance().commit(); // If there non-matching hostname is specified, nothing should be // returned. hosts = HostMgr::instance().getAllbyHostname6("foobar", SubnetID(1)); EXPECT_TRUE(hosts.empty()); // If there non-matching subnet is specified, nothing should be // returned. hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(10)); EXPECT_TRUE(hosts.empty()); // For the correct hostname, there should be two reservations. hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1)); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv6SubnetID()); // Make sure that two different hosts were returned. EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); EXPECT_TRUE(hosts[1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Make sure that hostname is correct including its case. EXPECT_EQ("Host", hosts[0]->getHostname()); EXPECT_EQ("hosT", hosts[1]->getHostname()); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (is_second_source_primary) { EXPECT_TRUE(hosts[hosts_in_primary_source-1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (!is_second_source_primary) { EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAllbyHostname6("host", SubnetID(1), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetPage4(bool use_database) { BaseHostDataSource& data_source1 = *getCfgHosts(); BaseHostDataSource& data_source2 = HostMgr::instance(); // Initially, no reservations should be present. size_t idx(0); HostPageSize page_size(10); ConstHostCollection hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size); ASSERT_TRUE(hosts.empty()); if (use_database) { EXPECT_EQ(2, idx); } else { EXPECT_EQ(1, idx); } // Add two reservations for the same subnet. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(use_database ? data_source2 : data_source1, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.6")); CfgMgr::instance().commit(); // If there non-matching subnet is specified, nothing should be returned. idx = 0; hosts = HostMgr::instance().getPage4(SubnetID(100), idx, 0, page_size); ASSERT_TRUE(hosts.empty()); // For the correct subnet, there should be two reservations. idx = 0; hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size); if (use_database) { ASSERT_EQ(1, hosts.size()); } else { ASSERT_EQ(2, hosts.size()); } // Make sure that returned values are correct. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); if (!use_database) { EXPECT_EQ(1, hosts[1]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText()); // Check it was the last page. uint64_t hid = hosts[1]->getHostId(); hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 1; hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } if (use_database) { uint64_t hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); ASSERT_EQ(0, idx); hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size); ASSERT_EQ(1, hosts.size()); ASSERT_NE(0, idx); EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText()); // Alternate way to use the database. idx = 1; hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size); ASSERT_EQ(1, hosts.size()); EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText()); // Check it was the last page. hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); hosts = HostMgr::instance().getPage4(SubnetID(1), idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 2; hosts = HostMgr::instance().getPage4(SubnetID(1), idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } } void HostMgrTest::testGetPage6(bool use_database) { BaseHostDataSource& data_source1 = *getCfgHosts(); BaseHostDataSource& data_source2 = HostMgr::instance(); // Initially, no reservations should be present. size_t idx(0); HostPageSize page_size(10); ConstHostCollection hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size); ASSERT_TRUE(hosts.empty()); if (use_database) { EXPECT_EQ(2, idx); } else { EXPECT_EQ(1, idx); } // Add two reservations for the same subnet. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(use_database ? data_source2 : data_source1, duids_[1], SubnetID(1), IOAddress("2001:db8:1::6")); CfgMgr::instance().commit(); // If there non-matching subnet is specified, nothing should be returned. idx = 0; hosts = HostMgr::instance().getPage6(SubnetID(100), idx, 0, page_size); ASSERT_TRUE(hosts.empty()); // For the correct subnet, there should be two reservations. idx = 0; hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size); if (use_database) { ASSERT_EQ(1, hosts.size()); } else { ASSERT_EQ(2, hosts.size()); } // Make sure that returned values are correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); if (!use_database) { EXPECT_EQ(1, hosts[1]->getIPv6SubnetID()); EXPECT_TRUE(hosts[1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Check it was the last page. uint64_t hid = hosts[1]->getHostId(); hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 1; hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } if (use_database) { uint64_t hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); ASSERT_EQ(0, idx); hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size); ASSERT_EQ(1, hosts.size()); ASSERT_NE(0, idx); EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Alternate way to use the database. idx = 1; hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size); ASSERT_EQ(1, hosts.size()); EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Check it was the last page. hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); hosts = HostMgr::instance().getPage6(SubnetID(1), idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 2; hosts = HostMgr::instance().getPage6(SubnetID(1), idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } } void HostMgrTest::testGetPage4All(bool use_database) { BaseHostDataSource& data_source1 = *getCfgHosts(); BaseHostDataSource& data_source2 = HostMgr::instance(); // Initially, no reservations should be present. size_t idx(0); HostPageSize page_size(10); ConstHostCollection hosts = HostMgr::instance().getPage4(idx, 0, page_size); ASSERT_TRUE(hosts.empty()); if (use_database) { EXPECT_EQ(2, idx); } else { EXPECT_EQ(1, idx); } // Add two reservations. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(use_database ? data_source2 : data_source1, hwaddrs_[1], SubnetID(2), IOAddress("192.0.2.6")); CfgMgr::instance().commit(); // There should be two reservations. idx = 0; hosts = HostMgr::instance().getPage4(idx, 0, page_size); if (use_database) { ASSERT_EQ(1, hosts.size()); } else { ASSERT_EQ(2, hosts.size()); } // Make sure that returned values are correct. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); if (!use_database) { EXPECT_EQ(2, hosts[1]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.6", hosts[1]->getIPv4Reservation().toText()); // Check it was the last page. uint64_t hid = hosts[1]->getHostId(); hosts = HostMgr::instance().getPage4(idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 1; hosts = HostMgr::instance().getPage4(idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } if (use_database) { uint64_t hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); ASSERT_EQ(0, idx); hosts = HostMgr::instance().getPage4(idx, hid, page_size); ASSERT_EQ(1, hosts.size()); ASSERT_NE(0, idx); EXPECT_EQ(2, hosts[0]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText()); // Alternate way to use the database. idx = 1; hosts = HostMgr::instance().getPage4(idx, 0, page_size); ASSERT_EQ(1, hosts.size()); EXPECT_EQ(2, hosts[0]->getIPv4SubnetID()); EXPECT_EQ("192.0.2.6", hosts[0]->getIPv4Reservation().toText()); // Check it was the last page. hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); hosts = HostMgr::instance().getPage4(idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 2; hosts = HostMgr::instance().getPage4(idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } } void HostMgrTest::testGetPage6All(bool use_database) { BaseHostDataSource& data_source1 = *getCfgHosts(); BaseHostDataSource& data_source2 = HostMgr::instance(); // Initially, no reservations should be present. size_t idx(0); HostPageSize page_size(10); ConstHostCollection hosts = HostMgr::instance().getPage6(idx, 0, page_size); ASSERT_TRUE(hosts.empty()); if (use_database) { EXPECT_EQ(2, idx); } else { EXPECT_EQ(1, idx); } // Add two reservations. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(use_database ? data_source2 : data_source1, duids_[1], SubnetID(2), IOAddress("2001:db8:1::6")); CfgMgr::instance().commit(); // There should be two reservations. idx = 0; hosts = HostMgr::instance().getPage6(idx, 0, page_size); if (use_database) { ASSERT_EQ(1, hosts.size()); } else { ASSERT_EQ(2, hosts.size()); } // Make sure that returned values are correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); if (!use_database) { EXPECT_EQ(2, hosts[1]->getIPv6SubnetID()); EXPECT_TRUE(hosts[1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Check it was the last page. uint64_t hid = hosts[1]->getHostId(); hosts = HostMgr::instance().getPage6(idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 1; hosts = HostMgr::instance().getPage6(idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } if (use_database) { uint64_t hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); ASSERT_EQ(0, idx); hosts = HostMgr::instance().getPage6(idx, hid, page_size); ASSERT_EQ(1, hosts.size()); ASSERT_NE(0, idx); EXPECT_EQ(2, hosts[0]->getIPv6SubnetID()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Alternate way to use the database. idx = 1; hosts = HostMgr::instance().getPage6(idx, 0, page_size); ASSERT_EQ(1, hosts.size()); EXPECT_EQ(2, hosts[0]->getIPv6SubnetID()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Check it was the last page. hid = hosts[0]->getHostId(); ASSERT_NE(0, hid); hosts = HostMgr::instance().getPage6(idx, hid, page_size); ASSERT_EQ(0, hosts.size()); idx = 2; hosts = HostMgr::instance().getPage6(idx, 0, page_size); ASSERT_EQ(0, hosts.size()); } } void HostMgrTest::testGetAll4(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Initially, no hosts should be present. ConstHostCollection hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")); ASSERT_TRUE(hosts.empty()); // Add two hosts to different data sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[1], SubnetID(10), IOAddress("192.0.2.5")); CfgMgr::instance().commit(); // Retrieve all hosts, This should return hosts from both sources // in a single container. hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5")); ASSERT_EQ(2, hosts.size()); // Make sure that IPv4 address is correct. EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText()); // Make sure that two different hosts were returned. EXPECT_NE(hosts[0]->getIPv4SubnetID(), hosts[1]->getIPv4SubnetID()); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); } if (is_second_source_primary) { EXPECT_EQ("192.0.2.5", hosts[hosts_in_primary_source-1]->getIPv4Reservation().toText()); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll4(IOAddress("192.0.2.5"), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); } if (!is_second_source_primary) { EXPECT_EQ("192.0.2.5", hosts[2 - hosts_in_primary_source - 1]->getIPv4Reservation().toText()); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGet4(BaseHostDataSource& data_source) { // Initially, no host should be present. ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_FALSE(host); // Add new host to the database. addHost4(data_source, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); CfgMgr::instance().commit(); // Retrieve the host from the database and expect that the parameters match. host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_TRUE(host); EXPECT_EQ(1, host->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText()); // Make sure that the operation target is supported. // Select host by explicit, matched operation target. HostMgrOperationTarget operation_target = isPrimaryDataSource(data_source) ? HostMgrOperationTarget::PRIMARY_SOURCE : HostMgrOperationTarget::ALTERNATE_SOURCES; host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), operation_target); ASSERT_TRUE(host); EXPECT_EQ(1, host->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText()); // Select host by explicit but unmatched operation target. operation_target = isPrimaryDataSource(data_source) ? HostMgrOperationTarget::ALTERNATE_SOURCES : HostMgrOperationTarget::PRIMARY_SOURCE; host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), operation_target); ASSERT_FALSE(host); // Select host for an unspecified operation target. host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE); ASSERT_FALSE(host); } void HostMgrTest::testGet4Any() { // Initially, no host should be present. ConstHostPtr host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); ASSERT_FALSE(host); HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); ASSERT_FALSE(host); // Add new host to the database. HostPtr new_host(new Host(duids_[0]->toText(), "duid", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.5"))); // Abuse of the server's configuration. getCfgHosts()->add(new_host); CfgMgr::instance().commit(); // Retrieve the host from the database and expect that the parameters match. host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); ASSERT_TRUE(host); EXPECT_EQ(1, host->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText()); // Set the negative cache flag on the host. new_host->setNegative(true); // get4 is not supposed to get it. host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); EXPECT_FALSE(host); // But get4Any should. host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); ASSERT_TRUE(host); EXPECT_EQ(1, host->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText()); EXPECT_TRUE(host->getNegative()); // To be sure. Note we use the CfgHosts source so only this // get4 overload works. host = HostMgr::instance().get4(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); EXPECT_FALSE(host); // Make sure that the operation target is supported. // Select host by explicit, matched operation target. host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::PRIMARY_SOURCE); ASSERT_TRUE(host); EXPECT_EQ(1, host->getIPv4SubnetID()); EXPECT_EQ("192.0.2.5", host->getIPv4Reservation().toText()); EXPECT_TRUE(host->getNegative()); // Select host by explicit but unmatched operation target. host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALTERNATE_SOURCES); ASSERT_FALSE(host); // Select host for an unspecified operation target. host = HostMgr::instance().get4Any(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE); ASSERT_FALSE(host); } void HostMgrTest::testGet6(BaseHostDataSource& data_source) { // Initially, no host should be present. ConstHostPtr host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); ASSERT_FALSE(host); // Add new host to the database. addHost6(data_source, duids_[0], SubnetID(2), IOAddress("2001:db8:1::1")); CfgMgr::instance().commit(); // Retrieve the host from the database and expect that the parameters match. host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()); ASSERT_TRUE(host); EXPECT_EQ(2, host->getIPv6SubnetID()); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1")))); // Make sure that the operation target is supported. // Select host by explicit, matched operation target. HostMgrOperationTarget operation_target = isPrimaryDataSource(data_source) ? HostMgrOperationTarget::PRIMARY_SOURCE : HostMgrOperationTarget::ALTERNATE_SOURCES; host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), operation_target); ASSERT_TRUE(host); EXPECT_EQ(2, host->getIPv6SubnetID()); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1")))); // Select host by explicit but unmatched operation target. operation_target = isPrimaryDataSource(data_source) ? HostMgrOperationTarget::ALTERNATE_SOURCES : HostMgrOperationTarget::PRIMARY_SOURCE; host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), operation_target); ASSERT_FALSE(host); // Select host for an unspecified operation target. host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE); ASSERT_FALSE(host); } void HostMgrTest::testGet6Any() { // Initially, no host should be present. ConstHostPtr host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_FALSE(host); host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_FALSE(host); // Add new host to the database. HostPtr new_host(new Host(hwaddrs_[0]->toText(false), "hw-address", SubnetID(1), SubnetID(2), IOAddress::IPV4_ZERO_ADDRESS())); new_host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1"), 128)); // Abuse of the server's configuration. getCfgHosts()->add(new_host); CfgMgr::instance().commit(); // Retrieve the host from the database and expect that the parameters match. host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_TRUE(host); EXPECT_EQ(2, host->getIPv6SubnetID()); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1")))); // Set the negative cache flag on the host. new_host->setNegative(true); // get6 is not supposed to get it. host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); EXPECT_FALSE(host); // But get6Any should. host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); ASSERT_TRUE(host); EXPECT_EQ(2, host->getIPv6SubnetID()); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1")))); EXPECT_TRUE(host->getNegative()); // To be sure. Note we use the CfgHosts source so only this // get6 overload works. host = HostMgr::instance().get6(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()); EXPECT_FALSE(host); // Make sure that the operation target is supported. // Select host by explicit, matched operation target. host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::PRIMARY_SOURCE); ASSERT_TRUE(host); EXPECT_EQ(2, host->getIPv6SubnetID()); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1")))); // Select host by explicit but unmatched operation target. host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALTERNATE_SOURCES); ASSERT_FALSE(host); // Select host for an unspecified operation target. host = HostMgr::instance().get6Any(SubnetID(2), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE); ASSERT_FALSE(host); } void HostMgrTest::testGet6ByPrefix(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { ConstHostPtr host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64); ASSERT_FALSE(host); // Add a host with a reservation for a prefix 2001:db8:1::/64. addHost6(data_source1, duids_[0], SubnetID(2), IOAddress("2001:db8:1::"), 64); // Add another host having a reservation for prefix 2001:db8:1:0:6::/72. addHost6(data_source2, duids_[1], SubnetID(3), IOAddress("2001:db8:1:0:6::"), 80); CfgMgr::instance().commit(); // Retrieve first reservation. host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64); ASSERT_TRUE(host); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 64))); // Make sure the first reservation is not retrieved when the prefix // length is incorrect. host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 72); EXPECT_FALSE(host); // Retrieve second reservation. host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 80); ASSERT_TRUE(host); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:0:6::"), 80))); // Make sure the second reservation is not retrieved when the prefix // length is incorrect. host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 64); EXPECT_FALSE(host); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); // Select host only from the primary source. host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64, HostMgrOperationTarget::PRIMARY_SOURCE); if (is_first_source_primary) { EXPECT_TRUE(host); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 64))); } else { EXPECT_FALSE(host); } host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 80, HostMgrOperationTarget::PRIMARY_SOURCE); if (is_second_source_primary) { EXPECT_TRUE(host); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:0:6::"), 80))); } else { EXPECT_FALSE(host); } // Select hosts only from the alternate sources. host = HostMgr::instance().get6(IOAddress("2001:db8:1::"), 64, HostMgrOperationTarget::ALTERNATE_SOURCES); if (!is_first_source_primary) { EXPECT_TRUE(host); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1::"), 64))); } else { EXPECT_FALSE(host); } host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 80, HostMgrOperationTarget::ALTERNATE_SOURCES); if (!is_second_source_primary) { EXPECT_TRUE(host); EXPECT_TRUE(host->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:0:6::"), 80))); } else { EXPECT_FALSE(host); } // Select hosts for an unspecified source. host = HostMgr::instance().get6(IOAddress("2001:db8:1:0:6::"), 80, HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_FALSE(host); } void HostMgrTest::testGetAll4BySubnetIP(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("192.0.2.5")); ASSERT_TRUE(hosts.empty()); // Add two reservations for the same subnet and IP address. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.5")); CfgMgr::instance().commit(); // If there non-matching subnet is specified, nothing should be returned. hosts = HostMgr::instance().getAll4(SubnetID(100), IOAddress("192.0.2.5")); ASSERT_TRUE(hosts.empty()); // For the correct subnet, there should be two reservations. hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("192.0.2.5")); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv4SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv4SubnetID()); // Make sure that two hosts were returned with different identifiers // but the same address. EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText()); EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); EXPECT_EQ("192.0.2.5", hosts[1]->getIPv4Reservation().toText()); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); } if (is_second_source_primary) { EXPECT_EQ("192.0.2.5", hosts[hosts_in_primary_source-1]->getIPv4Reservation().toText()); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_EQ("192.0.2.5", hosts[0]->getIPv4Reservation().toText()); } if (!is_second_source_primary) { EXPECT_EQ("192.0.2.5", hosts[2 - hosts_in_primary_source - 1]->getIPv4Reservation().toText()); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAll6BySubnetIP(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::5")); ASSERT_TRUE(hosts.empty()); // Add two reservations for the same subnet. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::5")); CfgMgr::instance().commit(); // If there non-matching subnet is specified, nothing should be returned. hosts = HostMgr::instance().getAll6(SubnetID(100), IOAddress("2001:db8:1::5")); ASSERT_TRUE(hosts.empty()); // For the correct subnet, there should be two reservations. hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::5")); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv6SubnetID()); // Make sure that two hosts were returned with different identifiers // but the same address. EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText()); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); EXPECT_TRUE(hosts[1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (is_second_source_primary) { EXPECT_TRUE(hosts[hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (!is_second_source_primary) { EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll4(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAll6ByIP(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1::10")); ASSERT_TRUE(hosts.empty()); // Prepare vectors of IPv6 address reservations for new hosts. std::vector addresses1; std::vector addresses2; addresses1.push_back(IOAddress("2001:db8:1::5")); addresses1.push_back(IOAddress("2001:db8:1::10")); addresses2.push_back(IOAddress("2001:db8:1::6")); addresses2.push_back(IOAddress("2001:db8:1::10")); // Add two hosts for the same subnet with 2 IPv6 addresses reservations per host. addHost6(data_source1, duids_[0], SubnetID(1), addresses1); addHost6(data_source2, duids_[1], SubnetID(1), addresses2); CfgMgr::instance().commit(); // If a non-matching subnet is specified, nothing should be returned. hosts = HostMgr::instance().getAll6(SubnetID(100), IOAddress("2001:db8:1::5")); ASSERT_TRUE(hosts.empty()); // For given IP there should be one reservation. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1::5")); ASSERT_EQ(1, hosts.size()); // For given IP there should be one reservation. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1::6")); ASSERT_EQ(1, hosts.size()); // For given IP there should be two reservations. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1::10")); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv6SubnetID()); // Make sure that all hosts were returned with different identifiers, and // they have expected reservations. EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText()); EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::10")))); EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); EXPECT_TRUE( hosts[1]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::10")))); EXPECT_TRUE( hosts[1]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1::10"), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::10")))); EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (is_second_source_primary) { EXPECT_TRUE(hosts[hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::10")))); EXPECT_TRUE(hosts[hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1::10"), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::10")))); EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5")))); } if (!is_second_source_primary) { EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::10")))); EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6")))); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll4(IOAddress("2001:db8:1::10"), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testGetAll6ByIpPrefix(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); // Initially, no reservations should be present. ConstHostCollection hosts = HostMgr::instance().getAll6(SubnetID(1), IOAddress("2001:db8:1:10::")); ASSERT_TRUE(hosts.empty()); // Prepare vectors of IPv6 prefix reservations for new hosts. std::vector addresses1; std::vector addresses2; addresses1.push_back(IOAddress("2001:db8:1:10::")); addresses1.push_back(IOAddress("2001:db8:1:11::")); addresses2.push_back(IOAddress("2001:db8:1:10::")); addresses2.push_back(IOAddress("2001:db8:1:12::")); // Add two hosts for the same subnet with 2 IPv6 prefix reservations per host. addHost6(data_source1, duids_[0], SubnetID(1), addresses1, 64); addHost6(data_source2, duids_[1], SubnetID(1), addresses2, 64); CfgMgr::instance().commit(); // If a non-matching subnet is specified, nothing should be returned. hosts = HostMgr::instance().getAll6(SubnetID(100), IOAddress("2001:db8:1:10::")); ASSERT_TRUE(hosts.empty()); // For given IP prefix there should be one reservation. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1:11::")); ASSERT_EQ(1, hosts.size()); // For given IP prefix there should be one reservation. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1:12::")); ASSERT_EQ(1, hosts.size()); // For given IP prefix there should be two reservations. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1:10::")); ASSERT_EQ(2, hosts.size()); // Make sure that subnet is correct. EXPECT_EQ(1, hosts[0]->getIPv6SubnetID()); EXPECT_EQ(1, hosts[1]->getIPv6SubnetID()); // Make sure that all hosts were returned with different identifiers, and // they have expected reservations. EXPECT_NE(hosts[0]->getIdentifierAsText(), hosts[1]->getIdentifierAsText()); EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:10::"), 64))); EXPECT_TRUE( hosts[0]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:11::"), 64))); EXPECT_TRUE( hosts[1]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:10::"), 64))); EXPECT_TRUE( hosts[1]->hasReservation(IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:12::"), 64))); // Make sure that the operation target is supported. bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); size_t hosts_in_primary_source = is_first_source_primary + is_second_source_primary; // Select hosts only from the primary source. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1:10::"), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source, hosts.size()); if (is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:10::"), 64))); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:11::"), 64))); } if (is_second_source_primary) { EXPECT_TRUE(hosts[hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:10::"), 64))); EXPECT_TRUE(hosts[hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:12::"), 64))); } // Select hosts only from the alternate sources. hosts = HostMgr::instance().getAll6(IOAddress("2001:db8:1:10::"), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(2 - hosts_in_primary_source, hosts.size()); if (!is_first_source_primary) { EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:10::"), 64))); EXPECT_TRUE(hosts[0]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:11::"), 64))); } if (!is_second_source_primary) { EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:10::"), 64))); EXPECT_TRUE(hosts[2 - hosts_in_primary_source - 1]->hasReservation( IPv6Resrv(IPv6Resrv::TYPE_PD, IOAddress("2001:db8:1:11::"), 64))); } // Select hosts for an unspecified source. hosts = HostMgr::instance().getAll4(IOAddress("2001:db8:1:10::"), HostMgrOperationTarget::UNSPECIFIED_SOURCE); EXPECT_EQ(0, hosts.size()); } void HostMgrTest::testAdd(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); bool has_alternate_source = !is_first_source_primary || !is_second_source_primary; // Initially, no reservations should be present. ConstHostCollection hosts4 = HostMgr::instance().getAll4(SubnetID(1)); ConstHostCollection hosts6 = HostMgr::instance().getAll6(SubnetID(1)); ASSERT_TRUE(hosts4.empty()); ASSERT_TRUE(hosts6.empty()); // Add hosts using the implicit operation target. auto host = HostPtr(new Host( hwaddrs_[0]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.5") )); if (has_alternate_source) { EXPECT_NO_THROW(HostMgr::instance().add(host)); } else { EXPECT_THROW(HostMgr::instance().add(host), NoHostDataSourceManager); } host = HostPtr(new Host( hwaddrs_[1]->toText(false), "hw-address", SUBNET_ID_UNUSED, SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS() )); host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::5"), 128)); if (has_alternate_source) { EXPECT_NO_THROW(HostMgr::instance().add(host)); } else { EXPECT_THROW(HostMgr::instance().add(host), NoHostDataSourceManager); } // Add hosts using the explicit operation target - all data sources. host = HostPtr(new Host( hwaddrs_[2]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.6") )); HostMgr::instance().add(host, HostMgrOperationTarget::ALL_SOURCES); host = HostPtr(new Host( hwaddrs_[3]->toText(false), "hw-address", SUBNET_ID_UNUSED, SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS() )); host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::6"), 128)); HostMgr::instance().add(host, HostMgrOperationTarget::ALL_SOURCES); // Add hosts using the explicit operation target - primary data source. host = HostPtr(new Host( hwaddrs_[4]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.7") )); HostMgr::instance().add(host, HostMgrOperationTarget::PRIMARY_SOURCE); host = HostPtr(new Host( hwaddrs_[5]->toText(false), "hw-address", SUBNET_ID_UNUSED, SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS() )); host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::7"), 128)); HostMgr::instance().add(host, HostMgrOperationTarget::PRIMARY_SOURCE); // Add hosts using the explicit operation target - alternate data sources. host = HostPtr(new Host( hwaddrs_[6]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.8") )); if (has_alternate_source) { EXPECT_NO_THROW(HostMgr::instance().add(host, HostMgrOperationTarget::ALTERNATE_SOURCES)); } else { EXPECT_THROW(HostMgr::instance().add(host, HostMgrOperationTarget::ALTERNATE_SOURCES), NoHostDataSourceManager); } host = HostPtr(new Host( hwaddrs_[7]->toText(false), "hw-address", SUBNET_ID_UNUSED, SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS() )); host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::8"), 128)); if (has_alternate_source) { EXPECT_NO_THROW(HostMgr::instance().add(host, HostMgrOperationTarget::ALTERNATE_SOURCES)); } else { EXPECT_THROW(HostMgr::instance().add(host, HostMgrOperationTarget::ALTERNATE_SOURCES), NoHostDataSourceManager); } // Add hosts using the explicit operation target - unspecified data source. host = HostPtr(new Host( hwaddrs_[8]->toText(false), "hw-address", SubnetID(1), SUBNET_ID_UNUSED, IOAddress("192.0.2.9") )); HostMgr::instance().add(host, HostMgrOperationTarget::UNSPECIFIED_SOURCE); host = HostPtr(new Host( hwaddrs_[9]->toText(false), "hw-address", SUBNET_ID_UNUSED, SubnetID(1), IOAddress::IPV4_ZERO_ADDRESS() )); host->addReservation(IPv6Resrv(IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::9"), 128)); HostMgr::instance().add(host, HostMgrOperationTarget::UNSPECIFIED_SOURCE); // Verify the hosts were added. // ALL_SOURCES + PRIMARY_SOURCE targets for IPv4 and IPv6. size_t hosts_in_primary_source = 2 * 2 * (is_first_source_primary || is_second_source_primary); // Default + ALL_SOURCES + ALTERNATE_SOURCES targets for IPv4 and IPv6. size_t hosts_in_alternate_sources = 3 * 2 * (!is_first_source_primary || !is_second_source_primary); // Verify primary sources. hosts4 = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::PRIMARY_SOURCE); hosts6 = HostMgr::instance().getAll6(SubnetID(1), HostMgrOperationTarget::PRIMARY_SOURCE); EXPECT_EQ(hosts_in_primary_source / 2, hosts4.size()); EXPECT_EQ(hosts_in_primary_source / 2, hosts6.size()); // Verify alternate sources. hosts4 = HostMgr::instance().getAll4(SubnetID(1), HostMgrOperationTarget::ALTERNATE_SOURCES); hosts6 = HostMgr::instance().getAll6(SubnetID(1), HostMgrOperationTarget::ALTERNATE_SOURCES); EXPECT_EQ(hosts_in_alternate_sources / 2, hosts4.size()); EXPECT_EQ(hosts_in_alternate_sources / 2, hosts6.size()); } void HostMgrTest::testDeleteByIDAndAddress(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); bool has_alternate_source = !is_first_source_primary || !is_second_source_primary; bool has_primary_source = is_first_source_primary || is_second_source_primary; size_t hosts4_in_primary_source = 2 * (is_first_source_primary + is_second_source_primary); size_t hosts6_in_primary_source = is_first_source_primary + is_second_source_primary; size_t hosts4_in_alternate_sources = 4 - hosts4_in_primary_source; size_t hosts6_in_alternate_sources = 2 - hosts6_in_primary_source; // Delete from the explicit operation target - all sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[1], SubnetID(1), IOAddress("192.0.2.5")); addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[1], SubnetID(1), IOAddress("2001:db8:1::5")); CfgMgr::instance().commit(); // 4 IPv4 reservations - 2 sources * 2 addresses. ASSERT_EQ(4, HostMgr::instance().getAll4(SubnetID(1)).size()); // 2 IPv6 reservations - each with 2 reserved addresses. ASSERT_EQ(2, HostMgr::instance().getAll6(SubnetID(1)).size()); EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALL_SOURCES)); EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALL_SOURCES)); EXPECT_TRUE(HostMgr::instance().getAll4(SubnetID(1)).empty()); EXPECT_TRUE(HostMgr::instance().getAll6(SubnetID(1)).empty()); // Delete from the default operation target. addHost4(data_source1, hwaddrs_[2], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[3], SubnetID(1), IOAddress("192.0.2.5")); addHost6(data_source1, duids_[2], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[3], SubnetID(1), IOAddress("2001:db8:1::5")); CfgMgr::instance().commit(); ASSERT_EQ(4, HostMgr::instance().getAll4(SubnetID(1)).size()); ASSERT_EQ(2, HostMgr::instance().getAll6(SubnetID(1)).size()); if (has_alternate_source) { EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"))); EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"))); } else { EXPECT_THROW(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5")), NoHostDataSourceManager); EXPECT_THROW(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5")), NoHostDataSourceManager); } EXPECT_EQ(hosts4_in_primary_source, HostMgr::instance().getAll4(SubnetID(1)).size()); EXPECT_EQ(hosts6_in_primary_source, HostMgr::instance().getAll6(SubnetID(1)).size()); HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALL_SOURCES); HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALL_SOURCES); // Delete from the explicit operation target - alternate sources. addHost4(data_source1, hwaddrs_[4], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[5], SubnetID(1), IOAddress("192.0.2.5")); addHost6(data_source1, duids_[4], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[5], SubnetID(1), IOAddress("2001:db8:1::5")); CfgMgr::instance().commit(); if (has_alternate_source) { EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALTERNATE_SOURCES)); EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALTERNATE_SOURCES)); } else { EXPECT_THROW(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALTERNATE_SOURCES), NoHostDataSourceManager); EXPECT_THROW(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALTERNATE_SOURCES), NoHostDataSourceManager); } EXPECT_EQ(hosts4_in_primary_source, HostMgr::instance().getAll4(SubnetID(1)).size()); EXPECT_EQ(hosts6_in_primary_source, HostMgr::instance().getAll6(SubnetID(1)).size()); HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALL_SOURCES); HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALL_SOURCES); // Delete from the explicit operation target - primary source. addHost4(data_source1, hwaddrs_[6], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[7], SubnetID(1), IOAddress("192.0.2.5")); addHost6(data_source1, duids_[6], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[7], SubnetID(1), IOAddress("2001:db8:1::5")); CfgMgr::instance().commit(); if (has_primary_source) { EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::PRIMARY_SOURCE)); EXPECT_TRUE(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::PRIMARY_SOURCE)); } else { EXPECT_FALSE(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::PRIMARY_SOURCE)); EXPECT_FALSE(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::PRIMARY_SOURCE)); } EXPECT_EQ(hosts4_in_alternate_sources, HostMgr::instance().getAll4(SubnetID(1)).size()); EXPECT_EQ(hosts6_in_alternate_sources, HostMgr::instance().getAll6(SubnetID(1)).size()); HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALL_SOURCES); HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALL_SOURCES); // Delete from the explicit operation target - unspecified source. addHost4(data_source1, hwaddrs_[8], SubnetID(1), IOAddress("192.0.2.5")); addHost4(data_source2, hwaddrs_[9], SubnetID(1), IOAddress("192.0.2.5")); addHost6(data_source1, duids_[8], SubnetID(1), IOAddress("2001:db8:1::5")); addHost6(data_source2, duids_[9], SubnetID(1), IOAddress("2001:db8:1::5")); CfgMgr::instance().commit(); EXPECT_FALSE(HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::UNSPECIFIED_SOURCE)); EXPECT_FALSE(HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::UNSPECIFIED_SOURCE)); EXPECT_EQ(4, HostMgr::instance().getAll4(SubnetID(1)).size()); EXPECT_EQ(2, HostMgr::instance().getAll6(SubnetID(1)).size()); HostMgr::instance().del(SubnetID(1), IOAddress("192.0.2.5"), HostMgrOperationTarget::ALL_SOURCES); HostMgr::instance().del(SubnetID(1), IOAddress("2001:db8:1::5"), HostMgrOperationTarget::ALL_SOURCES); } void HostMgrTest::testDelete4ByIDAndIdentifier(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); if (is_first_source_primary && is_second_source_primary) { // Two primary data sources - in fact it is a single source. // Delete from all sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); CfgMgr::instance().commit(); EXPECT_TRUE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALL_SOURCES)); EXPECT_TRUE(HostMgr::instance().getAll4(SubnetID(1)).empty()); // Delete from default (alternate) sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); CfgMgr::instance().commit(); EXPECT_THROW(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size()), NoHostDataSourceManager); EXPECT_EQ(1, HostMgr::instance().getAll4(SubnetID(1)).size()); // Delete from explicit alternate sources. EXPECT_THROW(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALTERNATE_SOURCES), NoHostDataSourceManager); EXPECT_EQ(1, HostMgr::instance().getAll4(SubnetID(1)).size()); // Delete from unspecified source. EXPECT_FALSE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE)); EXPECT_EQ(1, HostMgr::instance().getAll4(SubnetID(1)).size()); // Delete from primary source. EXPECT_TRUE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::PRIMARY_SOURCE)); EXPECT_TRUE(HostMgr::instance().getAll4(SubnetID(1)).empty()); } else if (is_first_source_primary != is_second_source_primary) { // One primary data source and one alternate data source. // Delete from all sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); addHost4(data_source2, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); CfgMgr::instance().commit(); EXPECT_TRUE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALL_SOURCES)); EXPECT_TRUE(HostMgr::instance().getAll4(SubnetID(1)).empty()); // Delete from default (alternate) sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); addHost4(data_source2, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); CfgMgr::instance().commit(); EXPECT_TRUE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size())); // The host reservation in the primary source still exists. EXPECT_EQ(1, HostMgr::instance().getAll4(SubnetID(1)).size()); // Clean the host reservations. HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALL_SOURCES); // Delete from explicit alternate sources. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); addHost4(data_source2, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); EXPECT_TRUE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALTERNATE_SOURCES)); // The host reservation in the primary source still exists. EXPECT_EQ(1, HostMgr::instance().getAll4(SubnetID(1)).size()); // Clean the host reservations. HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALL_SOURCES); // Delete from unspecified source. addHost4(data_source1, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); addHost4(data_source2, hwaddrs_[0], SubnetID(1), IOAddress("192.168.0.2")); EXPECT_FALSE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE)); EXPECT_EQ(2, HostMgr::instance().getAll4(SubnetID(1)).size()); // Delete from primary source. EXPECT_TRUE(HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::PRIMARY_SOURCE)); // The host reservation in the alternate source still exists. EXPECT_EQ(1, HostMgr::instance().getAll4(SubnetID(1)).size()); // Clean the host reservations. HostMgr::instance().del4(SubnetID(1), Host::IDENT_HWADDR, &hwaddrs_[0]->hwaddr_[0], hwaddrs_[0]->hwaddr_.size(), HostMgrOperationTarget::ALL_SOURCES); } else { // Not defined. isc_throw(NotImplemented, "not implemented test case for two alternate sources"); } } void HostMgrTest::testDelete6ByIDAndIdentifier(BaseHostDataSource& data_source1, BaseHostDataSource& data_source2) { // Set the mode of operation with multiple reservations for the same // IP address. ASSERT_TRUE(HostMgr::instance().setIPReservationsUnique(false)); CfgMgr::instance().getStagingCfg()->getCfgHosts()->setIPReservationsUnique(false); bool is_first_source_primary = isPrimaryDataSource(data_source1); bool is_second_source_primary = isPrimaryDataSource(data_source2); if (is_first_source_primary && is_second_source_primary) { // Two primary data sources - in fact it is a single source. // Delete from all sources. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); CfgMgr::instance().commit(); EXPECT_TRUE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALL_SOURCES)); EXPECT_TRUE(HostMgr::instance().getAll6(SubnetID(1)).empty()); // Delete from default (alternate) sources. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); CfgMgr::instance().commit(); EXPECT_THROW(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size()), NoHostDataSourceManager); EXPECT_EQ(1, HostMgr::instance().getAll6(SubnetID(1)).size()); // Delete from explicit alternate sources. EXPECT_THROW(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALTERNATE_SOURCES), NoHostDataSourceManager); EXPECT_EQ(1, HostMgr::instance().getAll6(SubnetID(1)).size()); // Delete from unspecified source. EXPECT_FALSE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE)); EXPECT_EQ(1, HostMgr::instance().getAll6(SubnetID(1)).size()); // Delete from primary source. EXPECT_TRUE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::PRIMARY_SOURCE)); EXPECT_TRUE(HostMgr::instance().getAll6(SubnetID(1)).empty()); } else if (is_first_source_primary != is_second_source_primary) { // One primary data source and one alternate data source. // Delete from all sources. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); addHost6(data_source2, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); CfgMgr::instance().commit(); EXPECT_TRUE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALL_SOURCES)); EXPECT_TRUE(HostMgr::instance().getAll6(SubnetID(1)).empty()); // Delete from default (alternate) sources. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); addHost6(data_source2, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); CfgMgr::instance().commit(); EXPECT_TRUE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size())); // The host reservation in the primary source still exists. EXPECT_EQ(1, HostMgr::instance().getAll6(SubnetID(1)).size()); // Clean the host reservations. HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALL_SOURCES); // Delete from explicit alternate sources. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); addHost6(data_source2, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); EXPECT_TRUE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALTERNATE_SOURCES)); // The host reservation in the primary source still exists. EXPECT_EQ(1, HostMgr::instance().getAll6(SubnetID(1)).size()); // Clean the host reservations. HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALL_SOURCES); // Delete from unspecified source. addHost6(data_source1, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); addHost6(data_source2, duids_[0], SubnetID(1), IOAddress("2001:db8:1::5"), 128); EXPECT_FALSE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::UNSPECIFIED_SOURCE)); EXPECT_EQ(2, HostMgr::instance().getAll6(SubnetID(1)).size()); // Delete from primary source. EXPECT_TRUE(HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::PRIMARY_SOURCE)); // The host reservation in the alternate source still exists. EXPECT_EQ(1, HostMgr::instance().getAll6(SubnetID(1)).size()); // Clean the host reservations. HostMgr::instance().del6(SubnetID(1), Host::IDENT_DUID, &duids_[0]->getDuid()[0], duids_[0]->getDuid().size(), HostMgrOperationTarget::ALL_SOURCES); } else { // Not defined. isc_throw(NotImplemented, "not implemented test case for two alternate sources"); } } bool HostMgrTest::isPrimaryDataSource(const BaseHostDataSource& data_source) const { const auto ptr = dynamic_cast(&data_source); return ptr != nullptr; } void GenericHostDataSourceTest::testUpdate() { // Make sure the host data source is initialized. ASSERT_TRUE(hdsptr_); // Create a host with an IPv4 address reservation. HostPtr const host(HostDataSourceUtils::initializeHost4("192.0.2.1", Host::IDENT_HWADDR)); SubnetID const v4_subnet(host->getIPv4SubnetID()); SubnetID const v6_subnet(host->getIPv6SubnetID()); string hwaddr(host->getHWAddress()->toText(false)); boost::replace_all(hwaddr, ":", ""); boost::to_upper(hwaddr); // Updating a host that doesn't exist should throw. EXPECT_THROW_MSG(hdsptr_->update(host), HostNotFound, "Host not updated (not found)."); // There should be no hosts. ConstHostCollection hosts(hdsptr_->getAll4(v4_subnet)); EXPECT_EQ(0, hosts.size()); // Add the host. EXPECT_NO_THROW(hdsptr_->add(host)); // The host should be there. hosts = hdsptr_->getAll4(v4_subnet); EXPECT_EQ(1, hosts.size()); EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + " ipv6_subnet_id=" + to_string(v6_subnet) + " hostname=(empty) " "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " "ipv6_reservations=(none)", hosts[0]->toText()); // Update the host. Change nothing. EXPECT_NO_THROW(hdsptr_->update(host)); // The same host should be in the data source. hosts = hdsptr_->getAll4(v4_subnet); EXPECT_EQ(1, hosts.size()); EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + " ipv6_subnet_id=" + to_string(v6_subnet) + " hostname=(empty) " "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " "ipv6_reservations=(none)", hosts[0]->toText()); // Update the host with new hostname. host->setHostname("foo.example.com"); EXPECT_NO_THROW(hdsptr_->update(host)); // The change should be reflected in the data source. hosts = hdsptr_->getAll4(v4_subnet); EXPECT_EQ(1, hosts.size()); EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + " ipv6_subnet_id=" + to_string(v6_subnet) + " hostname=foo.example.com " "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " "ipv6_reservations=(none)", hosts[0]->toText()); // Remove hostname from host. host->setHostname(""); EXPECT_NO_THROW(hdsptr_->update(host)); // The change should be reflected in the data source. hosts = hdsptr_->getAll4(v4_subnet); EXPECT_EQ(1, hosts.size()); EXPECT_EQ("hwaddr=" + hwaddr + " ipv4_subnet_id=" + to_string(v4_subnet) + " ipv6_subnet_id=" + to_string(v6_subnet) + " hostname=(empty) " "ipv4_reservation=192.0.2.1 siaddr=(no) sname=(empty) file=(empty) key=(empty) " "ipv6_reservations=(none)", hosts[0]->toText()); } } // namespace test } // namespace dhcp } // namespace isc