Commit 3d6c1163 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac3359' (shared unit-tests for all DHCP backends)

parents 305e3c4c 516b7c2f
......@@ -61,6 +61,7 @@ libdhcpsrv_unittests_SOURCES += dbaccess_parser_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_mgr_factory_unittest.cc
libdhcpsrv_unittests_SOURCES += lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += generic_lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += memfile_lease_mgr_unittest.cc
libdhcpsrv_unittests_SOURCES += dhcp_parsers_unittest.cc
if HAVE_MYSQL
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcpsrv/tests/generic_lease_mgr_unittest.h>
#include <dhcpsrv/tests/test_utils.h>
#include <asiolink/io_address.h>
#include <gtest/gtest.h>
#include <sstream>
using namespace std;
using namespace isc::asiolink;
namespace isc {
namespace dhcp {
namespace test {
// IPv4 and IPv6 addresses used in the tests
const char* ADDRESS4[] = {
"192.0.2.0", "192.0.2.1", "192.0.2.2", "192.0.2.3",
"192.0.2.4", "192.0.2.5", "192.0.2.6", "192.0.2.7",
NULL
};
const char* ADDRESS6[] = {
"2001:db8::0", "2001:db8::1", "2001:db8::2", "2001:db8::3",
"2001:db8::4", "2001:db8::5", "2001:db8::6", "2001:db8::7",
NULL
};
// Lease types that correspond to ADDRESS6 leases
static const Lease::Type LEASETYPE6[] = {
Lease::TYPE_NA, Lease::TYPE_TA, Lease::TYPE_PD, Lease::TYPE_NA,
Lease::TYPE_TA, Lease::TYPE_PD, Lease::TYPE_NA, Lease::TYPE_TA
};
GenericLeaseMgrTest::GenericLeaseMgrTest()
: lmptr_(NULL) {
// Initialize address strings and IOAddresses
for (int i = 0; ADDRESS4[i] != NULL; ++i) {
string addr(ADDRESS4[i]);
straddress4_.push_back(addr);
IOAddress ioaddr(addr);
ioaddress4_.push_back(ioaddr);
}
for (int i = 0; ADDRESS6[i] != NULL; ++i) {
string addr(ADDRESS6[i]);
straddress6_.push_back(addr);
IOAddress ioaddr(addr);
ioaddress6_.push_back(ioaddr);
/// Let's create different lease types. We use LEASETYPE6 values as
/// a template
leasetype6_.push_back(LEASETYPE6[i]);
}
}
GenericLeaseMgrTest::~GenericLeaseMgrTest() {
// Does nothing. The derived classes are expected to clean up, i.e.
// remove the lmptr_ pointer.
}
Lease4Ptr
GenericLeaseMgrTest::initializeLease4(std::string address) {
Lease4Ptr lease(new Lease4());
// Set the address of the lease
lease->addr_ = IOAddress(address);
// Initialize unused fields.
lease->ext_ = 0; // Not saved
lease->t1_ = 0; // Not saved
lease->t2_ = 0; // Not saved
lease->fixed_ = false; // Unused
lease->comments_ = std::string(""); // Unused
// Set other parameters. For historical reasons, address 0 is not used.
if (address == straddress4_[0]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x08);
lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x42)));
lease->valid_lft_ = 8677;
lease->cltt_ = 168256;
lease->subnet_id_ = 23;
lease->fqdn_rev_ = true;
lease->fqdn_fwd_ = false;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress4_[1]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x19);
lease->client_id_ = ClientIdPtr(
new ClientId(vector<uint8_t>(8, 0x53)));
lease->valid_lft_ = 3677;
lease->cltt_ = 123456;
lease->subnet_id_ = 73;
lease->fqdn_rev_ = true;
lease->fqdn_fwd_ = true;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress4_[2]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x2a);
lease->client_id_ = ClientIdPtr(new ClientId(vector<uint8_t>(8, 0x64)));
lease->valid_lft_ = 5412;
lease->cltt_ = 234567;
lease->subnet_id_ = 73; // Same as lease 1
lease->fqdn_rev_ = false;
lease->fqdn_fwd_ = false;
lease->hostname_ = "";
} else if (address == straddress4_[3]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x19); // Same as lease 1
lease->client_id_ = ClientIdPtr(
new ClientId(vector<uint8_t>(8, 0x75)));
// The times used in the next tests are deliberately restricted - we
// should be able to cope with valid lifetimes up to 0xffffffff.
// However, this will lead to overflows.
// @TODO: test overflow conditions when code has been fixed
lease->valid_lft_ = 7000;
lease->cltt_ = 234567;
lease->subnet_id_ = 37;
lease->fqdn_rev_ = true;
lease->fqdn_fwd_ = true;
lease->hostname_ = "otherhost.example.com.";
} else if (address == straddress4_[4]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x4c);
// Same ClientId as straddr4_[1]
lease->client_id_ = ClientIdPtr(
new ClientId(vector<uint8_t>(8, 0x53))); // Same as lease 1
lease->valid_lft_ = 7736;
lease->cltt_ = 222456;
lease->subnet_id_ = 85;
lease->fqdn_rev_ = true;
lease->fqdn_fwd_ = true;
lease->hostname_ = "otherhost.example.com.";
} else if (address == straddress4_[5]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x19); // Same as lease 1
// Same ClientId and IAID as straddress4_1
lease->client_id_ = ClientIdPtr(
new ClientId(vector<uint8_t>(8, 0x53))); // Same as lease 1
lease->valid_lft_ = 7832;
lease->cltt_ = 227476;
lease->subnet_id_ = 175;
lease->fqdn_rev_ = false;
lease->fqdn_fwd_ = false;
lease->hostname_ = "otherhost.example.com.";
} else if (address == straddress4_[6]) {
lease->hwaddr_ = vector<uint8_t>(6, 0x6e);
// Same ClientId as straddress4_1
lease->client_id_ = ClientIdPtr(
new ClientId(vector<uint8_t>(8, 0x53))); // Same as lease 1
lease->valid_lft_ = 1832;
lease->cltt_ = 627476;
lease->subnet_id_ = 112;
lease->fqdn_rev_ = false;
lease->fqdn_fwd_ = true;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress4_[7]) {
lease->hwaddr_ = vector<uint8_t>(); // Empty
lease->client_id_ = ClientIdPtr(); // Empty
lease->valid_lft_ = 7975;
lease->cltt_ = 213876;
lease->subnet_id_ = 19;
lease->fqdn_rev_ = true;
lease->fqdn_fwd_ = true;
lease->hostname_ = "myhost.example.com.";
} else {
// Unknown address, return an empty pointer.
lease.reset();
}
return (lease);
}
Lease6Ptr
GenericLeaseMgrTest::initializeLease6(std::string address) {
Lease6Ptr lease(new Lease6());
// Set the address of the lease
lease->addr_ = IOAddress(address);
// Initialize unused fields.
lease->t1_ = 0; // Not saved
lease->t2_ = 0; // Not saved
lease->fixed_ = false; // Unused
lease->comments_ = std::string(""); // Unused
// Set other parameters. For historical reasons, address 0 is not used.
if (address == straddress6_[0]) {
lease->type_ = leasetype6_[0];
lease->prefixlen_ = 4;
lease->iaid_ = 142;
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x77)));
lease->preferred_lft_ = 900;
lease->valid_lft_ = 8677;
lease->cltt_ = 168256;
lease->subnet_id_ = 23;
lease->fqdn_fwd_ = true;
lease->fqdn_rev_ = true;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress6_[1]) {
lease->type_ = leasetype6_[1];
lease->prefixlen_ = 0;
lease->iaid_ = 42;
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
lease->preferred_lft_ = 3600;
lease->valid_lft_ = 3677;
lease->cltt_ = 123456;
lease->subnet_id_ = 73;
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress6_[2]) {
lease->type_ = leasetype6_[2];
lease->prefixlen_ = 7;
lease->iaid_ = 89;
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x3a)));
lease->preferred_lft_ = 1800;
lease->valid_lft_ = 5412;
lease->cltt_ = 234567;
lease->subnet_id_ = 73; // Same as lease 1
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = false;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress6_[3]) {
lease->type_ = leasetype6_[3];
lease->prefixlen_ = 28;
lease->iaid_ = 0xfffffffe;
vector<uint8_t> duid;
for (uint8_t i = 31; i < 126; ++i) {
duid.push_back(i);
}
lease->duid_ = DuidPtr(new DUID(duid));
// The times used in the next tests are deliberately restricted - we
// should be able to cope with valid lifetimes up to 0xffffffff.
// However, this will lead to overflows.
// @TODO: test overflow conditions when code has been fixed
lease->preferred_lft_ = 7200;
lease->valid_lft_ = 7000;
lease->cltt_ = 234567;
lease->subnet_id_ = 37;
lease->fqdn_fwd_ = true;
lease->fqdn_rev_ = false;
lease->hostname_ = "myhost.example.com.";
} else if (address == straddress6_[4]) {
// Same DUID and IAID as straddress6_1
lease->type_ = leasetype6_[4];
lease->prefixlen_ = 15;
lease->iaid_ = 42;
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
lease->preferred_lft_ = 4800;
lease->valid_lft_ = 7736;
lease->cltt_ = 222456;
lease->subnet_id_ = 671;
lease->fqdn_fwd_ = true;
lease->fqdn_rev_ = true;
lease->hostname_ = "otherhost.example.com.";
} else if (address == straddress6_[5]) {
// Same DUID and IAID as straddress6_1
lease->type_ = leasetype6_[5];
lease->prefixlen_ = 24;
lease->iaid_ = 42; // Same as lease 4
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
// Same as lease 4
lease->preferred_lft_ = 5400;
lease->valid_lft_ = 7832;
lease->cltt_ = 227476;
lease->subnet_id_ = 175;
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "hostname.example.com.";
} else if (address == straddress6_[6]) {
// Same DUID as straddress6_1
lease->type_ = leasetype6_[6];
lease->prefixlen_ = 24;
lease->iaid_ = 93;
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0x42)));
// Same as lease 4
lease->preferred_lft_ = 5400;
lease->valid_lft_ = 1832;
lease->cltt_ = 627476;
lease->subnet_id_ = 112;
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "hostname.example.com.";
} else if (address == straddress6_[7]) {
// Same IAID as straddress6_1
lease->type_ = leasetype6_[7];
lease->prefixlen_ = 24;
lease->iaid_ = 42;
lease->duid_ = DuidPtr(new DUID(vector<uint8_t>(8, 0xe5)));
lease->preferred_lft_ = 5600;
lease->valid_lft_ = 7975;
lease->cltt_ = 213876;
lease->subnet_id_ = 19;
lease->fqdn_fwd_ = false;
lease->fqdn_rev_ = true;
lease->hostname_ = "hostname.example.com.";
} else {
// Unknown address, return an empty pointer.
lease.reset();
}
return (lease);
}
template <typename T>
void GenericLeaseMgrTest::checkLeasesDifferent(const std::vector<T>& leases) const {
// Check they were created
for (int i = 0; i < leases.size(); ++i) {
ASSERT_TRUE(leases[i]);
}
// Check they are different
for (int i = 0; i < (leases.size() - 1); ++i) {
for (int j = (i + 1); j < leases.size(); ++j) {
stringstream s;
s << "Comparing leases " << i << " & " << j << " for equality";
SCOPED_TRACE(s.str());
EXPECT_TRUE(*leases[i] != *leases[j]);
}
}
}
vector<Lease4Ptr>
GenericLeaseMgrTest::createLeases4() {
// Create leases for each address
vector<Lease4Ptr> leases;
for (int i = 0; i < straddress4_.size(); ++i) {
leases.push_back(initializeLease4(straddress4_[i]));
}
EXPECT_EQ(8, leases.size());
// Check all were created and that they are different.
checkLeasesDifferent(leases);
return (leases);
}
vector<Lease6Ptr>
GenericLeaseMgrTest::createLeases6() {
// Create leases for each address
vector<Lease6Ptr> leases;
for (int i = 0; i < straddress6_.size(); ++i) {
leases.push_back(initializeLease6(straddress6_[i]));
}
EXPECT_EQ(8, leases.size());
// Check all were created and that they are different.
checkLeasesDifferent(leases);
return (leases);
}
void
GenericLeaseMgrTest::testGetLease4ClientId() {
// Let's initialize a specific lease ...
Lease4Ptr lease = initializeLease4(straddress4_[1]);
EXPECT_TRUE(lmptr_->addLease(lease));
Lease4Collection returned = lmptr_->getLease4(*lease->client_id_);
ASSERT_EQ(1, returned.size());
// We should retrieve our lease...
detailCompareLease(lease, *returned.begin());
lease = initializeLease4(straddress4_[2]);
returned = lmptr_->getLease4(*lease->client_id_);
ASSERT_EQ(0, returned.size());
}
void
GenericLeaseMgrTest::testGetLease4NullClientId() {
// Let's initialize a specific lease ... But this time
// We keep its client id for further lookup and
// We clearly 'reset' it ...
Lease4Ptr leaseA = initializeLease4(straddress4_[4]);
ClientIdPtr client_id = leaseA->client_id_;
leaseA->client_id_ = ClientIdPtr();
ASSERT_TRUE(lmptr_->addLease(leaseA));
Lease4Collection returned = lmptr_->getLease4(*client_id);
// Shouldn't have our previous lease ...
ASSERT_TRUE(returned.empty());
// Add another lease with the non-NULL client id, and make sure that the
// lookup will not break due to existence of both leases with non-NULL and
// NULL client ids.
Lease4Ptr leaseB = initializeLease4(straddress4_[0]);
// Shouldn't throw any null pointer exception
ASSERT_TRUE(lmptr_->addLease(leaseB));
// Try to get the lease.
returned = lmptr_->getLease4(*client_id);
ASSERT_TRUE(returned.empty());
// Let's make it more interesting and add another lease with NULL client id.
Lease4Ptr leaseC = initializeLease4(straddress4_[5]);
leaseC->client_id_.reset();
ASSERT_TRUE(lmptr_->addLease(leaseC));
returned = lmptr_->getLease4(*client_id);
ASSERT_TRUE(returned.empty());
// But getting the lease with non-NULL client id should be successful.
returned = lmptr_->getLease4(*leaseB->client_id_);
ASSERT_EQ(1, returned.size());
}
void
GenericLeaseMgrTest::testLease4NullClientId() {
// Get the leases to be used for the test.
vector<Lease4Ptr> leases = createLeases4();
// Let's clear client-id pointers
leases[1]->client_id_ = ClientIdPtr();
leases[2]->client_id_ = ClientIdPtr();
leases[3]->client_id_ = ClientIdPtr();
// Start the tests. Add three leases to the database, read them back and
// check they are what we think they are.
EXPECT_TRUE(lmptr_->addLease(leases[1]));
EXPECT_TRUE(lmptr_->addLease(leases[2]));
EXPECT_TRUE(lmptr_->addLease(leases[3]));
lmptr_->commit();
// Reopen the database to ensure that they actually got stored.
reopen();
Lease4Ptr l_returned = lmptr_->getLease4(ioaddress4_[1]);
ASSERT_TRUE(l_returned);
detailCompareLease(leases[1], l_returned);
l_returned = lmptr_->getLease4(ioaddress4_[2]);
ASSERT_TRUE(l_returned);
detailCompareLease(leases[2], l_returned);
l_returned = lmptr_->getLease4(ioaddress4_[3]);
ASSERT_TRUE(l_returned);
detailCompareLease(leases[3], l_returned);
// Check that we can't add a second lease with the same address
EXPECT_FALSE(lmptr_->addLease(leases[1]));
// Check that we can get the lease by HWAddr
HWAddr tmp(leases[2]->hwaddr_, HTYPE_ETHER);
Lease4Collection returned = lmptr_->getLease4(tmp);
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[2], *returned.begin());
l_returned = lmptr_->getLease4(tmp, leases[2]->subnet_id_);
ASSERT_TRUE(l_returned);
detailCompareLease(leases[2], l_returned);
// Check that we can update the lease
// Modify some fields in lease 1 (not the address) and update it.
++leases[1]->subnet_id_;
leases[1]->valid_lft_ *= 2;
lmptr_->updateLease4(leases[1]);
// ... and check that the lease is indeed updated
l_returned = lmptr_->getLease4(ioaddress4_[1]);
ASSERT_TRUE(l_returned);
detailCompareLease(leases[1], l_returned);
// Delete a lease, check that it's gone, and that we can't delete it
// a second time.
EXPECT_TRUE(lmptr_->deleteLease(ioaddress4_[1]));
l_returned = lmptr_->getLease4(ioaddress4_[1]);
EXPECT_FALSE(l_returned);
EXPECT_FALSE(lmptr_->deleteLease(ioaddress4_[1]));
// Check that the second address is still there.
l_returned = lmptr_->getLease4(ioaddress4_[2]);
ASSERT_TRUE(l_returned);
detailCompareLease(leases[2], l_returned);
}
void
GenericLeaseMgrTest::testGetLease4HWAddr1() {
// Let's initialize two different leases 4 and just add the first ...
Lease4Ptr leaseA = initializeLease4(straddress4_[5]);
HWAddr hwaddrA(leaseA->hwaddr_, HTYPE_ETHER);
HWAddr hwaddrB(vector<uint8_t>(6, 0x80), HTYPE_ETHER);
EXPECT_TRUE(lmptr_->addLease(leaseA));
// we should not have a lease, with this MAC Addr
Lease4Collection returned = lmptr_->getLease4(hwaddrB);
ASSERT_EQ(0, returned.size());
// But with this one
returned = lmptr_->getLease4(hwaddrA);
ASSERT_EQ(1, returned.size());
}
void
GenericLeaseMgrTest::testGetLease4HWAddr2() {
// Get the leases to be used for the test and add to the database
vector<Lease4Ptr> leases = createLeases4();
for (int i = 0; i < leases.size(); ++i) {
EXPECT_TRUE(lmptr_->addLease(leases[i]));
}
// Get the leases matching the hardware address of lease 1
/// @todo: Simply use HWAddr directly once 2589 is implemented
HWAddr tmp(leases[1]->hwaddr_, HTYPE_ETHER);
Lease4Collection returned = lmptr_->getLease4(tmp);
// Should be three leases, matching leases[1], [3] and [5].
ASSERT_EQ(3, returned.size());
// Easiest way to check is to look at the addresses.
vector<string> addresses;
for (Lease4Collection::const_iterator i = returned.begin();
i != returned.end(); ++i) {
addresses.push_back((*i)->addr_.toText());
}
sort(addresses.begin(), addresses.end());
EXPECT_EQ(straddress4_[1], addresses[0]);
EXPECT_EQ(straddress4_[3], addresses[1]);
EXPECT_EQ(straddress4_[5], addresses[2]);
// Repeat test with just one expected match
/// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[2]->hwaddr_, HTYPE_ETHER));
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[2], *returned.begin());
// Check that an empty vector is valid
EXPECT_TRUE(leases[7]->hwaddr_.empty());
/// @todo: Simply use HWAddr directly once 2589 is implemented
returned = lmptr_->getLease4(HWAddr(leases[7]->hwaddr_, HTYPE_ETHER));
ASSERT_EQ(1, returned.size());
detailCompareLease(leases[7], *returned.begin());
// Try to get something with invalid hardware address
vector<uint8_t> invalid(6, 0);
returned = lmptr_->getLease4(invalid);
EXPECT_EQ(0, returned.size());
}
void
GenericLeaseMgrTest::testGetLease4ClientIdHWAddrSubnetId() {
Lease4Ptr leaseA = initializeLease4(straddress4_[4]);
Lease4Ptr leaseB = initializeLease4(straddress4_[5]);
Lease4Ptr leaseC = initializeLease4(straddress4_[6]);
// Set NULL client id for one of the leases. This is to make sure that such
// a lease may coexist with other leases with non NULL client id.
leaseC->client_id_.reset();
HWAddr hwaddrA(leaseA->hwaddr_, HTYPE_ETHER);
HWAddr hwaddrB(leaseB->hwaddr_, HTYPE_ETHER);
HWAddr hwaddrC(leaseC->hwaddr_, HTYPE_ETHER);