diff --git a/src/bin/lfc/Makefile.am b/src/bin/lfc/Makefile.am index 7c058018eb..c2926f6f39 100644 --- a/src/bin/lfc/Makefile.am +++ b/src/bin/lfc/Makefile.am @@ -1,5 +1,4 @@ -#SUBDIRS = . tests -SUBDIRS = . +SUBDIRS = . tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin diff --git a/src/bin/lfc/lfc.cc b/src/bin/lfc/lfc.cc index 3d5512ff2d..cb031e2154 100644 --- a/src/bin/lfc/lfc.cc +++ b/src/bin/lfc/lfc.cc @@ -17,7 +17,6 @@ #include #include #include -//#include #include using namespace std; @@ -27,23 +26,23 @@ namespace lfc { /// @brief Defines the application name, it may be used to locate /// configuration data and appears in log statements. -const char* lfc::lfc_app_name_ = "DhcpLFC"; +const char* lfcController::lfc_app_name_ = "DhcpLFC"; /// @brief Defines the executable name. -const char*lfc::lfc_bin_name_ = "kea-lfc"; +const char* lfcController::lfc_bin_name_ = "kea-lfc"; -lfc::lfc() - : dhcp_version_(0), verbose_(false), config_file_(""), - previous_file_(""), copy_file_(""), output_file_("") { +lfcController::lfcController() + : protocol_version_(0), verbose_(false), config_file_(""), previous_file_(""), + copy_file_(""), output_file_(""), finish_file_(""), pid_file_("./test_pid") { std::cerr << "created lfc" << std::endl; } -lfc::~lfc() { +lfcController::~lfcController() { std::cerr << "destroyed lfc" << std::endl; } void -lfc::launch(int argc, char* argv[], const bool test_mode) { +lfcController::launch(int argc, char* argv[], const bool test_mode) { try { parseArgs(argc, argv); } catch (const InvalidUsage& ex) { @@ -55,30 +54,30 @@ lfc::launch(int argc, char* argv[], const bool test_mode) { } void -lfc::parseArgs(int argc, char* argv[]) +lfcController::parseArgs(int argc, char* argv[]) { int ch; - while ((ch = getopt(argc, argv, "46dvVp:i:o:c:")) != -1) { + while ((ch = getopt(argc, argv, "46dvVp:i:o:c:f:")) != -1) { switch (ch) { case '4': // Process DHCPv4 lease files. - dhcp_version_ = 4; + protocol_version_ = 4; break; case '6': // Process DHCPv6 lease files. - dhcp_version_ = 6; + protocol_version_ = 6; break; case 'v': // Print just Kea vesion and exit. - // std::cout << getVersion(false) << std::endl; + std::cout << getVersion(false) << std::endl; exit(EXIT_SUCCESS); case 'V': // Print extended Kea vesion and exit. - //std::cout << getVersion(true) << std::endl; + std::cout << getVersion(true) << std::endl; exit(EXIT_SUCCESS); case 'd': @@ -110,6 +109,14 @@ lfc::parseArgs(int argc, char* argv[]) output_file_ = optarg; break; + case 'f': + // Output file name. + if (optarg == NULL) { + isc_throw(InvalidUsage, "Finish file name missing"); + } + finish_file_ = optarg; + break; + case 'c': // Previous file name. if (optarg == NULL) { @@ -128,7 +135,7 @@ lfc::parseArgs(int argc, char* argv[]) isc_throw(InvalidUsage, "Extraneous parameters."); } - if (dhcp_version_ == 0) { + if (protocol_version_ == 0) { isc_throw(InvalidUsage, "DHCP version required"); } @@ -144,43 +151,57 @@ lfc::parseArgs(int argc, char* argv[]) isc_throw(InvalidUsage, "Output file not specified"); } + if (finish_file_.empty()) { + isc_throw(InvalidUsage, "Finish file not specified"); + } + if (config_file_.empty()) { isc_throw(InvalidUsage, "Config file not specified"); } // If verbose is set echo the input information if (verbose_ == true) { - std::cerr << "Protocol version: " << dhcp_version_ << std::endl + std::cerr << "Protocol version: " << protocol_version_ << std::endl << "Previous lease file: " << previous_file_ << std::endl << "Copy lease file: " << copy_file_ << std::endl << "Output lease file: " << output_file_ << std::endl - << "Config file: " << config_file_ << std::endl; + << "Finishn file: " << finish_file_ << std::endl + << "Config file: " << config_file_ << std::endl + << "PID file: " << pid_file_ << std::endl; } } +bool +lfcController::pidCheck(const std::string & pid_file) +{ + return (false); +} + +bool +lfcController::pidWrite(const std::string & pid_file) +{ + return (true); +} + void -lfc::pidCheck() +lfcController::pidDelete(const std::string & pid_file) { } void -lfc::pidDelete() -{ -} - -void -lfc::usage(const std::string & text) +lfcController::usage(const std::string & text) { if (text != "") { std::cerr << "Usage error: " << text << std::endl; } std::cerr << "Usage: " << lfc_bin_name_ << std::endl - << " [-4|-6] -p file -i file -o file -c file" << std::endl + << " [-4|-6] -p file -i file -o file -f file -c file" << std::endl << " -4 or -6 clean a set of v4 or v6 lease files" << std::endl << " -p : previous lease file" << std::endl << " -i : copy of lease file" << std::endl << " -o : output lease file" << std::endl + << " -f : finish file" << std::endl << " -c : configuration file" << std::endl << " -v: print version number and exit" << std::endl << " -V: print extended version inforamtion and exit" << std::endl @@ -188,21 +209,17 @@ lfc::usage(const std::string & text) << std::endl; } +std::string +lfcController::getVersion(bool extended) { + std::stringstream tmp; + + tmp << VERSION; + if (extended) { + tmp << std::endl << EXTENDED_VERSION; + } + + return (tmp.str()); +} + }; // namespace isc::lfc }; // namespace isc - -//std::string -//isc::dhcp::Daemon::getVersion(bool extended) { -// std::stringstream tmp; -// -// tmp << VERSION; -// if (extended) { -// tmp << std::endl << EXTENDED_VERSION; -// - // @todo print more details (is it Botan or OpenSSL build, - // with or without MySQL/Postgres? What compilation options were - // used? etc) -// } -// -// return (tmp.str()); -//} diff --git a/src/bin/lfc/lfc.h b/src/bin/lfc/lfc.h index 4f38e5468f..4c0deb4623 100644 --- a/src/bin/lfc/lfc.h +++ b/src/bin/lfc/lfc.h @@ -32,7 +32,7 @@ public: //class lfcBase; //typedef boost::shared_ptr lfcBasePtr; -class lfc { +class lfcController { public: /// @brief Defines the application name, it may be used to locate /// configuration data and appears in log statements. @@ -43,10 +43,10 @@ public: static const char* lfc_bin_name_; /// @brief Constructor - lfc(); + lfcController(); /// @brief Destructor - ~lfc(); + ~lfcController(); /// @brief Acts as the primary entry point to start execution /// of the process. Provides the control logic: @@ -63,26 +63,94 @@ public: /// step taken after the process has been launched. void parseArgs(int argc, char* argv[]); - /// @brief Use the pid to determine if there is another instance - /// and create a pid file if we are alone. - void pidCheck(); + /// @brief Use the pid file to determine if there is another instance + /// + /// @param pid_file is the name of the file which holds the pid to check + /// returns true if there is a process with that pid + bool pidCheck(const std::string & pid_file); + + /// @brief Extract the pid and Write it out to the pid file + /// + /// @param pid_file is the name of the file in which to write the pid + /// returns true if the write was successful + bool pidWrite(const std::string & pid_file); /// @brief Get rid of the pid file we created earlier - void pidDelete(); + void pidDelete(const std::string & pid_file); - /// #brief prints the program usage text to std error. + /// @brief Prints the program usage text to std error. /// /// @param text is a string message which will preceded the usage text. /// This is intended to be used for specific usage violation messages. void usage(const std::string& text); + /// @brief Gets the Kea version number for printing + /// + /// @param extended is a boolean indicating if the version string + /// should be short (false) or extended (true) + std::string getVersion(bool extended); + + // The following are primarly for the test code and not expected + // to be used in normal situations + + /// @brief Gets the protocol version of the leaes files + /// + /// @return Returns the value of the protocol version + int getProtocolVersion() { + return (protocol_version_); + } + + /// @brief Gets the config file name + /// + /// @return Returns the name of the config file + std::string getConfigFile() const { + return (config_file_); + } + + /// @brief Gets the prevous file name + /// + /// @return Returns the name of the previous file + std::string getPreviousFile() const { + return (previous_file_); + } + + /// @brief Gets the copy file name + /// + /// @return Returns the name of the copy file + std::string getCopyFile() const { + return (copy_file_); + } + + /// @brief Gets the output file name + /// + /// @return Returns the name of the output file + std::string getOutputFile() const { + return (output_file_); + } + + /// @brief Gets the finish file name + /// + /// @return Returns the name of the finish file + std::string getFinishFile() const { + return (finish_file_); + } + + /// @brief Gets the pid file name + /// + /// @return Returns the name of the pid file + std::string getPidFile() const { + return (pid_file_); + } + private: - int dhcp_version_; + int protocol_version_; bool verbose_; std::string config_file_; std::string previous_file_; std::string copy_file_; std::string output_file_; + std::string finish_file_; + std::string pid_file_; }; }; // namespace isc:lfc diff --git a/src/bin/lfc/main.cc b/src/bin/lfc/main.cc index 9f1b455285..7328f945e7 100644 --- a/src/bin/lfc/main.cc +++ b/src/bin/lfc/main.cc @@ -31,16 +31,13 @@ using namespace std; /// errors, EXIT_FAILURE otherwise. int main(int argc, char* argv[]) { int ret = EXIT_SUCCESS; - lfc lfc; - - // Instantiate/fetch the lfc application controller. - // lfc& lfc = lfc::lfc(); + lfcController lfcController; // Launch the controller passing in command line arguments. // Exit program with the controller's return code. try { // 'false' value disables test mode. - lfc.launch(argc, argv, false); + lfcController.launch(argc, argv, false); } catch (const isc::Exception& ex) { std::cerr << "Service failed:" << ex.what() << std::endl; ret = EXIT_FAILURE; diff --git a/src/bin/lfc/tests/Makefile.am b/src/bin/lfc/tests/Makefile.am index 42b0d5beff..23ea485887 100644 --- a/src/bin/lfc/tests/Makefile.am +++ b/src/bin/lfc/tests/Makefile.am @@ -1,8 +1,8 @@ SHTESTS = -noinst_SCRIPTS = lfc_tests.sh +noinst_SCRIPTS = -EXTRA_DIST = lfc_tests.sh.in +EXTRA_DIST = # test using command-line arguments, so use check-local target instead of TESTS check-local: @@ -24,7 +24,7 @@ AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\" CLEANFILES = $(builddir)/interfaces.txt $(builddir)/logger_lockfile -DISTCLEANFILES = lfc_process_tests.sh +DISTCLEANFILES = AM_CXXFLAGS = $(KEA_CXXFLAGS) if USE_CLANGPP @@ -44,12 +44,13 @@ if HAVE_GTEST TESTS += lfc_unittests -#lfc_unittests_SOURCES = d_test_stubs.cc d_test_stubs.h +lfc_unittests_SOURCES = lfc_unittests.cc +lfc_unittests_SOURCES += lfc_controller_unittests.cc lfc_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) lfc_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) lfc_unittests_LDADD = $(GTEST_LDADD) -lfc_unittests_LDADD += $(top_builddir)/src/bin/d2/libd2.la +lfc_unittests_LDADD += $(top_builddir)/src/bin/lfc/liblfc.la lfc_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libkea-exceptions.la lfc_unittests_LDADD += $(top_builddir)/src/lib/log/libkea-log.la lfc_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libkea-asiodns.la diff --git a/src/bin/lfc/tests/lfc_controller_unittests.cc b/src/bin/lfc/tests/lfc_controller_unittests.cc new file mode 100644 index 0000000000..3069a2ac52 --- /dev/null +++ b/src/bin/lfc/tests/lfc_controller_unittests.cc @@ -0,0 +1,158 @@ +// Copyright (C) 2015 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 +#include +#include + +using namespace isc::lfc; +using namespace std; + +TEST(lfcControllerTest, initialValues) { + lfcController lfcController; + + // Verify that we start with everything empty + EXPECT_TRUE(lfcController.getProtocolVersion() == 0); + EXPECT_TRUE(lfcController.getConfigFile() == ""); + EXPECT_TRUE(lfcController.getPreviousFile() == ""); + EXPECT_TRUE(lfcController.getCopyFile() == ""); + EXPECT_TRUE(lfcController.getOutputFile() == ""); + EXPECT_TRUE(lfcController.getFinishFile() == ""); + // Currently defaulting pid file for testing + // EXPECT_TRUE(lfcController.getPidFile() == ""); +} + +TEST(lfcControllerTest, fullCommandLine) { + lfcController lfcController; + + // Verify that standard options can be parsed without error + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-p"), + const_cast("previous"), + const_cast("-i"), + const_cast("copy"), + const_cast("-o"), + const_cast("output"), + const_cast("-c"), + const_cast("config"), + const_cast("-f"), + const_cast("finish") }; + int argc = 12; + + EXPECT_NO_THROW(lfcController.parseArgs(argc, argv)); + + // The parsed data + EXPECT_TRUE(lfcController.getProtocolVersion() == 4); + EXPECT_TRUE(lfcController.getConfigFile() == "config"); + EXPECT_TRUE(lfcController.getPreviousFile() == "previous"); + EXPECT_TRUE(lfcController.getCopyFile() == "copy"); + EXPECT_TRUE(lfcController.getOutputFile() == "output"); + EXPECT_TRUE(lfcController.getFinishFile() == "finish"); +} + +TEST(lfcControllerTest, notEnoughData) { + lfcController lfcController; + + // The standard options we shall test what happens + // if we don't include all of them + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-p"), + const_cast("previous"), + const_cast("-i"), + const_cast("copy"), + const_cast("-o"), + const_cast("output"), + const_cast("-c"), + const_cast("config"), + const_cast("-f"), + const_cast("finish") }; + int argc = 1; + + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 2; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 3; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 4; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 5; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 6; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 7; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 8; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 9; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 10; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + + argc = 11; + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); + +} + +TEST(lfcControllerTest, tooMuchData) { + lfcController lfcController; + + // The standard options plus some others + + char* argv[] = { const_cast("progName"), + const_cast("-4"), + const_cast("-p"), + const_cast("previous"), + const_cast("-i"), + const_cast("copy"), + const_cast("-o"), + const_cast("output"), + const_cast("-c"), + const_cast("config"), + const_cast("-f"), + const_cast("finish"), + const_cast("some"), + const_cast("other"), + const_cast("args"), + }; + int argc = 15; + + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); +} + +TEST(lfcControllerTest, someBadData) { + lfcController lfcController; + + // The standard options plus some others + + char* argv[] = { const_cast("progName"), + const_cast("some"), + const_cast("bad"), + const_cast("args"), + }; + int argc = 4; + + EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage); +} +//-4 -p previous -i copy -o output -c config -f finish -d diff --git a/src/bin/lfc/tests/lfc_unittests.cc b/src/bin/lfc/tests/lfc_unittests.cc new file mode 100644 index 0000000000..a2bb34bc26 --- /dev/null +++ b/src/bin/lfc/tests/lfc_unittests.cc @@ -0,0 +1,30 @@ +// Copyright (C) 2015 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 +#include + +int +main(int argc, char* argv[]) { + + ::testing::InitGoogleTest(&argc, argv); + + // See the documentation of the KEA_* environment variables in + // src/lib/log/README for info on how to tweak logging + isc::log::initLogger(); + + int result = RUN_ALL_TESTS(); + + return (result); +}