Browse Source

[trac3665] More tests and cleanup

Add more tests to verity the cleanup of leases files

Cleanup the code for comments, typos, spaces and the like.
Shawn Routhier 10 years ago
parent
commit
ca432aa598

+ 51 - 39
src/bin/lfc/lfc_controller.cc

@@ -22,8 +22,6 @@
 #include <dhcpsrv/lease_file_loader.h>
 #include <config.h>
 
-#include <boost/shared_ptr.hpp>
-
 #include <iostream>
 #include <sstream>
 #include <unistd.h>
@@ -44,7 +42,7 @@ 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.
+/// @brief Maximum number of errors to allow when reading leases from the file.
 const uint32_t MAX_LEASE_ERRORS = 100;
 
 LFCController::LFCController()
@@ -57,6 +55,8 @@ LFCController::~LFCController() {
 
 void
 LFCController::launch(int argc, char* argv[]) {
+    bool do_clean = true;
+
     try {
         parseArgs(argc, argv);
     } catch (const InvalidUsage& ex) {
@@ -64,7 +64,8 @@ LFCController::launch(int argc, char* argv[]) {
         throw;  // rethrow it
     }
 
-    std::cerr << "Starting lease file cleanup" << std::endl;
+    if (verbose_ == true)
+        std::cerr << "Starting lease file cleanup" << std::endl;
 
     // verify we are the only instance
     PIDFile pid_file(pid_file_);
@@ -88,26 +89,36 @@ LFCController::launch(int argc, char* argv[]) {
         return;
     }
 
-    // do other work (TBD)
     // 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<Lease4, CSVLeaseFile4, Lease4Storage>();
-	} else {
-	    processLeases<Lease6, CSVLeaseFile6, Lease6Storage>();
-	}
+        if (verbose_ == true)
+            std::cerr << "LFC Processing files" << std::endl;
+
+        try {
+            if (protocol_version_ == 4) {
+                processLeases<Lease4, CSVLeaseFile4, Lease4Storage>();
+            } else {
+                processLeases<Lease6, CSVLeaseFile6, Lease6Storage>();
+            }
+        } catch (const isc::Exception& proc_ex) {
+            // We don't want to do the cleanup but do want to get rid of the pid
+            do_clean = false;
+            std::cerr << "Processing failed: " << proc_ex.what() << std::endl;
+        }
     }
 
-    // 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
+    // If do_clean is true We either already had a finish file or
+    // were able to create one.  We now want to 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;
+    if (do_clean == true) {
+        if (verbose_ == true)
+            std::cerr << "LFC cleaning files" << std::endl;
+        try {
+            fileCleanup();
+        } catch (const RunTimeFail& run_ex) {
+            std::cerr << run_ex.what() << std::endl;
+        }
     }
 
     // delete the pid file for this instance
@@ -115,10 +126,10 @@ LFCController::launch(int argc, char* argv[]) {
         pid_file.deleteFile();
     } catch (const PIDFileError& pid_ex) {
         std::cerr << pid_ex.what() << std::endl;
-        return;
     }
 
-    std::cerr << "LFC complete" << std::endl;
+    if (verbose_ == true)
+        std::cerr << "LFC complete" << std::endl;
 }
 
 void
@@ -256,13 +267,14 @@ LFCController::parseArgs(int argc, char* argv[]) {
 
     // If verbose is set echo the input information
     if (verbose_ == true) {
-      std::cerr << "Protocol version:    DHCPv" << protocol_version_ << std::endl
-                << "Previous or ex lease file: " << previous_file_ << std::endl
-                << "Copy lease file:           " << copy_file_ << std::endl
-                << "Output lease file:         " << output_file_ << std::endl
-                << "Finish file:               " << finish_file_ << std::endl
-                << "Config file:               " << config_file_ << std::endl
-                << "PID file:                  " << pid_file_ << std::endl;
+        std::cerr << "Protocol version:    DHCPv" << protocol_version_ << std::endl
+                  << "Previous or ex lease file: " << previous_file_ << std::endl
+                  << "Copy lease file:           " << copy_file_ << std::endl
+                  << "Output lease file:         " << output_file_ << std::endl
+                  << "Finish file:               " << finish_file_ << std::endl
+                  << "Config file:               " << config_file_ << std::endl
+                  << "PID file:                  " << pid_file_ << std::endl
+                  << std::endl;
     }
 }
 
