// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <string>
-
-#include <boost/scoped_ptr.hpp>
-#include <boost/shared_ptr.hpp>
+#include <auth/command.h>
+#include <auth/auth_log.h>
+#include <auth/auth_srv.h>
#include <exceptions/exceptions.h>
#include <config/ccsession.h>
-#include <auth/auth_log.h>
-#include <auth/auth_srv.h>
-#include <auth/command.h>
+#include <string>
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <sys/types.h>
+#include <unistd.h>
using boost::scoped_ptr;
using namespace isc::auth;
virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) = 0;
};
-// Handle the "shutdown" command. No argument is assumed.
+// Handle the "shutdown" command. An optional parameter "pid" is used to
+// see if it is really for our instance.
class ShutdownCommand : public AuthCommand {
public:
- virtual void exec(AuthSrv& server, isc::data::ConstElementPtr) {
+ virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
+ // Is the pid argument provided?
+ if (args && args->getType() ==
+ isc::data::Element::map && args->contains("pid")) {
+ // If it is, we check it is the same as our PID
+ int pid(args->get("pid")->intValue());
+ pid_t my_pid(getpid());
+ if (my_pid != pid) {
+ // It is not for us
+ return;
+ }
+ }
server.stop();
}
};
#include <config.h>
-#include <cassert>
-#include <cstdlib>
-#include <string>
-#include <stdexcept>
-
-#include <boost/bind.hpp>
-
-#include <gtest/gtest.h>
+#include <auth/auth_srv.h>
+#include <auth/auth_config.h>
+#include <auth/command.h>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <datasrc/memory_datasrc.h>
-#include <auth/auth_srv.h>
-#include <auth/auth_config.h>
-#include <auth/command.h>
-
#include <asiolink/asiolink.h>
#include <testutils/mockups.h>
+#include <cassert>
+#include <cstdlib>
+#include <string>
+#include <stdexcept>
+
+#include <boost/bind.hpp>
+
+#include <gtest/gtest.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
using namespace std;
using namespace isc::dns;
using namespace isc::data;
namespace {
class AuthCommandTest : public ::testing::Test {
protected:
- AuthCommandTest() : server(false, xfrout), rcode(-1) {
+ AuthCommandTest() :
+ server(false, xfrout),
+ rcode(-1),
+ itimer_(server.getIOService())
+ {
server.setStatisticsSession(&statistics_session);
}
void checkAnswer(const int expected_code) {
MockXfroutClient xfrout;
AuthSrv server;
ConstElementPtr result;
+ // The shutdown command parameter
+ ConstElementPtr param;
int rcode;
+ isc::asiolink::IntervalTimer itimer_;
public:
void stopServer(); // need to be public for boost::bind
+ void dontStopServer(); // need to be public for boost::bind
};
TEST_F(AuthCommandTest, unknownCommand) {
void
AuthCommandTest::stopServer() {
- result = execAuthServerCommand(server, "shutdown", ConstElementPtr());
+ result = execAuthServerCommand(server, "shutdown", param);
parseAnswer(rcode, result);
assert(rcode == 0); // make sure the test stops when something is wrong
}
TEST_F(AuthCommandTest, shutdown) {
- isc::asiolink::IntervalTimer itimer(server.getIOService());
- itimer.setup(boost::bind(&AuthCommandTest::stopServer, this), 1);
+ // Param defaults to empty/null pointer on creation
+ itimer_.setup(boost::bind(&AuthCommandTest::stopServer, this), 1);
+ server.getIOService().run();
+ EXPECT_EQ(0, rcode);
+}
+
+TEST_F(AuthCommandTest, shutdownCorrectPID) {
+ // Put the pid parameter there
+ pid_t pid(getpid());
+ ElementPtr param(new isc::data::MapElement());
+ param->set("pid", ConstElementPtr(new isc::data::IntElement(pid)));
+ this->param = param;
+ // With the correct PID, it should act exactly the same as in case
+ // of no parameter
+ itimer_.setup(boost::bind(&AuthCommandTest::stopServer, this), 1);
+ server.getIOService().run();
+ EXPECT_EQ(0, rcode);
+}
+
+// This is like stopServer, but the server should not stop after the
+// command, it should be running
+void
+AuthCommandTest::dontStopServer() {
+ result = execAuthServerCommand(server, "shutdown", param);
+ parseAnswer(rcode, result);
+ EXPECT_EQ(0, rcode);
+ rcode = -1;
+ // We run the stopServer now, to really stop the server.
+ // If it had stopped already, it won't be run and the rcode -1 will
+ // be left here.
+ param = ConstElementPtr();
+ itimer_.cancel();
+ itimer_.setup(boost::bind(&AuthCommandTest::stopServer, this), 1);
+}
+
+TEST_F(AuthCommandTest, shutdownIncorrectPID) {
+ // The PID = 0 should be taken by init, so we are not init and the
+ // PID should be different
+ param = Element::fromJSON("{\"pid\": 0}");
+ itimer_.setup(boost::bind(&AuthCommandTest::dontStopServer, this), 1);
server.getIOService().run();
EXPECT_EQ(0, rcode);
}