From: Tomek Mrugalski Date: Thu, 10 Mar 2016 10:49:32 +0000 (+0100) Subject: [4339] Unit-test for updating lease indexes implemented. X-Git-Tag: trac4268a_base~5^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9bd45528fd4835e65b8140d8b7f0e7170212cf93;p=thirdparty%2Fkea.git [4339] Unit-test for updating lease indexes implemented. Also updated tests for Lease6::toText function. --- diff --git a/src/lib/dhcpsrv/tests/lease_unittest.cc b/src/lib/dhcpsrv/tests/lease_unittest.cc index 6dc2e56b76..3604033756 100644 --- a/src/lib/dhcpsrv/tests/lease_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -838,6 +838,7 @@ TEST(Lease6Test, toText) { << "Pref life: 400\n" << "Valid life: 800\n" << "Cltt: 12345678\n" + << "DUID: 00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\n" << "Hardware addr: " << hwaddr->toText(false) << "\n" << "Subnet ID: 5678\n" << "State: declined\n"; @@ -854,6 +855,7 @@ TEST(Lease6Test, toText) { << "Pref life: 400\n" << "Valid life: 800\n" << "Cltt: 12345678\n" + << "DUID: 00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f\n" << "Hardware addr: (none)\n" << "Subnet ID: 5678\n" << "State: declined\n"; diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index 3173fccdbd..4daa60c685 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -232,8 +233,126 @@ public: return (iterations < iterations_max); } + /// @brief Generates a DHCPv4 lease with random content. + /// + /// The following lease parameters are randomly generated: + /// - HW address, + /// - client identifier, + /// - hostname, + /// - subnet identifier, + /// - client last transmission time, + /// + /// The following lease parameters are set to constant values: + /// - valid lifetime = 1200, + /// - T1 = 600, + /// - T2 = 900, + /// - DNS update forward flag = false, + /// - DNS update reverse flag = false, + /// + /// The lease address is set to address passed as function + /// argument. + /// + /// @param address Lease address. + /// + /// @return new lease with random content + Lease4Ptr initiateRandomLease4(const IOAddress& address) { + + // Randomize HW address. + vector mac(6); + fillRandom(mac.begin(), mac.end()); + HWAddrPtr hwaddr(new HWAddr(mac, HTYPE_ETHER)); + + // Let's generate clientid of random length + vector clientid(4 + rand()%20); + // And then fill it with random value. + fillRandom(clientid.begin(), clientid.end()); + + uint32_t valid_lft = 1200; + uint32_t t1 = 600; + uint32_t t2 = 900; + time_t timestamp = time(NULL) - 86400 + rand()%86400; + bool fqdn_fwd = false; + bool fqdn_rev = false; + uint32_t subnet_id = 1000 + rand()%16; + + string hostname; + hostname.resize(rand()%32); + for (int i = 0; i < hostname.size(); i++) { + // this should generate random garbage consisting of + // printable characters from between + // 33 (!, first printable character after space) to + // 126 (~, the last surely printable character) + hostname[i] = static_cast(33 + rand()%93); + } + + // Return created lease. + return (Lease4Ptr(new Lease4(address, hwaddr, &clientid[0], + clientid.size(), valid_lft, t1, t2, + timestamp, subnet_id, fqdn_fwd, + fqdn_rev, hostname))); + } + + /// @brief Generates a DHCPv6 lease with random content. + /// + /// The following lease parameters are randomly generated: + /// - DUID, + /// - IAID, + /// - hostname, + /// - subnet identifier, + /// - client last transmission time, + /// + /// The following lease parameters are set to constant values: + /// - lease type = IA_NA + /// - valid lifetime = 1200, + /// - preferred lifetime = 1000 + /// - T1 = 600, + /// - T2 = 900, + /// - DNS update forward flag = false, + /// - DNS update reverse flag = false, + /// + /// The lease address is set to address passed as function + /// argument. + /// + /// @param address Lease address. + /// + /// @return new lease with random content + Lease6Ptr initiateRandomLease6(const IOAddress& address) { + // Let's generate DUID of random length. + std::vector duid_vec(8 + rand()%20); + // And then fill it with random value. + fillRandom(duid_vec.begin(), duid_vec.end()); + DuidPtr duid(new DUID(duid_vec)); + + Lease::Type lease_type = Lease::TYPE_NA; + uint32_t iaid = 1 + rand()%100; + uint32_t valid_lft = 1200; + uint32_t preferred_lft = 1000; + uint32_t t1 = 600; + uint32_t t2 = 900; + time_t timestamp = time(NULL) - 86400 + rand()%86400; + bool fqdn_fwd = false; + bool fqdn_rev = false; + uint32_t subnet_id = 1000 + rand()%16; + + std::string hostname; + hostname.resize(rand()%32); + for (int i = 0; i < hostname.size(); i++) { + // this should generate random garbage consisting of + // printable characters from between + // 33 (!, first printable character after space) to + // 126 (~, the last surely printable character) + hostname[i] = static_cast(33 + rand()%93); + } - /// @brief Object providing access to v4 lease IO. + // Return created lease. + Lease6Ptr lease(new Lease6(lease_type, address, duid, iaid, + preferred_lft, valid_lft, t1, t2, + subnet_id, fqdn_fwd, fqdn_rev, hostname)); + lease->cltt_ = timestamp; + return (lease); + } + + /// @Brief Object providing access to v4 lease IO. LeaseFileIO io4_; /// @brief Object providing access to v6 lease IO. @@ -1513,4 +1632,271 @@ TEST_F(MemfileLeaseMgrTest, leaseUpgrade6) { EXPECT_EQ(result_file_contents, input_file.readFile()); } +// This test verifies that the indexes of the container holding +// DHCPv4 leases are updated correctly when a lease is updated. +TEST_F(MemfileLeaseMgrTest, lease4ContainerIndexUpdate) { + + const uint32_t seed = 12345678; // Used to initialize the random generator + const uint32_t leases_cnt = 100; // Number of leases generated per round. + const uint32_t updates_cnt = 5; // Number of times existing leases are updated + + const string leasefile(getLeaseFilePath("leasefile4_0.csv")); + + // Parameters for the lease file. Make sure the leases are persistent, so they + // are written to disk. + DatabaseConnection::ParameterMap pmap; + pmap["universe"] = "4"; + pmap["name"] = leasefile; + pmap["persist"] = "true"; + + srand(seed); + + IOAddress addr("10.0.0.1"); // Let's generate leases sequentially + + // Recreate Memfile_LeaseMgr. + LeaseMgrFactory::destroy(); + ASSERT_NO_THROW(lmptr_ = new Memfile_LeaseMgr(pmap)); + + // We will store addresses here, so it will be easier to randomly + // pick a lease. + std::vector lease_addresses; + + // Generarate random leases. We remember their addresses in + // lease_addresses. + for (uint32_t i = 0; i < leases_cnt; ++i) { + Lease4Ptr lease = initiateRandomLease4(addr); + lease_addresses.push_back(addr); + ASSERT_NO_THROW(lmptr_->addLease(lease)); + addr = IOAddress::increase(addr); + } + + // Check that we inserted correct number of leases. + ASSERT_EQ(leases_cnt, lease_addresses.size()); + + // Now, conduct updates. We call initiateRandomLease4(), so most + // of the fields are randomly changed. The only constant field + // is the address. + for (uint32_t i = 0; i < updates_cnt; i++) { + uint32_t offset = rand() % lease_addresses.size(); + Lease4Ptr existing(lmptr_->getLease4(lease_addresses[offset])); + Lease4Ptr updated(initiateRandomLease4(lease_addresses[offset])); + + // Update a lease with new data but preserve a lease address. + // This update should also cause lease container indexes to + // be updated. + ASSERT_NO_THROW(lmptr_->updateLease4(updated)) + << "Attempt " << i << " out of " << updates_cnt + << ":Failed to update lease for address " + << lease_addresses[offset]; + } + + // Re-create lease manager to cause it to reload leases + // from a lease file. We want to make sure that lease + // container is rebuilt correctly and the indexes are + // consistent with lease information held. + ASSERT_NO_THROW({ + LeaseMgrFactory::destroy(); + lmptr_ = new Memfile_LeaseMgr(pmap); + }); + + // Ok, let's check if the leases are really accessible. + // First, build an array of leases. Get them by address. + // This should work in general, as we haven't updated the addresses. + std::vector leases; + for (uint32_t i = 0; i < lease_addresses.size(); i++) { + Lease4Ptr from_mgr = lmptr_->getLease4(lease_addresses[i]); + ASSERT_TRUE(from_mgr) << "Lease for address " << lease_addresses[i].toText() + << " not found"; + leases.push_back(from_mgr); + } + + ASSERT_EQ(leases_cnt, leases.size()); + + // Now do the actual checks. + for (uint32_t i = 0; i < leases.size(); ++i) { + Lease4Ptr tested = leases[i]; + + // Get the lease by different access patterns. + // In properly working lease manager all queries should return + // exactly the same lease. + + std::string error_desc = " which indicates that the lease indexes were" + " not updated correctly when the lease was updated."; + + // Retrieve lease by address. + Lease4Ptr lease_by_address = lmptr_->getLease4(tested->addr_); + ASSERT_TRUE(lease_by_address) + << "Lease " << tested->addr_.toText() + << " not found by getLease4(addr)" + << error_desc; + detailCompareLease(tested, lease_by_address); + + // Retrieve lease by HW address and subnet id. + Lease4Ptr lease_by_hwaddr_subnet = lmptr_->getLease4(*tested->hwaddr_, + tested->subnet_id_); + ASSERT_TRUE(lease_by_hwaddr_subnet) + << "Lease " << tested->addr_.toText() + << " not found by getLease4(hwaddr, subnet_id)" + << error_desc; + detailCompareLease(tested, lease_by_hwaddr_subnet); + + // Retrieve lease by client identifier and subnet id. + Lease4Ptr lease_by_clientid_subnet = lmptr_->getLease4(*tested->client_id_, + tested->subnet_id_); + ASSERT_TRUE(lease_by_clientid_subnet) + << "Lease " << tested->addr_.toText() + << " not found by getLease4(clientid, subnet_id)" + << error_desc; + detailCompareLease(tested, lease_by_clientid_subnet); + + // Retrieve lease by client id, HW address and subnet. + Lease4Ptr lease_by_clientid_hwaddr_subnet = lmptr_->getLease4(*tested->client_id_, + *tested->hwaddr_, + tested->subnet_id_); + ASSERT_TRUE(lease_by_clientid_hwaddr_subnet) + << "Lease " << tested->addr_.toText() + << " not found by getLease4(clientid, hwaddr, subnet_id)" + << error_desc; + detailCompareLease(tested, lease_by_clientid_hwaddr_subnet); + + // Retrieve lease by HW address. + Lease4Collection leases_by_hwaddr = lmptr_->getLease4(*tested->hwaddr_); + ASSERT_EQ(1, leases_by_hwaddr.size()); + detailCompareLease(tested, leases_by_hwaddr[0]); + + // Retrieve lease by client identifier. + Lease4Collection leases_by_client_id = lmptr_->getLease4(*tested->client_id_); + ASSERT_EQ(1, leases_by_client_id.size()); + detailCompareLease(tested, leases_by_client_id[0]); + } +} + +// This test verifies that the indexes of the container holding +// DHCPv4 leases are updated correctly when a lease is updated. +TEST_F(MemfileLeaseMgrTest, lease6ContainerIndexUpdate) { + + const uint32_t seed = 12345678; // Used to initialize the random generator + const uint32_t leases_cnt = 100; // Number of leases generated per round. + const uint32_t updates_cnt = 5; // Number of times existing leases are updated + + const string leasefile(getLeaseFilePath("leasefile6_0.csv")); + + // Parameters for the lease file. Make sure the leases are persistent, so they + // are written to disk. + DatabaseConnection::ParameterMap pmap; + pmap["universe"] = "6"; + pmap["name"] = leasefile; + pmap["persist"] = "true"; + + srand(seed); + + IOAddress addr("2001:db8:1::1"); // Let's generate leases sequentially + + // Recreate Memfile_LeaseMgr. + LeaseMgrFactory::destroy(); + ASSERT_NO_THROW(lmptr_ = new Memfile_LeaseMgr(pmap)); + + // We will store addresses here, so it will be easier to randomly + // pick a lease. + std::vector lease_addresses; + + // Generarate random leases. We remember their addresses in + // lease_addresses. + for (uint32_t i = 0; i < leases_cnt; ++i) { + Lease6Ptr lease = initiateRandomLease6(addr); + lease_addresses.push_back(addr); + ASSERT_NO_THROW(lmptr_->addLease(lease)); + addr = IOAddress::increase(addr); + } + + // Check that we inserted correct number of leases. + ASSERT_EQ(leases_cnt, lease_addresses.size()); + + // Now, conduct updates. We call initiateRandomLease6(), so most + // of the fields are randomly changed. The only constant field + // is the address. + for (uint32_t i = 0; i < updates_cnt; i++) { + uint32_t offset = rand() % lease_addresses.size(); + Lease6Ptr existing(lmptr_->getLease6(Lease::TYPE_NA, + lease_addresses[offset])); + Lease6Ptr updated(initiateRandomLease6(lease_addresses[offset])); + + // Update a lease with new data but preserve a lease address. + // This update should also cause lease container indexes to + // be updated. + ASSERT_NO_THROW(lmptr_->updateLease6(updated)) + << "Attempt " << i << " out of " << updates_cnt + << ":Failed to update lease for address " + << lease_addresses[offset]; + } + + // Re-create lease manager to cause it to reload leases + // from a lease file. We want to make sure that lease + // container is rebuilt correctly and the indexes are + // consistent with lease information held. + ASSERT_NO_THROW({ + LeaseMgrFactory::destroy(); + lmptr_ = new Memfile_LeaseMgr(pmap); + }); + + // Ok, let's check if the leases are really accessible. + // First, build an array of leases. Get them by address. + // This should work in general, as we haven't updated the addresses. + std::vector leases; + for (uint32_t i = 0; i < lease_addresses.size(); i++) { + Lease6Ptr from_mgr = lmptr_->getLease6(Lease::TYPE_NA, + lease_addresses[i]); + ASSERT_TRUE(from_mgr) << "Lease for address " << lease_addresses[i].toText() + << " not found"; + leases.push_back(from_mgr); + } + + ASSERT_EQ(leases_cnt, leases.size()); + + // Now do the actual checks. + for (uint32_t i = 0; i < leases.size(); ++i) { + Lease6Ptr tested = leases[i]; + + // Get the lease by different access patterns. + // In properly working lease manager all queries should return + // exactly the same lease. + + std::string error_desc = " which indicates that the lease indexes were" + " not updated correctly when the lease was updated."; + + // Retrieve lease by address. + Lease6Ptr lease_by_address = lmptr_->getLease6(Lease::TYPE_NA, + tested->addr_); + ASSERT_TRUE(lease_by_address) + << "Lease " << tested->addr_.toText() + << " not found by getLease6(addr)" + << error_desc; + detailCompareLease(tested, lease_by_address); + + // Retrieve lease by type, DUID, IAID. + Lease6Collection leases_by_duid_iaid = lmptr_->getLeases6(tested->type_, + *tested->duid_, + tested->iaid_); + ASSERT_EQ(1, leases_by_duid_iaid.size()); + ASSERT_TRUE(leases_by_duid_iaid[0]) + << "Lease " << tested->addr_.toText() + << " not found by getLease6(type, duid, iaid)" + << error_desc; + detailCompareLease(tested, leases_by_duid_iaid[0]); + + // Retrieve lease by type, DUID, IAID, subnet identifier. + Lease6Collection leases_by_duid_iaid_subnet = + lmptr_->getLeases6(tested->type_, *tested->duid_, + tested->iaid_, tested->subnet_id_); + ASSERT_EQ(1, leases_by_duid_iaid_subnet.size()); + ASSERT_TRUE(leases_by_duid_iaid_subnet[0]) + << "Lease " << tested->addr_.toText() + << " not found by getLease6(type, duid, iaid, subnet_id)" + << error_desc; + detailCompareLease(tested, leases_by_duid_iaid_subnet[0]); + } +} + + + }; // end of anonymous namespace