@@ -303,26 +315,26 @@ LFCController::getVersion(const bool extended) const{
 template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
 void
 LFCController::processLeases() const {
-    LeaseFileType lfPrev(previous_file_.c_str());
-    LeaseFileType lfCopy(copy_file_.c_str());
-    LeaseFileType lfOutput(output_file_.c_str());
+    LeaseFileType lf_prev(previous_file_.c_str());
+    LeaseFileType lf_copy(copy_file_.c_str());
+    LeaseFileType lf_output(output_file_.c_str());
     StorageType storage;
     storage.clear();
 
     // If a previous file exists read the entries into storage
-    if (lfPrev.exists()) {
-        LeaseFileLoader::load<LeaseObjectType>(lfPrev, storage,
-					       MAX_LEASE_ERRORS);
+    if (lf_prev.exists()) {
+        LeaseFileLoader::load<LeaseObjectType>(lf_prev, storage,
+                                               MAX_LEASE_ERRORS);
     }
 
-    // Follow that with the copy of the current lease file 
-    if (lfCopy.exists()) {
-        LeaseFileLoader::load<LeaseObjectType>(lfCopy, storage,
-					       MAX_LEASE_ERRORS);
+    // Follow that with the copy of the current lease file
+    if (lf_copy.exists()) {
+        LeaseFileLoader::load<LeaseObjectType>(lf_copy, storage,
+                                               MAX_LEASE_ERRORS);
     }
 
     // Write the result out to the output file
-    LeaseFileLoader::write<LeaseObjectType>(lfOutput, storage);
+    LeaseFileLoader::write<LeaseObjectType>(lf_output, 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)

+ 7 - 9
src/bin/lfc/lfc_controller.h

@@ -41,10 +41,6 @@ public:
 /// manage the command line, check for already running instances,
 /// invoke the code to process the lease files and finally to rename
 /// the lease files as necessary.
-///
-/// @todo The current code simply processes the command line we still need to
-/// -# invoke the code to read, process and write the lease files
-/// -# rename and delete the shell files as required
 class LFCController {
 public:
     /// @brief Defines the application name, it may be used to locate
@@ -67,10 +63,10 @@ public:
     /// -# parse command line arguments
     /// -# verify that it is the only instance
     /// -# create pid file
-    /// -# read leases files TBD
-    /// -# write lease file TBD
-    /// -# move leases files TBD
-    /// -# cleanup artifacts TBD
+    /// -# read leases files
+    /// -# write lease file
+    /// -# move leases files
+    /// -# cleanup artifacts
     /// -# remove pid file
     /// -# exit to the caller
     ///
@@ -158,6 +154,8 @@ 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.
+    ///
+    /// @throw RunTimeFail if we can't move the file.
     template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
     void processLeases() const;
 
@@ -166,7 +164,7 @@ public:
     /// delete the work files (previous & copy) and move the finish file
     /// to be the new previous file.
     ///
-    /// @throw RunTimeFail if the command line parameters are invalid.
+    /// @throw RunTimeFail if we can't manipulate the files.
     void fileCleanup() const;
     //@}
 

+ 267 - 148
src/bin/lfc/tests/lfc_controller_unittests.cc

@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <lfc/lfc_controller.h>
+#include <util/csv_file.h>
 #include <gtest/gtest.h>
 #include <fstream>
 #include <cerrno>
@@ -24,7 +25,6 @@ namespace {
 
 class LFCControllerTest : public ::testing::Test {
 public:
-    
     string pstr_; ///< String for name for pid file
     string xstr_; ///< String for name for previous file
     string istr_; ///< String for name for copy file
@@ -32,30 +32,36 @@ public:
     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);
+    string v4_hdr_; ///< String for the header of the v4 csv test file
+    string v6_hdr_; ///< String for the header of the v6 csv test file
 
     /// @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 
+    /// @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);
-
 protected:
-    /// @brief Sets up the file names and Removes any old test
-    /// files before the test
+    /// @brief Sets up the file names and header string and removes 
+    /// any old test files before the test
     virtual void SetUp() {
         // set up the test files we need
-        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
+        string base_dir = TEST_DATA_BUILDDIR;
+        string lf = "lease_file.";
+
+        pstr_ = base_dir + "/" + lf + "pid";        // pid
+        xstr_ = base_dir + "/" + lf + "2";          // previous
+        istr_ = base_dir + "/" + lf + "1";          // copy
+        ostr_ = base_dir + "/" + lf + "output";     // output
+        fstr_ = base_dir + "/" + lf + "completed";  // finish
+        cstr_ = base_dir + "/" + "config_file";     // config
+
+        v4_hdr_ = "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
+                  "fqdn_fwd,fqdn_rev,hostname\n";
+
+        v6_hdr_ = "address,duid,valid_lifetime,expire,subnet_id,"
+                  "pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,"
+                  "fqdn_rev,hostname,hwaddr\n";
 
         // and remove any outstanding test files
         removeTestFile();
@@ -67,7 +73,6 @@ protected:
     }
 
 private:
-
     /// @brief Removes any remaining test files
     void removeTestFile() const {
         remove(pstr_.c_str());
@@ -79,53 +84,28 @@ private:
 
 };
 
-void
-LFCControllerTest::touchFile(const std::string& filename, int i) {
-    std::ofstream fs;
-
-    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<char>(fs)),
-			 std::istreambuf_iterator<char>());
+                         std::istreambuf_iterator<char>());
     fs.close();
     return (contents);
 }
 
 void
 LFCControllerTest::writeFile(const std::string& filename,
-			     const std::string& contents) const {
+                             const std::string& contents) const {
     std::ofstream fs(filename, std::ofstream::out);
 
     if (fs.is_open()) {
         fs << contents;
-	fs.close();
+        fs.close();
     }
 }
 
-bool
-LFCControllerTest::checkFile(const std::string& filename, int i) {
-    std::ifstream fs;
-    int j;
-
-    fs.open(filename, std::ifstream::in);
-    fs >> j;
-    fs.close();
-
-    if (i == j)
-        return (true);
-    return (false);
-}
-
-
 /// @brief Verify initial state of LFC controller.
 /// Create an instance of the controller and see that
 /// all of the initial values are empty as expected.
@@ -301,74 +281,79 @@ 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(xstr_.c_str(), 1);
-    touchFile(istr_.c_str(), 2);
-    touchFile(fstr_.c_str(), 3);
+    writeFile(xstr_.c_str(), "1");
+    writeFile(istr_.c_str(), "2");
+    writeFile(fstr_.c_str(), "3");
 
     lfc_controller.fileCleanup();
 
     // verify finish is now previous and copy and finish are gone
-    EXPECT_TRUE(checkFile(xstr_.c_str(), 3));
+    EXPECT_EQ(readFile(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());
+    remove(xstr_.c_str());
 
 
     // Test 3: Create a file for previous and finish but not copy.
-    touchFile(xstr_.c_str(), 4);
-    touchFile(fstr_.c_str(), 6);
+    writeFile(xstr_.c_str(), "4");
+    writeFile(fstr_.c_str(), "6");
 
     lfc_controller.fileCleanup();
 
     // verify finish is now previous and copy and finish are gone
-    EXPECT_TRUE(checkFile(xstr_.c_str(), 6));
+    EXPECT_EQ(readFile(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());
+    remove(xstr_.c_str());
 
 
     // Test 4: Create a file for copy and finish but not previous.
-    touchFile(istr_.c_str(), 8);
-    touchFile(fstr_.c_str(), 9);
+    writeFile(istr_.c_str(), "8");
+    writeFile(fstr_.c_str(), "9");
 
     lfc_controller.fileCleanup();
 
     // verify finish is now previous and copy and finish are gone
-    EXPECT_TRUE(checkFile(xstr_.c_str(), 9));
+    EXPECT_EQ(readFile(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());
+    remove(xstr_.c_str());
 
 
     // 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(xstr_.c_str(), 10);
-    touchFile(istr_.c_str(), 11);
-    touchFile(fstr_.c_str(), 12);
+    writeFile(xstr_.c_str(), "10");
+    writeFile(istr_.c_str(), "11");
+    writeFile(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(xstr_.c_str(), 12));
+    EXPECT_EQ(readFile(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());
+    remove(xstr_.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
+/// here.  We check: both files available, only previous, only copy
+/// neither and one of them having many lease errors.  This is the
+/// v4 version.
 
-TEST_F(LFCControllerTest, programLaunch4) {
+TEST_F(LFCControllerTest, launch4) {
     LFCController lfc_controller;
 
-    // We can use the same arguments and controller for all of the tests
-    // as the files get redone for each subtest.
+    // The arg list for our test.  We generally use the
+    // same file names to make it easy.  We include the -d
+    // in the argv list in case we want to enable verbose
+    // for debugging purposes.  To enable it change argc from
+    // 14 to 15
     char* argv[] = { const_cast<char*>("progName"),
                      const_cast<char*>("-4"),
                      const_cast<char*>("-x"),
@@ -386,64 +371,135 @@ TEST_F(LFCControllerTest, programLaunch4) {
                      const_cast<char*>("-d")
     };
     int argc = 14;
-    lfc_controller.parseArgs(argc, argv);
+    string test_str, astr;
+
+    // Create the various strings we want to use, the header is predefined.
+    // We have several entries for different leases, the naming is:
+    // <lease letter>_<version#>
+    string A_1 = "192.0.2.1,06:07:08:09:0a:bc,,"
+                 "200,200,8,1,1,host.example.com\n";
+    string A_2 = "192.0.2.1,06:07:08:09:0a:bc,,"
+                 "200,500,8,1,1,host.example.com\n";
+    string A_3 = "192.0.2.1,06:07:08:09:0a:bc,,"
+                 "200,800,8,1,1,host.example.com\n";
+
+    string B_1 = "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,"
+                 "100,100,7,0,0,\n";
+    string B_2 = "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,"
+                 "100,135,7,0,0,\n";
+    string B_3 = "192.0.3.15,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,"
+                 "100,150,7,0,0,\n";
+
+    string C_1 = "192.0.2.3,,a:11:01:04,"
+                 "200,200,8,1,1,host.example.com\n";
+
+    string D_1 = "192.0.2.5,16:17:18:19:1a:bc,,"
+                 "200,200,8,1,1,host.example.com\n";
+    string D_2 = "192.0.2.5,16:17:18:19:1a:bc,,"
+                 "0,200,8,1,1,host.example.com\n";
+
+    // Subtest 1: both previous and copy available.
+    // Create the test previous file
+    test_str = v4_hdr_ + A_1 + B_1 + C_1 + B_2 + A_2 + D_1;
+    writeFile(xstr_.c_str(), test_str);
+
+    // Create the test copy file
+    test_str = v4_hdr_ + A_3 + B_3 + D_2;
+    writeFile(istr_.c_str(), test_str);
+
+    // Run the cleanup
+    lfc_controller.launch(argc, argv);
+
+    // Compare the results, we expect the last lease for each ip
+    // except for C which was invalid and D which has expired
+    test_str = v4_hdr_ + A_3 + B_3;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
 
+    // Subtest 2: only previous available
     // 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");
+    test_str = v4_hdr_ + A_1 + B_1 + C_1 + B_2 + A_2 + D_1;
+    writeFile(xstr_.c_str(), test_str);
 
+    // No copy file
 
+    // Run the cleanup
+    lfc_controller.launch(argc, argv);
+
+    // Compare the results, we expect the last lease for each ip
+    // except for C which was invalid and D which has expired
+    test_str = v4_hdr_ + A_2 + D_1 + B_2;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
+
+    // Subtest 3: only copy available
+    // No previous file
 
     // 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");
+    test_str = v4_hdr_ + D_1 + A_1 + B_1 + B_3 + D_2 + A_3;
+    writeFile(istr_.c_str(), test_str);
 
     // 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");
+    // Compare the results, we expect the last lease for each ip
+    // except for C which was invalid and D which has expired
+    test_str = v4_hdr_ + A_3 + B_3;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
+
+    // Subtest 4: neither available
+    // No previous file
+
+    // No copy file
+
+    // Run the cleanup
+    lfc_controller.launch(argc, argv);
 
-	      
+    // Compare the results, we expect a header and no leaes
+    test_str = v4_hdr_;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
 
+
+    // Subtest 5: a file with a lot of errors
+    // A previous file with a lot of errors
+    astr = "1,\n2,\n3,\n4,\n5,\n6,\n7,\n7,\n8,\n9,\n10,\n";
+    test_str = v4_hdr_ + astr + astr + astr + astr + astr +
+               astr + astr + astr + astr + astr + astr;
+    writeFile(xstr_.c_str(), test_str);
+
+    // No copy file
+
+    // Run the cleanup, the file should fail but we should
+    // catch the error and properly cleanup.
+    lfc_controller.launch(argc, argv);
+
+    // And we shouldn't have deleted the previous file, but should
+    // have deleted the pid file
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    EXPECT_TRUE((remove(pstr_.c_str()) != 0) && (errno == ENOENT));
 }
 
 /// @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
+/// here.  We check: both files available, only previous, only copy
+/// neither and one of them having many lease errors.  This is the
+/// v6 version.
 
-TEST_F(LFCControllerTest, programLaunch6) {
+TEST_F(LFCControllerTest, launch6) {
     LFCController lfc_controller;
 
-    // We can use the same arguments and controller for all of the tests
-    // as the files get redone for each subtest.
+    // The arg list for our test.  We generally use the
+    // same file names to make it easy.  We include the -d
+    // in the argv list in case we want to enable verbose
+    // for debugging purposes.  To enable it change argc from
+    // 14 to 15
     char* argv[] = { const_cast<char*>("progName"),
                      const_cast<char*>("-6"),
                      const_cast<char*>("-x"),
@@ -461,56 +517,119 @@ TEST_F(LFCControllerTest, programLaunch6) {
                      const_cast<char*>("-d")
     };
     int argc = 14;
-    lfc_controller.parseArgs(argc, argv);
+    string test_str, astr;
+
+    // Create the various strings we want to use, the header is predefined.
+    // We have several entries for different leases, the naming is:
+    // <lease letter>_<version#>.
+    string A_1 = "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";
+    string A_2 = "2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,\n";
+    string A_3 = "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";
+    string A_4 = "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";
+
+    string B_1 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,"
+                 "300,300,6,150,0,8,0,0,0,,\n";
+    string B_2 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,"
+                 "300,800,6,150,0,8,0,0,0,,\n";
+    string B_3 = "2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,"
+                 "300,1000,6,150,0,8,0,0,0,,\n";
+
+    string C_1 = "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";
+    string C_2 = "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";
+
+    string D_1 = "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";
+
+    // Subtest 1: bot previous and copy available
+    // Create the test previous file
+    test_str = v6_hdr_ + A_1 + B_1 + A_2 + C_1 + A_3 + B_2;
+    writeFile(xstr_.c_str(), test_str);
 
+    // Create the test copy file
+    test_str = v6_hdr_ + B_3 + A_4 + D_1 + C_2;
+    writeFile(istr_.c_str(), test_str);
+
+    // Run the cleanup
+    lfc_controller.launch(argc, argv);
+
+    // Compare the results, we expect the last lease for each ip
+    // except for A which has expired
+    test_str = v6_hdr_ + D_1 + B_3 + C_2;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
+
+    // Subtest 2: only previous available
     // 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"
-	      );
+    test_str = v6_hdr_ + A_1 + B_1 + A_2 + C_1 + A_3 + B_2;
+    writeFile(xstr_.c_str(), test_str);
+
+    // No copy file
+
+    // Run the cleanup
+    lfc_controller.launch(argc, argv);
+
+    // Compare the results, we expect the last lease for each ip
+    // except for A which has expired
+    test_str = v6_hdr_ + A_3 + B_2 + C_1;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
+
+    // Subtest 3: only copy available
+    // No previous file
 
     // 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"
-	      );
+    test_str = v6_hdr_ + A_1 + B_2 + B_3 + A_4 + D_1 + C_2;
+    writeFile(istr_.c_str(), test_str);
 
     // 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"
-	      );
+    // Compare the results, we expect the last lease for each ip
+    // except for A which has expired
+    test_str = v6_hdr_ + D_1 + B_3 + C_2;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
+
+    // Subtest 4: neither available
+    // No previous file
+
+    // No copy file
+
+    // Run the cleanup
+    lfc_controller.launch(argc, argv);
+
+    // Compare the results, we expect a header and no leases
+    test_str = v6_hdr_;
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    remove(xstr_.c_str());
+
+
+    // Subtest 5: a file with a lot of errors
+    // A previous file with a lot of errors
+    astr = "1,\n2,\n3,\n4,\n5,\n6,\n7,\n7,\n8,\n9,\n10,\n";
+    test_str = v6_hdr_ + astr + astr + astr + astr + astr +
+               astr + astr + astr + astr + astr + astr;
+    writeFile(xstr_.c_str(), test_str);
+
+    // No copy file
+
+    // Run the cleanup, the file should fail but we should
+    // catch the error and properly cleanup.
+    lfc_controller.launch(argc, argv);
+
+    // And we shouldn't have deleted the previous file, but should
+    // have deleted the pid file
+    EXPECT_EQ(readFile(xstr_.c_str()), test_str);
+    EXPECT_TRUE((remove(pstr_.c_str()) != 0) && (errno == ENOENT));
+
 }
 
 } // end of anonymous namespace

+ 6 - 6
src/lib/dhcpsrv/lease_file_loader.h

@@ -161,20 +161,20 @@ public:
         }
     }
 
-    /// @brief Write leaes from the storage into a lease file
+    /// @brief Write leases 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.
+    /// This method writes all entries in the storage to the file, it does
+    /// not perform any checks for expiration 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..
+    /// 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.
@@ -188,14 +188,14 @@ public:
         lease_file.close();
         lease_file.open();
 
-	// Iterate over the storage area writing out the leases
+        // 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 
+        // Close the file
         lease_file.close();
     }
 };

+ 61 - 46
src/lib/dhcpsrv/tests/lease_file_loader_unittest.cc

@@ -82,31 +82,31 @@ public:
     /// @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
+    /// then compares the output to the string provided in the arguments to verify
+    /// the write was correct.  The order of the leases in the output will depend
     /// 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
-    /// 
+    /// @param compare The string to compare to what was read from the file
+    ///
     /// @tparam LeaseStorage Type of the container: @c Lease4Container
     /// @c Lease6Container.
     ///
     template<typename LeaseObjectType, typename LeaseFileType,
-	     typename StorageType>
+             typename StorageType>
     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<LeaseObjectType, LeaseFileType, StorageType>
-	(lease_file, storage);
-
-      // Compare to see if we got what we exepcted.
-      EXPECT_EQ(compare, io_.readFile());
+                     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<LeaseObjectType, LeaseFileType, StorageType>
+            (lease_file, storage);
+
+        // Compare to see if we got what we exepcted.
+        EXPECT_EQ(compare, io_.readFile());
     }
 
 
@@ -131,6 +131,9 @@ LeaseFileLoaderTest::absolutePath(const std::string& filename) {
 // This test verifies that the DHCPv4 leases can be loaded from the lease
 // file and that only the most recent entry for each lease is loaded and
 // the previous entries are discarded.
+//
+// It also tests the write function by writing the storage to a file
+// and comparing that with the expected value.
 TEST_F(LeaseFileLoaderTest, load4) {
     // Create lease file with leases for 192.0.2.1, 192.0.3.15. The lease
     // entry for the 192.0.2.3 is invalid (lacks HW address) and should
@@ -177,17 +180,20 @@ TEST_F(LeaseFileLoaderTest, load4) {
 
     writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>
         (*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");
+         "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
 // is removed from the storage. The valid lifetime of 0 is set
 // for the released leases.
+//
+// It also tests the write function by writing the storage to a file
+// and comparing that with the expected value.
 TEST_F(LeaseFileLoaderTest, load4LeaseRemove) {
     // Create lease file in which one of the entries for 192.0.2.1
     // has a valid_lifetime of 0 and results in the deletion of the
@@ -219,15 +225,18 @@ TEST_F(LeaseFileLoaderTest, load4LeaseRemove) {
 
     writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>
         (*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");
+         "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
 // file and that only the most recent entry for each lease is loaded and
 // the previous entries are discarded.
+//
+// It also tests the write function by writing the storage to a file
+// and comparing that with the expected value.
 TEST_F(LeaseFileLoaderTest, load6) {
     // Create a lease file with three valid leases: 2001:db8:1::1,
     // 3000:1:: and 2001:db8:2::10.
@@ -277,20 +286,23 @@ TEST_F(LeaseFileLoaderTest, load6) {
 
     writeLeases<Lease6, CSVLeaseFile6, Lease6Storage>
         (*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");
+         "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
 // is removed from the storage. The valid lifetime of 0 set set
 // for the released leases.
+//
+// It also tests the write function by writing the storage to a file
+// and comparing that with the expected value.
 TEST_F(LeaseFileLoaderTest, load6LeaseRemove) {
     // Create lease file in which one of the entries for the 2001:db8:1::1
     // has valid lifetime set to 0, in which case the lease should be
@@ -324,11 +336,11 @@ TEST_F(LeaseFileLoaderTest, load6LeaseRemove) {
 
     writeLeases<Lease6, CSVLeaseFile6, Lease6Storage>
         (*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");
+         "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
@@ -380,6 +392,9 @@ TEST_F(LeaseFileLoaderTest, loadMaxErrors) {
 // This test verifies that the lease with a valid lifetime set to 0 is
 // not loaded if there are no previous entries for this lease in the
 // lease file.
+//
+// It also tests the write function by writing the storage to a file
+// and comparing that with the expected value.
 TEST_F(LeaseFileLoaderTest, loadLeaseWithZeroLifetime) {
     // Create lease file. The second lease has a valid lifetime of 0.
     io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
@@ -388,7 +403,7 @@ TEST_F(LeaseFileLoaderTest, loadLeaseWithZeroLifetime) {
                   "192.0.2.3,06:07:08:09:0a:bd,,0,200,8,1,1,,\n");
 
     boost::scoped_ptr<CSVLeaseFile4> lf(new CSVLeaseFile4(filename_));
-    ASSERT_NO_THROW(lf->open()); 
+    ASSERT_NO_THROW(lf->open());
 
     // Set the error count to 0 to make sure that lease with a zero
     // lifetime doesn't cause an error.
@@ -405,11 +420,11 @@ TEST_F(LeaseFileLoaderTest, loadLeaseWithZeroLifetime) {
 
     writeLeases<Lease4, CSVLeaseFile4, Lease4Storage>
         (*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");
+         "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");
 
-}   
+}
 
 
 } // end of anonymous namespace

+ 0 - 1
src/lib/util/pid_file.cc

@@ -97,4 +97,3 @@ PIDFile::deleteFile() const {
 
 } // namespace isc::util
 } // namespace isc
-