Commit 6bb231d2 authored by Shawn Routhier's avatar Shawn Routhier

[trac3664] Code updates and add unittests for parsing

Add the structure for doing unittests and add some tests
to exercise parseArgs().

Rename the class to lfcController to be more in line with
the coding spec.
parent c9ce1955
#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
......
......@@ -17,7 +17,6 @@
#include <exceptions/exceptions.h>
#include <log/logger_support.h>
#include <log/logger_manager.h>
//#include <dhcpsrv/cfgmgr.h>
#include <iostream>
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;
}
}
void
lfc::pidCheck()
bool
lfcController::pidCheck(const std::string & pid_file)
{
return (false);
}
bool
lfcController::pidWrite(const std::string & pid_file)
{
return (true);
}
void
lfc::pidDelete()
lfcController::pidDelete(const std::string & pid_file)
{
}
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 <file>: previous lease file" << std::endl
<< " -i <file>: copy of lease file" << std::endl
<< " -o <file>: output lease file" << std::endl
<< " -f <file>: finish file" << std::endl
<< " -c <file>: 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());
//}
......@@ -32,7 +32,7 @@ public:
//class lfcBase;
//typedef boost::shared_ptr<lfcBase> 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
......
......@@ -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;
......
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
......
// 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 <log/logger_support.h>
#include <gtest/gtest.h>
#include <lfc/lfc.h>
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<char*>("progName"),
const_cast<char*>("-4"),
const_cast<char*>("-p"),
const_cast<char*>("previous"),
const_cast<char*>("-i"),
const_cast<char*>("copy"),
const_cast<char*>("-o"),
const_cast<char*>("output"),
const_cast<char*>("-c"),
const_cast<char*>("config"),
const_cast<char*>("-f"),
const_cast<char*>("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<char*>("progName"),
const_cast<char*>("-4"),
const_cast<char*>("-p"),
const_cast<char*>("previous"),
const_cast<char*>("-i"),
const_cast<char*>("copy"),
const_cast<char*>("-o"),
const_cast<char*>("output"),
const_cast<char*>("-c"),
const_cast<char*>("config"),
const_cast<char*>("-f"),
const_cast<char*>("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<char*>("progName"),
const_cast<char*>("-4"),
const_cast<char*>("-p"),
const_cast<char*>("previous"),
const_cast<char*>("-i"),
const_cast<char*>("copy"),
const_cast<char*>("-o"),
const_cast<char*>("output"),
const_cast<char*>("-c"),
const_cast<char*>("config"),
const_cast<char*>("-f"),
const_cast<char*>("finish"),
const_cast<char*>("some"),
const_cast<char*>("other"),
const_cast<char*>("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<char*>("progName"),
const_cast<char*>("some"),
const_cast<char*>("bad"),
const_cast<char*>("args"),
};
int argc = 4;
EXPECT_THROW(lfcController.parseArgs(argc, argv), InvalidUsage);
}
//-4 -p previous -i copy -o output -c config -f finish -d
// 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 <log/logger_support.h>
#include <gtest/gtest.h>
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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment