From 3e0491cba94634bb536569665d000bc44d14d16c Mon Sep 17 00:00:00 2001 From: Shawn Routhier Date: Mon, 2 Feb 2015 22:22:38 -0800 Subject: [PATCH] [trac3665] Dump leases from storage to file and use this in LFC Add the write method to lease_file_loader to dump the leaes files from a storage container into a file. Update the LFC code to use the lease_file_loader functions to load the leases from the appropriate files and then to write them to the output file and finally to move the file around. --- src/bin/lfc/lfc_controller.cc | 52 +++- src/bin/lfc/lfc_controller.h | 1 + src/bin/lfc/tests/lfc_controller_unittests.cc | 280 ++++++++++++++---- src/lib/dhcpsrv/lease_file_loader.h | 42 ++- .../tests/lease_file_loader_unittest.cc | 75 +++++ 5 files changed, 390 insertions(+), 60 deletions(-) diff --git a/src/bin/lfc/lfc_controller.cc b/src/bin/lfc/lfc_controller.cc index b3d7b61f6b..88b73f19fd 100644 --- a/src/bin/lfc/lfc_controller.cc +++ b/src/bin/lfc/lfc_controller.cc @@ -15,7 +15,15 @@ #include #include #include +#include +#include +#include +#include +#include #include + +#include + #include #include #include @@ -24,6 +32,7 @@ using namespace std; using namespace isc::util; +using namespace isc::dhcp; namespace isc { namespace lfc { @@ -35,6 +44,9 @@ const char* LFCController::lfc_app_name_ = "DhcpLFC"; /// @brief Defines the executable name. const char* LFCController::lfc_bin_name_ = "kea-lfc"; +/// @brief Maximum number of errors to read the leases from the lease file. +const uint32_t MAX_LEASE_ERRORS = 100; + LFCController::LFCController() : protocol_version_(0), verbose_(false), config_file_(""), previous_file_(""), copy_file_(""), output_file_(""), finish_file_(""), pid_file_("") { @@ -77,13 +89,22 @@ LFCController::launch(int argc, char* argv[]) { } // do other work (TBD) - std::cerr << "Add code to perform lease cleanup" << std::endl; // If we don't have a finish file do the processing + if (access(finish_file_.c_str(), F_OK) == -1) { + std::cerr << "LFC Processing files" << std::endl; + + if (protocol_version_ == 4) { + processLeases(); + } else { + processLeases(); + } + } // We either already had a finish file or just created one, do the // file cleanup, we don't want to return after the catch as we // still need to cleanup the pid file try { + std::cerr << "LFC cleaning files" << std::endl; fileCleanup(); } catch (const RunTimeFail& run_ex) { std::cerr << run_ex.what() << std::endl; @@ -239,7 +260,7 @@ LFCController::parseArgs(int argc, char* argv[]) { << "Previous or ex lease file: " << previous_file_ << std::endl << "Copy lease file: " << copy_file_ << std::endl << "Output lease file: " << output_file_ << std::endl - << "Finishn file: " << finish_file_ << std::endl + << "Finish file: " << finish_file_ << std::endl << "Config file: " << config_file_ << std::endl << "PID file: " << pid_file_ << std::endl; } @@ -279,8 +300,35 @@ LFCController::getVersion(const bool extended) const{ return (version_stream.str()); } +template void LFCController::processLeases() const { + LeaseFileType lfPrev(previous_file_.c_str()); + LeaseFileType lfCopy(copy_file_.c_str()); + LeaseFileType lfOutput(output_file_.c_str()); + StorageType storage; + storage.clear(); + + // If a previous file exists read the entries into storage + if (lfPrev.exists()) { + LeaseFileLoader::load(lfPrev, storage, + MAX_LEASE_ERRORS); + } + + // Follow that with the copy of the current lease file + if (lfCopy.exists()) { + LeaseFileLoader::load(lfCopy, storage, + MAX_LEASE_ERRORS); + } + + // Write the result out to the output file + LeaseFileLoader::write(lfOutput, storage); + + // Once we've finished the output file move it to the complete file + if (rename(output_file_.c_str(), finish_file_.c_str()) != 0) + isc_throw(RunTimeFail, "Unable to move output (" << output_file_ + << ") to complete (" << finish_file_ + << ") error: " << strerror(errno)); } void diff --git a/src/bin/lfc/lfc_controller.h b/src/bin/lfc/lfc_controller.h index c2553f63e0..24eb5e0da3 100644 --- a/src/bin/lfc/lfc_controller.h +++ b/src/bin/lfc/lfc_controller.h @@ -158,6 +158,7 @@ public: /// @brief Process files. Read in the leases from any previous & copy /// files we have and write the results out to the output file. Upon /// completion of the write move the file to the finish file. + template void processLeases() const; /// @brief Cleanup files. After we have a finish file, either from diff --git a/src/bin/lfc/tests/lfc_controller_unittests.cc b/src/bin/lfc/tests/lfc_controller_unittests.cc index 9637efb538..e5da609816 100644 --- a/src/bin/lfc/tests/lfc_controller_unittests.cc +++ b/src/bin/lfc/tests/lfc_controller_unittests.cc @@ -22,24 +22,25 @@ using namespace std; namespace { -// Filenames used for testing. -const char* PREVIOUS = "lease_file.2"; -const char* COPY = "lease_file.1"; -const char* FINISH = "lease_file.completed"; -const char* OUTPUT = "lease_file.output"; -const char* PID = "lease_file.pid"; - class LFCControllerTest : public ::testing::Test { public: - string pstr_; - string cstr_; - string fstr_; - string ostr_; - string istr_; + + string pstr_; ///< String for name for pid file + string xstr_; ///< String for name for previous file + string istr_; ///< String for name for copy file + string ostr_; ///< String for name for output file + string fstr_; ///< String for name for finish file + string cstr_; ///< String for name for config file /// @brief Create a file and write the filename into it. void touchFile(const std::string& filename, int); + /// @brief Create a file and write the given string into it. + void writeFile(const std::string& filename, const std::string& contents) const; + + /// @brief Read a string from a file + std::string readFile(const std::string& contents) const; + /// @brief check the file to see if i matches what was written to it. bool checkFile(const std::string& filename, int); @@ -48,26 +49,13 @@ protected: /// files before the test virtual void SetUp() { // set up the test files we need - std::ostringstream prev_str; - std::ostringstream copy_str; - std::ostringstream fin_str; - std::ostringstream out_str; - std::ostringstream pid_str; - - prev_str << TEST_DATA_BUILDDIR << "/" << PREVIOUS; - pstr_ = prev_str.str(); - - copy_str << TEST_DATA_BUILDDIR << "/" << COPY; - cstr_ = copy_str.str(); - - fin_str << TEST_DATA_BUILDDIR << "/" << FINISH; - fstr_ = fin_str.str(); - - out_str << TEST_DATA_BUILDDIR << "/" << OUTPUT; - ostr_ = out_str.str(); - - pid_str << TEST_DATA_BUILDDIR << "/" << PID; - istr_ = pid_str.str(); + string baseDir = TEST_DATA_BUILDDIR; + pstr_ = baseDir + "/" + "lease_file." + "pid"; // pid + xstr_ = baseDir + "/" + "lease_file." + "2"; // previous + istr_ = baseDir + "/" + "lease_file." + "1"; // copy + ostr_ = baseDir + "/" + "lease_file." + "output"; // output + fstr_ = baseDir + "/" + "lease_file." + "completed"; // finish + cstr_ = baseDir + "/" + "config_file"; // config // and remove any outstanding test files removeTestFile(); @@ -83,10 +71,10 @@ private: /// @brief Removes any remaining test files void removeTestFile() const { remove(pstr_.c_str()); - remove(cstr_.c_str()); - remove(fstr_.c_str()); - remove(ostr_.c_str()); + remove(xstr_.c_str()); remove(istr_.c_str()); + remove(ostr_.c_str()); + remove(fstr_.c_str()); } }; @@ -98,6 +86,29 @@ LFCControllerTest::touchFile(const std::string& filename, int i) { fs.open(filename, std::ofstream::out); fs << i << std::endl; fs.close(); + +} + +std::string +LFCControllerTest::readFile(const std::string& filename) const { + std::ifstream fs; + + fs.open(filename, std::ifstream::in); + std::string contents((std::istreambuf_iterator(fs)), + std::istreambuf_iterator()); + fs.close(); + return (contents); +} + +void +LFCControllerTest::writeFile(const std::string& filename, + const std::string& contents) const { + std::ofstream fs(filename, std::ofstream::out); + + if (fs.is_open()) { + fs << contents; + fs.close(); + } } bool @@ -261,24 +272,26 @@ TEST_F(LFCControllerTest, fileCleanup) { LFCController lfc_controller, lfc_controller_launch; // We can use the same arguments and controller for all of the tests - // as the files get redone for each subtest. + // as the files get redone for each subtest. We leave "-d" in the arg + // list but don't pass it as we use 14 as the argument count. This + // makes it easy to turn it on by simply increasing argc below to 15 char* argv[] = { const_cast("progName"), const_cast("-4"), const_cast("-x"), - const_cast(pstr_.c_str()), + const_cast(xstr_.c_str()), const_cast("-i"), - const_cast(cstr_.c_str()), + const_cast(istr_.c_str()), const_cast("-o"), const_cast(ostr_.c_str()), const_cast("-c"), - const_cast("config"), + const_cast(cstr_.c_str()), const_cast("-f"), const_cast(fstr_.c_str()), const_cast("-p"), - const_cast(istr_.c_str()), + const_cast(pstr_.c_str()), const_cast("-d") }; - int argc = 15; + int argc = 14; lfc_controller.parseArgs(argc, argv); // Test 1: Start with no files - we expect an execption as there @@ -288,41 +301,41 @@ TEST_F(LFCControllerTest, fileCleanup) { // Test 2: Create a file for each of previous, copy and finish. We should // delete the previous and copy files then move finish to previous. - touchFile(pstr_.c_str(), 1); - touchFile(cstr_.c_str(), 2); + touchFile(xstr_.c_str(), 1); + touchFile(istr_.c_str(), 2); touchFile(fstr_.c_str(), 3); lfc_controller.fileCleanup(); // verify finish is now previous and copy and finish are gone - EXPECT_TRUE(checkFile(pstr_.c_str(), 3)); - EXPECT_TRUE((remove(cstr_.c_str()) != 0) && (errno == ENOENT)); + EXPECT_TRUE(checkFile(xstr_.c_str(), 3)); + EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT)); EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT)); remove(pstr_.c_str()); // Test 3: Create a file for previous and finish but not copy. - touchFile(pstr_.c_str(), 4); + touchFile(xstr_.c_str(), 4); touchFile(fstr_.c_str(), 6); lfc_controller.fileCleanup(); // verify finish is now previous and copy and finish are gone - EXPECT_TRUE(checkFile(pstr_.c_str(), 6)); - EXPECT_TRUE((remove(cstr_.c_str()) != 0) && (errno == ENOENT)); + EXPECT_TRUE(checkFile(xstr_.c_str(), 6)); + EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT)); EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT)); remove(pstr_.c_str()); // Test 4: Create a file for copy and finish but not previous. - touchFile(cstr_.c_str(), 8); + touchFile(istr_.c_str(), 8); touchFile(fstr_.c_str(), 9); lfc_controller.fileCleanup(); // verify finish is now previous and copy and finish are gone - EXPECT_TRUE(checkFile(pstr_.c_str(), 9)); - EXPECT_TRUE((remove(cstr_.c_str()) != 0) && (errno == ENOENT)); + EXPECT_TRUE(checkFile(xstr_.c_str(), 9)); + EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT)); EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT)); remove(pstr_.c_str()); @@ -330,19 +343,174 @@ TEST_F(LFCControllerTest, fileCleanup) { // Test 5: rerun test 2 but using launch instead of cleanup // as we already have a finish file we shouldn't do any extra // processing - touchFile(pstr_.c_str(), 10); - touchFile(cstr_.c_str(), 11); + touchFile(xstr_.c_str(), 10); + touchFile(istr_.c_str(), 11); touchFile(fstr_.c_str(), 12); lfc_controller_launch.launch(argc, argv); // verify finish is now previous and copy and finish are gone // as we ran launch we also check to see if the pid is gone. - EXPECT_TRUE(checkFile(pstr_.c_str(), 12)); - EXPECT_TRUE((remove(cstr_.c_str()) != 0) && (errno == ENOENT)); - EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT)); + EXPECT_TRUE(checkFile(xstr_.c_str(), 12)); EXPECT_TRUE((remove(istr_.c_str()) != 0) && (errno == ENOENT)); + EXPECT_TRUE((remove(fstr_.c_str()) != 0) && (errno == ENOENT)); + EXPECT_TRUE((remove(pstr_.c_str()) != 0) && (errno == ENOENT)); remove(pstr_.c_str()); } +/// @brief Verify that we properly combine and clean up files +/// +/// This is mostly a retest as we already test that the loader and +/// writer functions work in their own tests but we combine it all +/// here. This is the v4 version + +TEST_F(LFCControllerTest, programLaunch4) { + LFCController lfc_controller; + + // We can use the same arguments and controller for all of the tests + // as the files get redone for each subtest. + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-x"), + const_cast(xstr_.c_str()), + const_cast("-i"), + const_cast(istr_.c_str()), + const_cast("-o"), + const_cast(ostr_.c_str()), + const_cast("-c"), + const_cast(cstr_.c_str()), + const_cast("-f"), + const_cast(fstr_.c_str()), + const_cast("-p"), + const_cast(pstr_.c_str()), + const_cast("-d") + }; + int argc = 14; + lfc_controller.parseArgs(argc, argv); + + // Create the test previous file + writeFile(xstr_.c_str(), + "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," + "fqdn_fwd,fqdn_rev,hostname\n" + "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1," + "host.example.com\n" + "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7," + "0,0,\n" + "192.0.2.3,,a:11:01:04,200,200,8,1,1,host.example.com\n" + "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7," + "0,0,\n" + "192.0.2.1,06:07:08:09:0a:bc,,200,500,8,1,1," + "host.example.com\n" + "192.0.2.5,06:07:08:09:0a:bc,,200,200,8,1,1," + "host.example.com\n"); + + + + // Create the test copy file + writeFile(istr_.c_str(), + "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," + "fqdn_fwd,fqdn_rev,hostname\n" + "192.0.2.1,06:07:08:09:0a:bc,,200,800,8,1,1," + "host.example.com\n" + "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,150,7," + "0,0,\n" + "192.0.2.5,06:07:08:09:0a:bc,,200,0,8,1,1," + "host.example.com\n"); + + // Run the cleanup + lfc_controller.launch(argc, argv); + + // Compare the results + EXPECT_EQ(readFile(xstr_.c_str()), + "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," + "fqdn_fwd,fqdn_rev,hostname\n" + "192.0.2.1,06:07:08:09:0a:bc,,200,800,8,1,1," + "host.example.com\n" + "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,150,7," + "0,0,\n"); + + + +} + +/// @brief Verify that we properly combine and clean up files +/// +/// This is mostly a retest as we already test that the loader and +/// writer functions work in their own tests but we combine it all +/// here. This is the v6 version + +TEST_F(LFCControllerTest, programLaunch6) { + LFCController lfc_controller; + + // We can use the same arguments and controller for all of the tests + // as the files get redone for each subtest. + char* argv[] = { const_cast("progName"), + const_cast("-6"), + const_cast("-x"), + const_cast(xstr_.c_str()), + const_cast("-i"), + const_cast(istr_.c_str()), + const_cast("-o"), + const_cast(ostr_.c_str()), + const_cast("-c"), + const_cast(cstr_.c_str()), + const_cast("-f"), + const_cast(fstr_.c_str()), + const_cast("-p"), + const_cast(pstr_.c_str()), + const_cast("-d") + }; + int argc = 14; + lfc_controller.parseArgs(argc, argv); + + // Create the test previous file + writeFile(xstr_.c_str(), + "address,duid,valid_lifetime,expire,subnet_id," + "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd," + "fqdn_rev,hostname,hwaddr\n" + "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," + "200,200,8,100,0,7,0,1,1,host.example.com,\n" + "2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,\n" + "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,300,6,150," + "0,8,0,0,0,,\n" + "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,200,8,0,2," + "16,64,0,0,,\n" + "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150," + "0,8,0,0,0,,\n" + "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," + "200,400,8,100,0,7,0,1,1,host.example.com,\n" + ); + + // Create the test copy file + writeFile(istr_.c_str(), + "address,duid,valid_lifetime,expire,subnet_id," + "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd," + "fqdn_rev,hostname,hwaddr\n" + "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,1000,6,150," + "0,8,0,0,0,,\n" + "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," + "0,200,8,100,0,7,0,1,1,host.example.com,\n" + "2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," + "200,600,8,100,0,7,0,1,1,host.example.com,\n" + "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,400,8,0,2," + "16,64,0,0,,\n" + ); + + // Run the cleanup + lfc_controller.launch(argc, argv); + + // Compare the results + EXPECT_EQ(readFile(xstr_.c_str()), + "address,duid,valid_lifetime,expire,subnet_id," + "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd," + "fqdn_rev,hostname,hwaddr\n" + "2001:db8:1::3,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," + "200,600,8,100,0,7,0,1,1,host.example.com,\n" + "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,1000,6,150," + "0,8,0,0,0,,\n" + "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,400,8,0,2," + "16,64,0,0,,\n" + ); +} + } // end of anonymous namespace diff --git a/src/lib/dhcpsrv/lease_file_loader.h b/src/lib/dhcpsrv/lease_file_loader.h index 7b9e7ee33a..fa47fe4b69 100644 --- a/src/lib/dhcpsrv/lease_file_loader.h +++ b/src/lib/dhcpsrv/lease_file_loader.h @@ -160,9 +160,47 @@ public: lease_file.close(); } } + + /// @brief Write leaes from the storage into a lease file + /// + /// This method iterates over the @c Lease4 or @c Lease6 object in the + /// storage specified in the arguments and writes them to the file + /// specified in the arguments. + /// + /// This method writes all entries in the storege to the file, it does + /// not perform any checks for expriation or duplication. + /// + /// @param lease_file A reference to the @c CSVLeaseFile4 or + /// @c CSVLeaseFile6 object representing the lease file. The file + /// doesn't need to be open because the method re-opens the file. + /// @param storage A reference to the container from which leases + /// should be written.. + /// @tparam LeasePtrType A @c Lease4 or @c Lease6. + /// @tparam LeaseFileType A @c CSVLeaseFile4 or @c CSVLeaseFile6. + /// @tparam StorageType A @c Lease4Storage or @c Lease6Storage. + /// + + template + static void write(LeaseFileType& lease_file, const StorageType& storage) { + // Reopen the file, as we don't know whether the file is open + // and we also don't know its current state. + lease_file.close(); + lease_file.open(); + + // Iterate over the storage area writing out the leases + for (typename StorageType::const_iterator lease = storage.begin(); + lease != storage.end(); + ++lease) { + lease_file.append(**lease); + } + + // Close the file + lease_file.close(); + } }; -} -} +} // namesapce dhcp +} // namespace isc #endif // LEASE_FILE_LOADER_H diff --git a/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc b/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc index 59e927403a..fae1946b77 100644 --- a/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc +++ b/src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc @@ -79,6 +79,37 @@ public: return (LeasePtrType()); } + /// @brief Tests the write function. + /// + /// This method writes the leases from the storage container to the lease file + /// then compares the output to the string provided in the aguments to verify + /// the write was correct. The order of the leases in the output will dpend + /// on the order in which the container provides the leases. + /// + /// @param storage A reference to the container to be written to the file + /// @param compStr The string to compare to what was read from the file + /// + /// @tparam LeaseStorage Type of the container: @c Lease4Container + /// @c Lease6Container. + /// + template + void writeLeases(LeaseFileType lease_file, + const StorageType& storage, + const std::string& compare) { + // Prepare for a new file, close and remove the old + lease_file.close(); + io_.removeFile(); + + // Write the current leases to the file + LeaseFileLoader::write + (lease_file, storage); + + // Compare to see if we got what we exepcted. + EXPECT_EQ(compare, io_.readFile()); + } + + /// @brief Name of the test lease file. std::string filename_; @@ -143,6 +174,15 @@ TEST_F(LeaseFileLoaderTest, load4) { lease = getLease("192.0.3.15", storage); ASSERT_TRUE(lease); EXPECT_EQ(35, lease->cltt_); + + writeLeases + (*lf, storage, + "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," + "fqdn_fwd,fqdn_rev,hostname\n" + "192.0.2.1,06:07:08:09:0a:bc,,200,500,8,1,1," + "host.example.com\n" + "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7," + "0,0,\n"); } // This test verifies that the lease with a valid lifetime of 0 @@ -176,6 +216,13 @@ TEST_F(LeaseFileLoaderTest, load4LeaseRemove) { Lease4Ptr lease = getLease("192.0.3.15", storage); ASSERT_TRUE(lease); EXPECT_EQ(35, lease->cltt_); + + writeLeases + (*lf, storage, + "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," + "fqdn_fwd,fqdn_rev,hostname\n" + "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,135,7," + "0,0,\n"); } // This test verifies that the DHCPv6 leases can be loaded from the lease @@ -226,6 +273,19 @@ TEST_F(LeaseFileLoaderTest, load6) { lease = getLease("2001:db8:2::10", storage); ASSERT_TRUE(lease); EXPECT_EQ(500, lease->cltt_); + + + writeLeases + (*lf, storage, + "address,duid,valid_lifetime,expire,subnet_id," + "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd," + "fqdn_rev,hostname,hwaddr\n" + "2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f," + "200,400,8,100,0,7,0,1,1,host.example.com,\n" + "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150," + "0,8,0,0,0,,\n" + "3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,100,200,8,0,2," + "16,64,0,0,,\n"); } // This test verifies that the lease with a valid lifetime of 0 @@ -261,6 +321,14 @@ TEST_F(LeaseFileLoaderTest, load6LeaseRemove) { Lease6Ptr lease = getLease("2001:db8:2::10", storage); ASSERT_TRUE(lease); EXPECT_EQ(500, lease->cltt_); + + writeLeases + (*lf, storage, + "address,duid,valid_lifetime,expire,subnet_id," + "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd," + "fqdn_rev,hostname,hwaddr\n" + "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,800,6,150," + "0,8,0,0,0,,\n"); } // This test verifies that the exception is thrown when the specific @@ -334,6 +402,13 @@ TEST_F(LeaseFileLoaderTest, loadLeaseWithZeroLifetime) { // The lease with a valid lifetime of 0 should not be loaded. EXPECT_FALSE(getLease("192.0.2.3", storage)); + + writeLeases + (*lf, storage, + "address,hwaddr,client_id,valid_lifetime,expire,subnet_id," + "fqdn_fwd,fqdn_rev,hostname\n" + "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,\n"); + } -- 2.47.3