Commit 3827222d authored by Steven Murray's avatar Steven Murray
Browse files

The constructors of the C++ daemons now take as paramaters output stream

objects representing standard in and standard error.

By being able to provide dummy output stream objects, this modification allows
C++ daemon objects to be instantiated in unit tests without the worry of them
writing to the real standard in and standard error streams.
parent 07e8277f
......@@ -33,12 +33,13 @@
#include "castor/log/LoggerImplementation.hpp"
#include "castor/server/SignalThreadPool.hpp"
#include "castor/server/BaseThreadPool.hpp"
#include "Cgetopt.h"
#include "getconfent.h"
#include "h/Cgetopt.h"
#include "h/getconfent.h"
#include <iostream>
#include <sys/time.h>
#include <string.h>
//-----------------------------------------------------------------------------
// main
//-----------------------------------------------------------------------------
......@@ -46,7 +47,7 @@ int main(int argc, char *argv[]) {
try {
castor::log::LoggerImplementation logger("gcd");
castor::gc::GcDaemon daemon(logger);
castor::gc::GcDaemon daemon(std::cout, std::cerr, logger);
// Randomize the start-up of the daemon between 1 and 15 minutes.
char *value;
......@@ -110,8 +111,9 @@ int main(int argc, char *argv[]) {
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
castor::gc::GcDaemon::GcDaemon(log::Logger &logger):
castor::server::MultiThreadedDaemon(logger) {
castor::gc::GcDaemon::GcDaemon(std::ostream &stdOut, std::ostream &stdErr,
log::Logger &logger):
castor::server::MultiThreadedDaemon(stdOut, stdErr, logger) {
// Now with predefined messages
castor::dlf::Message messages[] = {
......
......@@ -47,9 +47,11 @@ namespace castor {
/**
* Constructor
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
*/
GcDaemon(log::Logger &logger);
GcDaemon(std::ostream &stdOut, std::ostream &stdErr, log::Logger &logger);
/**
* Default destructor
......
......@@ -63,7 +63,7 @@ const char *castor::rh::PORT_SEC_CONF = "SEC_PORT";
int main(int argc, char *argv[]) {
try {
castor::log::LoggerImplementation logger("rhd");
castor::rh::Server server(logger);
castor::rh::Server server(std::cout, std::cerr, logger);
// parse the command line
server.parseCommandLine(argc, argv);
......@@ -93,8 +93,9 @@ int main(int argc, char *argv[]) {
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
castor::rh::Server::Server(castor::log::Logger &logger) :
castor::server::MultiThreadedDaemon(logger),
castor::rh::Server::Server(std::ostream &stdOut, std::ostream &stdErr,
castor::log::Logger &logger) :
castor::server::MultiThreadedDaemon(stdOut, stdErr, logger),
m_port(-1),
m_secure(false),
m_waitIfBusy(true),
......
......@@ -59,9 +59,12 @@ namespace castor {
/**
* Constructor
*
* @param logger Object representing the API of the CASTOR logging system.
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging
* system.
*/
Server(log::Logger &logger);
Server(std::ostream &stdOut, std::ostream &stdErr, log::Logger &logger);
/**
* Destructor
......
......@@ -33,9 +33,12 @@
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::server::Daemon::Daemon(log::Logger &logger) throw():
castor::server::Daemon::Daemon(std::ostream &stdOut, std::ostream &stdErr,
log::Logger &logger) throw():
m_foreground(false),
m_commandLineHasBeenParsed(false),
m_stdOut(stdOut),
m_stdErr(stdErr),
m_runAsStagerSuperuser(false),
m_logger(logger) {
}
......@@ -82,7 +85,7 @@ void castor::server::Daemon::parseCommandLine(int argc,
break;
case 'c':
setenv("PATH_CONFIG", Coptarg, 1);
std::cout << "Using configuration file " << Coptarg << std::endl;
m_stdOut << "Using configuration file " << Coptarg << std::endl;
break;
case 'h':
help(argv[0]);
......@@ -101,7 +104,7 @@ void castor::server::Daemon::parseCommandLine(int argc,
//------------------------------------------------------------------------------
void castor::server::Daemon::help(const std::string &programName)
throw() {
std::cout << "Usage: " << programName << " [options]\n"
m_stdOut << "Usage: " << programName << " [options]\n"
"\n"
"where options can be:\n"
"\n"
......
......@@ -28,6 +28,8 @@
#include "castor/exception/Exception.hpp"
#include "castor/log/Logger.hpp"
#include <ostream>
namespace castor {
namespace server {
......@@ -43,9 +45,12 @@ public:
/**
* Constructor
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
*/
Daemon(log::Logger &logger) throw();
Daemon(std::ostream &stdOut, std::ostream &stdErr, log::Logger &logger)
throw();
/**
* Destructor.
......@@ -226,6 +231,16 @@ protected:
*/
bool m_commandLineHasBeenParsed;
/**
* Stream representing standard out.
*/
std::ostream &m_stdOut;
/**
* Stream reprsenting standard in.
*/
std::ostream &m_stdErr;
private:
/**
......
......@@ -26,6 +26,7 @@
#include "castor/server/Daemon.hpp"
#include <gtest/gtest.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
......@@ -59,8 +60,10 @@ protected:
};
TEST_F(castor_server_DaemonTest, getForegroundBeforeParseCommandLine) {
std::ostringstream dummyStdOut;
std::ostringstream dummyStdErr;
castor::log::DummyLogger log(m_programName);
castor::server::Daemon daemon(log);
castor::server::Daemon daemon(dummyStdOut, dummyStdErr, log);
ASSERT_THROW(daemon.getForeground(), castor::exception::CommandLineNotParsed);
}
......@@ -71,8 +74,10 @@ TEST_F(castor_server_DaemonTest, parseEmptyCmdLine) {
m_argv[1] = NULL;
m_argc = 1;
std::ostringstream dummyStdOut;
std::ostringstream dummyStdErr;
castor::log::DummyLogger log(m_programName);
castor::server::Daemon daemon(log);
castor::server::Daemon daemon(dummyStdOut, dummyStdErr, log);
ASSERT_NO_THROW(daemon.parseCommandLine(m_argc, m_argv));
ASSERT_EQ(false, daemon.getForeground());
......@@ -85,8 +90,10 @@ TEST_F(castor_server_DaemonTest, parseFOnCmdLine) {
m_argv[2] = NULL;
m_argc = 2;
std::ostringstream dummyStdOut;
std::ostringstream dummyStdErr;
castor::log::DummyLogger log(m_programName);
castor::server::Daemon daemon(log);
castor::server::Daemon daemon(dummyStdOut, dummyStdErr, log);
ASSERT_NO_THROW(daemon.parseCommandLine(m_argc, m_argv));
ASSERT_EQ(true, daemon.getForeground());
......
......@@ -32,8 +32,9 @@
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::server::MultiThreadedDaemon::MultiThreadedDaemon(log::Logger &logger):
Daemon(logger), m_signalMutex(NULL) {
castor::server::MultiThreadedDaemon::MultiThreadedDaemon(std::ostream &stdOut,
std::ostream &stdErr, log::Logger &logger) throw():
Daemon(stdOut, stdErr, logger), m_signalMutex(NULL) {
}
//------------------------------------------------------------------------------
......@@ -91,7 +92,7 @@ void castor::server::MultiThreadedDaemon::parseCommandLine(int argc,
break;
case 'c':
setenv("PATH_CONFIG", Coptarg, 1);
std::cout << "Using configuration file " << Coptarg << std::endl;
m_stdOut << "Using configuration file " << Coptarg << std::endl;
break;
case 'h':
help(argv[0]);
......@@ -124,7 +125,7 @@ void castor::server::MultiThreadedDaemon::parseCommandLine(int argc,
//------------------------------------------------------------------------------
void castor::server::MultiThreadedDaemon::help(const std::string &programName)
throw() {
std::cout << "Usage: " << programName << " [options]\n"
m_stdOut << "Usage: " << programName << " [options]\n"
"\n"
"where options can be:\n"
"\n"
......@@ -156,7 +157,7 @@ void castor::server::MultiThreadedDaemon::addThreadPool(
void castor::server::MultiThreadedDaemon::start()
throw(castor::exception::Exception) {
if (m_foreground) {
std::cout << "Starting " << getServerName() << std::endl;
m_stdOut << "Starting " << getServerName() << std::endl;
}
std::map<const char, castor::server::BaseThreadPool*>::const_iterator tp;
......
......@@ -50,9 +50,12 @@ public:
/**
* Constructor
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
*/
MultiThreadedDaemon(log::Logger &logger);
MultiThreadedDaemon(std::ostream &stdOut, std::ostream &stdErr,
log::Logger &logger) throw();
/**
* Destructor.
......
......@@ -60,7 +60,8 @@
int main(int argc, char* argv[]){
try{
castor::log::LoggerImplementation logger("stagerd");
castor::stager::daemon::StagerDaemon stagerDaemon(logger);
castor::stager::daemon::StagerDaemon
stagerDaemon(std::cout, std::cerr, logger);
castor::stager::IStagerSvc* stgService =
dynamic_cast<castor::stager::IStagerSvc*>
......@@ -154,12 +155,12 @@ int main(int argc, char* argv[]){
}// end main
/******************************************************************************************/
/*****************************************************************************************/
/* constructor: initiallizes the DLF logging and set the default value to its attributes */
/****************************************************************************************/
castor::stager::daemon::StagerDaemon::StagerDaemon(log::Logger &logger)
throw (castor::exception::Exception)
: castor::server::MultiThreadedDaemon(logger) {
/*****************************************************************************************/
castor::stager::daemon::StagerDaemon::StagerDaemon(std::ostream &stdOut,
std::ostream &stdErr, log::Logger &logger) throw (castor::exception::Exception)
: castor::server::MultiThreadedDaemon(stdOut, stdErr, logger) {
castor::dlf::Message stagerDlfMessages[]={
......
......@@ -50,10 +50,13 @@ namespace castor{
/**
* Constructor
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging
* system.
*/
StagerDaemon(log::Logger &logger) throw (castor::exception::Exception);
StagerDaemon(std::ostream &stdOut, std::ostream &stdErr,
log::Logger &logger) throw (castor::exception::Exception);
/**
* Destructor
......
......@@ -24,6 +24,7 @@
#include "castor/tape/rmc/Acs.hpp"
#include "castor/tape/utils/utils.hpp"
#include "castor/utils/utils.hpp"
#include <iomanip>
#include <sstream>
......@@ -41,7 +42,7 @@ castor::tape::rmc::Acs::~Acs() throw() {
DRIVEID castor::tape::rmc::Acs::str2DriveId(const std::string &str)
const throw(castor::exception::InvalidArgument) {
std::vector<std::string> components;
utils::splitString(str, ':', components);
castor::utils::splitString(str, ':', components);
// The drive ID should consist of 4 components: ACS, LSM, Panel and Transport
if(4 != components.size()) {
......
......@@ -46,8 +46,9 @@
// constructor
//------------------------------------------------------------------------------
castor::tape::tapebridge::TapeBridgeDaemon::TapeBridgeDaemon(
log::Logger &logger) throw(castor::exception::Exception) :
castor::server::MultiThreadedDaemon(logger),
std::ostream &stdOut, std::ostream &stdErr, log::Logger &logger)
throw(castor::exception::Exception) :
castor::server::MultiThreadedDaemon(stdOut, stdErr, logger),
m_vdqmRequestHandlerThreadPool(0) {
}
......
......@@ -54,9 +54,12 @@ public:
/**
* Constructor.
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
*/
TapeBridgeDaemon(log::Logger &logger) throw(castor::exception::Exception);
TapeBridgeDaemon(std::ostream &stdOut, std::ostream &stdErr,
log::Logger &logger) throw(castor::exception::Exception);
/**
* Destructor.
......@@ -79,6 +82,9 @@ private:
* Exception throwing main() function which basically implements the
* non-exception throwing main() function except for the initialisation of
* DLF and the "exception catch and log" logic.
*
* @param argc The number of command-line arguments.
* @param argv The array of command-line arguments.
*/
int exceptionThrowingMain(const int argc, char **argv)
throw(castor::exception::Exception);
......
......@@ -22,11 +22,10 @@
* @author Nicola.Bessone@cern.ch Steven.Murray@cern.ch
*****************************************************************************/
#include "castor/log/LoggerImplementation.hpp"
#include "castor/tape/tapebridge/TapeBridgeDaemon.hpp"
#include <iostream>
//------------------------------------------------------------------------------
// main
......@@ -34,7 +33,8 @@
int main(int argc, char **argv) {
castor::log::LoggerImplementation logger("tapebridged");
castor::tape::tapebridge::TapeBridgeDaemon daemon(logger);
castor::tape::tapebridge::TapeBridgeDaemon
daemon(std::cout, std::cerr, logger);
return daemon.main(argc, argv);
}
......@@ -165,7 +165,8 @@ int castor::tape::tapegateway::TapeGatewayDaemon::exceptionThrowingMain(int argc
// TapeGatewayDaemon Constructor
//------------------------------------------------------------------------------
castor::tape::tapegateway::TapeGatewayDaemon::TapeGatewayDaemon(
log::Logger &logger): castor::server::MultiThreadedDaemon(logger) {
std::ostream &stdOut, std::ostream &stdErr, log::Logger &logger):
castor::server::MultiThreadedDaemon(stdOut, stdErr,logger) {
// get the port
char* tmp=NULL;
......
......@@ -84,9 +84,12 @@ namespace castor {
/**
* Constructor
*
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
*/
TapeGatewayDaemon(log::Logger &logger);
TapeGatewayDaemon(std::ostream &stdOut, std::ostream &stdErr,
log::Logger &logger);
/**
* The main entry function of the mighunter daemon.
......
......@@ -26,13 +26,16 @@
#include "castor/tape/tapegateway/daemon/TapeGatewayDaemon.hpp"
#include "castor/exception/Exception.hpp"
#include <iostream>
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(int argc, char **argv) {
try {
castor::log::LoggerImplementation logger("tapegatewayd");
castor::tape::tapegateway::TapeGatewayDaemon daemon(logger);
castor::tape::tapegateway::TapeGatewayDaemon
daemon(std::cout, std::cerr, logger);
return daemon.main(argc, argv);
} catch (castor::exception::Exception e) {
std::cerr << "Caught exception :\n" << e.getMessage().str() << "\nExiting" << std::endl;
......
......@@ -22,6 +22,12 @@
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include "tapeserverd.hpp"
#include "castor/log/LoggerImplementation.hpp"
#include "log.h"
#include "castor/io/AbstractSocket.hpp"
#include "castor/exception/Errnum.hpp"
#include <iostream>
#include <exception>
#include <unistd.h>
......@@ -32,23 +38,24 @@
#include <sstream>
#include <signal.h>
#include "tapeserverd.hpp"
#include "castor/log/LoggerImplementation.hpp"
#include "log.h"
#include "castor/io/AbstractSocket.hpp"
#include "castor/exception/Errnum.hpp"
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(int argc, char ** argv) {
return castor::tape::Server::Daemon::main(argc, argv);
}
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int castor::tape::Server::Daemon::main(int argc, char ** argv) throw() {
try {
/* Before anything, we need a logger: */
castor::log::LoggerImplementation logger("tapeserverd");
try {
/* Setup the object (parse command line, register logger) */
castor::tape::Server::Daemon daemon(argc, argv, logger);
castor::tape::Server::Daemon
daemon(argc, argv, std::cout, std::cerr, logger);
/* ... and run. */
daemon.run();
/* Catch all block for any left over exception which will go to the logger */
......@@ -72,13 +79,20 @@ int castor::tape::Server::Daemon::main(int argc, char ** argv) throw() {
return (EXIT_SUCCESS);
}
castor::tape::Server::Daemon::Daemon(int argc, char** argv,
castor::log::Logger & logger) throw (castor::tape::Exception):
castor::server::Daemon(logger),
m_option_run_directory ("/var/log/castor") {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::tape::Server::Daemon::Daemon(int argc, char** argv,
std::ostream &stdOut, std::ostream &stdErr, castor::log::Logger & logger)
throw (castor::tape::Exception):
castor::server::Daemon(stdOut, stdErr, logger),
m_option_run_directory ("/var/log/castor") {
parseCommandLineOptions(argc, argv);
}
//------------------------------------------------------------------------------
// run
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::run() {
/* Block signals, we will handle them synchronously */
blockSignals();
......@@ -91,6 +105,9 @@ void castor::tape::Server::Daemon::run() {
/* Loop on both */
}
//------------------------------------------------------------------------------
// parseCommandLineOptions
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::parseCommandLineOptions(int argc, char** argv)
throw (castor::tape::Exception)
{
......@@ -129,6 +146,9 @@ throw (castor::tape::Exception)
}
}
//------------------------------------------------------------------------------
// daemonize
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::daemonize()
{
pid_t pid, sid;
......@@ -171,6 +191,9 @@ void castor::tape::Server::Daemon::daemonize()
"Failed to freopen stderr in castor::tape::Server::Daemon::daemonize");
}
//------------------------------------------------------------------------------
// blockSignals
//------------------------------------------------------------------------------
void castor::tape::Server::Daemon::blockSignals()
{
sigset_t sigs;
......
......@@ -28,31 +28,50 @@
namespace castor {
namespace tape {
namespace Server {
class Daemon: public castor::server::Daemon {
public:
/** Wrapper for main */
static int main (int argc, char ** argv) throw ();
/** Constructor: parse the command line */
Daemon (int argc, char ** argv, castor::log::Logger & logger)
throw (castor::tape::Exception);
/** Run the daemon: daemonize if needed, and run the main loop. */
void run();
~Daemon() throw () {}
private:
void parseCommandLineOptions(int argc, char ** argv) throw (castor::tape::Exception);
/** This daemonize() version has to be merged into castor::server::Daemon::daemonize
* which has a few things to check (error cases for fork are not handled correctly,
* error cases for setsid are not looked at, there is a forced switch to stager
* user, while taped (and children) and rtcpd (but not its children) run
* as root. There is some calls to signal in daemonize for just 2 signals */
void daemonize();
/** We block all signals, so that they can be handled synchronously with
* a sigtimedwait in the main loop (alternately with a poll using a
* non-zero timeout. */
void blockSignals();
std::string m_option_run_directory;
};
}
}
}
namespace Server {
class Daemon: public castor::server::Daemon {
public:
/** Wrapper for main */
static int main (int argc, char ** argv) throw ();
/**
* Constructor: parse the command line
*
* @param argc The number of command-line arguments.
* @param argv The array of command-line arguments.
* @param stdOut Stream representing standard out.
* @param stdErr Stream representing standard error.
* @param logger Object representing the API of the CASTOR logging system.
*/
Daemon (int argc, char ** argv, std::ostream &stdOut, std::ostream &stdErr,
castor::log::Logger & logger) throw (castor::tape::Exception);
/** Run the daemon: daemonize if needed, and run the main loop. */
void run();
~Daemon() throw () {}
private:
void parseCommandLineOptions(int argc, char ** argv) throw (castor::tape::Exception);
/** This daemonize() version has to be merged into castor::server::Daemon::daemonize
* which has a few things to check (error cases for fork are not handled correctly,
* error cases for setsid are not looked at, there is a forced switch to stager
* user, while taped (and children) and rtcpd (but not its children) run
* as root. There is some calls to signal in daemonize for just 2 signals */
void daemonize();
/** We block all signals, so that they can be handled synchronously with
* a sigtimedwait in the main loop (alternately with a poll using a
* non-zero timeout. */
void blockSignals();
std::string m_option_run_directory;
}; // class Daemon
} // namespace castor
} // namespace tape
} // namespace Server
Supports Markdown