Commit d7fe7188 authored by Thomas Markwalder's avatar Thomas Markwalder
Browse files

[2955] Addressed review comments. Most notably, renamed DProcess

to DProcessBase.
parent b70a49c1
......@@ -48,7 +48,8 @@ pkglibexec_PROGRAMS = b10-d2
b10_d2_SOURCES = main.cc
b10_d2_SOURCES += d2_log.cc d2_log.h
b10_d2_SOURCES += d2_process.cc d2_process.h d_process.h
b10_d2_SOURCES += d2_process.h
b10_d2_SOURCES += d2_process.cc d2_process.h
nodist_b10_d2_SOURCES = d2_messages.h d2_messages.cc
EXTRA_DIST += d2_messages.mes
......
......@@ -14,39 +14,35 @@
$NAMESPACE isc::d2
% D2_STARTING : service starting
This is a debug message issued during a D2 service startup.
% D2CTL_STARTING DHCP-DDNS controller starting, pid: %1
This is an informational message issued when controller for DHCP-DDNS
service first starts.
% D2_START_INFO pid: %1, verbose: %2, standalone: %3
This is a debug message issued during the D2 service startup.
It lists some information about the parameters with which the
process is running.
% D2CTL_STOPPING DHCP-DDNS controller is exiting
This is an informational message issued when the controller is exiting
following a shut down (normal or otherwise) of the DDHCP-DDNS process.
% D2_SHUTDOWN : service is performing a normal shutting down
This is a debug message issued when the D2 service shuts down
normally in response to command to stop.
% D2PRC_SHUTDOWN DHCP-DDNS process is performing a normal shut down
This is a debug message issued when the service process has been instructed
to shut down by the controller.
% D2PRC_SHUTDOWN : process is performing a normal shutting down
This is a debug message issued when the D2 process shuts down
normally in response to service directive to stop.
% D2PRC_RUN_ENTER : process has entered the event loop.
% D2PRC_RUN_ENTER process has entered the event loop
This is a debug message issued when the D2 process enters it's
run method.
% D2PRC_RUN_EXIT : process is exiting the event loop.
% D2PRC_RUN_EXIT process is exiting the event loop
This is a debug message issued when the D2 process exits the
in event loop.
% D2PRC_FAILED : process experienced a fatal error.
% D2PRC_FAILED process experienced a fatal error: %1
This is a debug message issued when the D2 process encounters an
unrecoverable error from within the event loop.
% D2PRC_CONFIGURE : new configuration received: %1
% D2PRC_CONFIGURE new configuration received: %1
This is a debug message issued when the D2 process configure method
has been invoked.
% D2PRC_COMMAND : command directive received, command: %1 - args: %2
% D2PRC_COMMAND command directive received, command: %1 - args: %2
This is a debug message issued when the D2 process command method
has been invoked.
......@@ -22,7 +22,7 @@ namespace isc {
namespace d2 {
D2Process::D2Process(const char* name, IOServicePtr io_service)
: DProcess(name, io_service) {
: DProcessBase(name, io_service) {
};
void
......@@ -38,9 +38,10 @@ D2Process::run() {
// or the call to run will continue to block, and shutdown will not
// occur.
LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2PRC_RUN_ENTER);
while (!shut_down_) {
IOServicePtr& io_service = getIoService();
while (!shouldShutDown()) {
try {
io_service_->run_one();
io_service->run_one();
} catch (const std::exception& ex) {
LOG_FATAL(d2_logger, D2PRC_FAILED).arg(ex.what());
return (EXIT_FAILURE);
......@@ -54,7 +55,7 @@ D2Process::run() {
int
D2Process::shutdown() {
LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2PRC_SHUTDOWN);
shut_down_ = true;
setShutdownFlag(true);
return (0);
}
......
......@@ -25,10 +25,10 @@ namespace d2 {
/// D2Process provides the top level application logic for DHCP-driven DDNS
/// update processing. It provides the asynchronous event processing required
/// to receive DNS mapping change requests and carry them out.
/// It implements the DProcess interface, which structures it such that it
/// It implements the DProcessBase interface, which structures it such that it
/// is a managed "application", controlled by a management layer.
class D2Process : public DProcess {
class D2Process : public DProcessBase {
public:
/// @brief Constructor
///
......@@ -37,7 +37,7 @@ public:
/// @param io_service is the io_service used by the caller for
/// asynchronous event handling.
///
/// @throw DProcessError is io_service is NULL.
/// @throw DProcessBaseError is io_service is NULL.
D2Process(const char* name, IOServicePtr io_service);
/// @brief Will be used after instantiation to perform initialization
......
......@@ -27,25 +27,25 @@ namespace isc {
namespace d2 {
/// @brief Exception thrown if the process encountered an operational error.
class DProcessError : public isc::Exception {
class DProcessBaseError : public isc::Exception {
public:
DProcessError(const char* file, size_t line, const char* what) :
DProcessBaseError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @brief Application Process Interface
///
/// DProcess is an abstract class represents the primary "application" level
/// object in a "managed" asyncrhonous application. It provides a uniform
/// DProcessBase is an abstract class represents the primary "application"
/// level object in a "managed" asynchronous application. It provides a uniform
/// interface such that a managing layer can construct, intialize, and start
/// the application's event loop. The event processing is centered around the
/// use of isc::asiolink::io_service. The io_service is shared between the
/// the managing layer and the DProcess. This allows management layer IO
/// the managing layer and the DProcessBase. This allows management layer IO
/// such as directives to be sensed and handled, as well as processing IO
/// activity specific to the application. In terms fo management layer IO,
/// activity specific to the application. In terms of management layer IO,
/// there are methods shutdown, configuration updates, and commands unique
/// to the application.
class DProcess {
class DProcessBase {
public:
/// @brief Constructor
///
......@@ -54,12 +54,12 @@ public:
/// @param io_service is the io_service used by the caller for
/// asynchronous event handling.
///
/// @throw DProcessError is io_service is NULL.
DProcess(const char* name, IOServicePtr io_service) : name_(name),
io_service_(io_service), shut_down_(false) {
/// @throw DProcessBaseError is io_service is NULL.
DProcessBase(const char* name, IOServicePtr io_service) : name_(name),
io_service_(io_service), shut_down_flag(false) {
if (!io_service_) {
isc_throw (DProcessError, "IO Service cannot be null");
isc_throw (DProcessBaseError, "IO Service cannot be null");
}
};
......@@ -112,9 +112,25 @@ public:
const std::string& command, isc::data::ConstElementPtr args) = 0;
/// @brief Destructor
virtual ~DProcess(){};
virtual ~DProcessBase(){};
protected:
bool shouldShutDown() {
return shut_down_flag;
}
void setShutdownFlag(bool value) {
shut_down_flag = value;
}
const std::string& getName() {
return (name_);
}
IOServicePtr& getIoService() {
return (io_service_);
}
private:
/// @brief Text label for the process. Generally used in log statements,
/// but otherwise can be arbitrary.
std::string name_;
......@@ -123,11 +139,11 @@ protected:
IOServicePtr io_service_;
/// @brief Boolean flag set when shutdown has been requested.
bool shut_down_;
bool shut_down_flag;
};
/// @brief Defines a shared pointer to DProcess.
typedef boost::shared_ptr<DProcess> DProcessPtr;
/// @brief Defines a shared pointer to DProcessBase.
typedef boost::shared_ptr<DProcessBase> DProcessBasePtr;
}; // namespace isc::d2
}; // namespace isc
......
......@@ -82,16 +82,14 @@ main(int argc, char* argv[]) {
((verbose_mode && stand_alone)
? isc::log::DEBUG : isc::log::INFO),
isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone);
LOG_INFO(d2_logger, D2_STARTING);
LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2_START_INFO)
.arg(getpid()).arg(verbose_mode ? "yes" : "no")
.arg(stand_alone ? "yes" : "no" );
LOG_INFO(d2_logger, D2CTL_STARTING);
// For now we will sleep awhile to simulate doing something.
// Without at least a sleep, the process will start, exit and be
// restarted by Bind10/Init endlessley in a rapid succession.
sleep(1000);
LOG_INFO(d2_logger, D2_SHUTDOWN);
LOG_INFO(d2_logger, D2CTL_STOPPING);
return (EXIT_SUCCESS);
}
......@@ -52,6 +52,7 @@ if HAVE_GTEST
TESTS += d2_unittests
d2_unittests_SOURCES = ../d2_log.h ../d2_log.cc
d2_unittests_SOURCES += ../d2_process.h
d2_unittests_SOURCES += ../d2_process.cc ../d2_process.h ../d_process.h
d2_unittests_SOURCES += d2_unittests.cc
d2_unittests_SOURCES += d2_process_unittests.cc
......
......@@ -35,7 +35,7 @@ class D2ProcessTest : public ::testing::Test {
public:
/// @brief Static instance accessible via test callbacks.
static DProcessPtr process_;
static DProcessBasePtr process_;
/// @brief Constructor
D2ProcessTest() {
......@@ -56,7 +56,7 @@ public:
/// @brief Callback that throws an exception.
static void genFatalErrorCallback() {
isc_throw (DProcessError, "simulated fatal error");
isc_throw (DProcessBaseError, "simulated fatal error");
}
/// @brief IOService for event processing. Fills in for IOservice
......@@ -65,7 +65,7 @@ public:
};
// Define the static process instance
DProcessPtr D2ProcessTest::process_;
DProcessBasePtr D2ProcessTest::process_;
/// @brief Verifies D2Process constructor behavior.
......@@ -75,7 +75,7 @@ TEST(D2Process, construction) {
// Verify that the constructor will fail if given an empty
// io service.
IOServicePtr lcl_io_service;
EXPECT_THROW (D2Process("TestProcess", lcl_io_service), DProcessError);
EXPECT_THROW (D2Process("TestProcess", lcl_io_service), DProcessBaseError);
// Verify that the constructor succeeds with a valid io_service
lcl_io_service.reset(new isc::asiolink::IOService());
......@@ -115,16 +115,16 @@ TEST_F(D2ProcessTest, command) {
/// the run method to exit gracefully with a return value of EXIT_SUCCESS.
TEST_F(D2ProcessTest, normalShutdown) {
// Use an asiolink IntervalTimer and callback to generate the
// shutdown invocation.
// shutdown invocation. (Note IntervalTimer setup is in milliseconds).
isc::asiolink::IntervalTimer timer(*io_service_);
timer.setup(genShutdownCallback, 2*1000);
timer.setup(genShutdownCallback, 2 * 1000);
// Record start time, and invoke run().
ptime start = second_clock::universal_time();
ptime start = microsec_clock::universal_time();
int rcode = process_->run();
// Record stop time.
ptime stop = second_clock::universal_time();
ptime stop = microsec_clock::universal_time();
// Verify normal shutdown status.
EXPECT_EQ(EXIT_SUCCESS, rcode);
......@@ -133,23 +133,24 @@ TEST_F(D2ProcessTest, normalShutdown) {
// timer duration. This demonstrates that the shutdown was driven
// by an io_service event and callback.
time_duration elapsed = stop - start;
EXPECT_EQ(2L, elapsed.seconds());
EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
elapsed.total_milliseconds() <= 2100);
}
/// @brief Verifies that an "uncaught" exception thrown during event loop
/// processing is treated as a fatal error.
TEST_F(D2ProcessTest, fatalErrorShutdown) {
// Use an asiolink IntervalTimer and callback to generate the
// the exception.
// the exception. (Note IntervalTimer setup is in milliseconds).
isc::asiolink::IntervalTimer timer(*io_service_);
timer.setup(genFatalErrorCallback, 2*1000);
timer.setup(genFatalErrorCallback, 2 * 1000);
// Record start time, and invoke run().
ptime start = second_clock::universal_time();
ptime start = microsec_clock::universal_time();
int rcode = process_->run();
// Record stop time.
ptime stop = second_clock::universal_time();
ptime stop = microsec_clock::universal_time();
// Verify failure status.
EXPECT_EQ(EXIT_FAILURE, rcode);
......@@ -158,7 +159,8 @@ TEST_F(D2ProcessTest, fatalErrorShutdown) {
// timer duration. This demonstrates that the anomaly occurred
// during io callback processing.
time_duration elapsed = stop - start;
EXPECT_EQ(2L, elapsed.seconds());
EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
elapsed.total_milliseconds() <= 2100);
}
} // end of anonymous namespace
......@@ -161,7 +161,7 @@ class TestD2Daemon(unittest.TestCase):
# soon enough to catch it.
(returncode, output, error) = self.runCommand(["../b10-d2", "-s"])
output_text = str(output) + str(error)
self.assertEqual(output_text.count("D2_STARTING"), 1)
self.assertEqual(output_text.count("D2CTL_STARTING"), 1)
if __name__ == '__main__':
unittest.main()
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