daemon_unittest.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <exceptions/exceptions.h>
  8. #include <cc/data.h>
  9. #include <dhcpsrv/cfgmgr.h>
  10. #include <dhcpsrv/daemon.h>
  11. #include <dhcpsrv/logging.h>
  12. #include <log/logger_support.h>
  13. #include <gtest/gtest.h>
  14. #include <sys/wait.h>
  15. using namespace isc;
  16. using namespace isc::dhcp;
  17. using namespace isc::data;
  18. namespace isc {
  19. namespace dhcp {
  20. // @brief Derived Daemon class
  21. class DaemonImpl : public Daemon {
  22. public:
  23. static std::string getVersion(bool extended);
  24. using Daemon::makePIDFileName;
  25. };
  26. std::string DaemonImpl::getVersion(bool extended) {
  27. if (extended) {
  28. return (std::string("EXTENDED"));
  29. } else {
  30. return (std::string("BASIC"));
  31. }
  32. }
  33. };
  34. };
  35. namespace {
  36. /// @brief Daemon Test test fixture class
  37. class DaemonTest : public ::testing::Test {
  38. public:
  39. /// @brief Constructor
  40. DaemonTest() : env_copy_() {
  41. // Take a copy of KEA_PIDFILE_DIR environment variable value
  42. char *env_value = getenv("KEA_PIDFILE_DIR");
  43. if (env_value) {
  44. env_copy_ = std::string(env_value);
  45. }
  46. }
  47. /// @brief Destructor
  48. ///
  49. /// As some of the tests have the side-effect of altering the logging
  50. /// settings (when configureLogger is called), the logging is reset to
  51. /// the default after each test completes.
  52. ~DaemonTest() {
  53. isc::log::setDefaultLoggingOutput();
  54. // Restore KEA_PIDFILE_DIR environment variable value
  55. if (env_copy_.empty()) {
  56. static_cast<void>(unsetenv("KEA_PIDFILE_DIR"));
  57. } else {
  58. static_cast<void>(setenv("KEA_PIDFILE_DIR", env_copy_.c_str(), 1));
  59. }
  60. }
  61. private:
  62. /// @brief copy of KEA_PIDFILE_DIR environment variable value
  63. std::string env_copy_;
  64. };
  65. // Very simple test. Checks whether Daemon can be instantiated and its
  66. // default parameters are sane
  67. TEST_F(DaemonTest, constructor) {
  68. // Disable KEA_PIDFILE_DIR
  69. EXPECT_EQ(0, unsetenv("KEA_PIDFILE_DIR"));
  70. EXPECT_NO_THROW(Daemon instance1);
  71. // Check that the verbose mode is not set by default.
  72. Daemon instance2;
  73. EXPECT_FALSE(instance2.getVerbose());
  74. EXPECT_TRUE(instance2.getConfigFile().empty());
  75. EXPECT_TRUE(instance2.getProcName().empty());
  76. EXPECT_EQ(CfgMgr::instance().getDataDir(),instance2.getPIDFileDir());
  77. EXPECT_TRUE(instance2.getPIDFileName().empty());
  78. }
  79. // Verify config file accessors
  80. TEST_F(DaemonTest, getSetConfigFile) {
  81. Daemon instance;
  82. EXPECT_NO_THROW(instance.setConfigFile("test.txt"));
  83. EXPECT_EQ("test.txt", instance.getConfigFile());
  84. }
  85. // Verify process name accessors
  86. TEST_F(DaemonTest, getSetProcName) {
  87. Daemon instance;
  88. EXPECT_NO_THROW(instance.setProcName("myproc"));
  89. EXPECT_EQ("myproc", instance.getProcName());
  90. }
  91. // Verify PID file directory name accessors
  92. TEST_F(DaemonTest, getSetPIDFileDir) {
  93. Daemon instance;
  94. EXPECT_NO_THROW(instance.setPIDFileDir("/tmp"));
  95. EXPECT_EQ("/tmp", instance.getPIDFileDir());
  96. }
  97. // Verify PID file name accessors.
  98. TEST_F(DaemonTest, setPIDFileName) {
  99. Daemon instance;
  100. // Verify that PID file name may not be set to empty
  101. EXPECT_THROW(instance.setPIDFileName(""), BadValue);
  102. EXPECT_NO_THROW(instance.setPIDFileName("myproc"));
  103. EXPECT_EQ("myproc", instance.getPIDFileName());
  104. // Verify that setPIDFileName cannot be called twice on the same instance.
  105. EXPECT_THROW(instance.setPIDFileName("again"), InvalidOperation);
  106. }
  107. // Test the getVersion() redefinition
  108. TEST_F(DaemonTest, getVersion) {
  109. EXPECT_THROW(Daemon::getVersion(false), NotImplemented);
  110. ASSERT_NO_THROW(DaemonImpl::getVersion(false));
  111. EXPECT_EQ(DaemonImpl::getVersion(false), "BASIC");
  112. ASSERT_NO_THROW(DaemonImpl::getVersion(true));
  113. EXPECT_EQ(DaemonImpl::getVersion(true), "EXTENDED");
  114. }
  115. // Verify makePIDFileName method
  116. TEST_F(DaemonTest, makePIDFileName) {
  117. DaemonImpl instance;
  118. // Verify that config file cannot be blank
  119. instance.setProcName("notblank");
  120. EXPECT_THROW(instance.makePIDFileName(), InvalidOperation);
  121. // Verify that proc name cannot be blank
  122. instance.setProcName("");
  123. instance.setConfigFile("notblank");
  124. EXPECT_THROW(instance.makePIDFileName(), InvalidOperation);
  125. // Verify that config file must contain a file name
  126. instance.setProcName("myproc");
  127. instance.setConfigFile(".txt");
  128. EXPECT_THROW(instance.makePIDFileName(), BadValue);
  129. instance.setConfigFile("/tmp/");
  130. EXPECT_THROW(instance.makePIDFileName(), BadValue);
  131. // Given a valid config file name and proc name we should good to go
  132. instance.setConfigFile("/tmp/test.conf");
  133. std::string name;
  134. EXPECT_NO_THROW(name = instance.makePIDFileName());
  135. // Make sure the name is as we expect
  136. std::ostringstream stream;
  137. stream << instance.getPIDFileDir() << "/test.myproc.pid";
  138. EXPECT_EQ(stream.str(), name);
  139. // Verify that the default directory can be overridden
  140. instance.setPIDFileDir("/tmp");
  141. EXPECT_NO_THROW(name = instance.makePIDFileName());
  142. EXPECT_EQ("/tmp/test.myproc.pid", name);
  143. }
  144. // Verifies the creation a PID file and that a pre-existing PID file
  145. // which points to a live PID causes a throw.
  146. TEST_F(DaemonTest, createPIDFile) {
  147. DaemonImpl instance;
  148. instance.setConfigFile("test.conf");
  149. instance.setProcName("daemon_test");
  150. instance.setPIDFileDir(TEST_DATA_BUILDDIR);
  151. EXPECT_NO_THROW(instance.createPIDFile());
  152. std::ostringstream stream;
  153. stream << TEST_DATA_BUILDDIR << "/test.daemon_test.pid";
  154. EXPECT_EQ(stream.str(), instance.getPIDFileName());
  155. // If we try again, we should see our own PID file and fail
  156. EXPECT_THROW(instance.createPIDFile(), DaemonPIDExists);
  157. }
  158. // Verifies that a pre-existing PID file which points to a dead PID
  159. // is overwritten.
  160. TEST_F(DaemonTest, createPIDFileOverwrite) {
  161. DaemonImpl instance;
  162. // We're going to use fork to generate a PID we KNOW is dead.
  163. int pid = fork();
  164. ASSERT_GE(pid, 0);
  165. if (pid == 0) {
  166. // This is the child, die right away. Tragic, no?
  167. exit (0);
  168. }
  169. // Back in the parent test, we need to wait for the child to die
  170. // As with debugging waitpid() can be interrupted ignore EINTR.
  171. int stat;
  172. int ret;
  173. do {
  174. ret = waitpid(pid, &stat, 0);
  175. } while ((ret == -1) && (errno == EINTR));
  176. ASSERT_EQ(ret, pid);
  177. // Ok, so we should now have a PID that we know to be dead.
  178. // Let's use it to create a PID file.
  179. instance.setConfigFile("test.conf");
  180. instance.setProcName("daemon_test");
  181. instance.setPIDFileDir(TEST_DATA_BUILDDIR);
  182. EXPECT_NO_THROW(instance.createPIDFile(pid));
  183. // If we try to create the PID file again, this should work.
  184. EXPECT_NO_THROW(instance.createPIDFile());
  185. }
  186. // Verifies that Daemon destruction deletes the PID file
  187. TEST_F(DaemonTest, PIDFileCleanup) {
  188. boost::shared_ptr<DaemonImpl> instance;
  189. instance.reset(new DaemonImpl);
  190. instance->setConfigFile("test.conf");
  191. instance->setProcName("daemon_test");
  192. instance->setPIDFileDir(TEST_DATA_BUILDDIR);
  193. EXPECT_NO_THROW(instance->createPIDFile());
  194. // If we try again, we should see our own PID file
  195. EXPECT_THROW(instance->createPIDFile(), DaemonPIDExists);
  196. // Save the pid file name
  197. std::string pid_file_name = instance->getPIDFileName();
  198. // Now delete the Daemon instance. This should remove the
  199. // PID file.
  200. instance.reset();
  201. struct stat stat_buf;
  202. ASSERT_EQ(-1, stat(pid_file_name.c_str(), &stat_buf));
  203. EXPECT_EQ(errno, ENOENT);
  204. }
  205. // Checks that configureLogger method is behaving properly.
  206. // More dedicated tests are availablef for LogConfigParser class.
  207. // See logger_unittest.cc
  208. TEST_F(DaemonTest, parsingConsoleOutput) {
  209. CfgMgr::instance().setVerbose(false);
  210. // Storage - parsed configuration will be stored here
  211. SrvConfigPtr storage(new SrvConfig());
  212. const char* config_txt =
  213. "{ \"loggers\": ["
  214. " {"
  215. " \"name\": \"kea\","
  216. " \"output_options\": ["
  217. " {"
  218. " \"output\": \"stdout\""
  219. " }"
  220. " ],"
  221. " \"debuglevel\": 99,"
  222. " \"severity\": \"DEBUG\""
  223. " }"
  224. "]}";
  225. ConstElementPtr config = Element::fromJSON(config_txt);
  226. // Spawn a daemon and tell it to configure logger
  227. Daemon x;
  228. EXPECT_NO_THROW(x.configureLogger(config, storage));
  229. // The parsed configuration should be processed by the daemon and
  230. // stored in configuration storage.
  231. ASSERT_EQ(1, storage->getLoggingInfo().size());
  232. EXPECT_EQ("kea", storage->getLoggingInfo()[0].name_);
  233. EXPECT_EQ(99, storage->getLoggingInfo()[0].debuglevel_);
  234. EXPECT_EQ(isc::log::DEBUG, storage->getLoggingInfo()[0].severity_);
  235. ASSERT_EQ(1, storage->getLoggingInfo()[0].destinations_.size());
  236. EXPECT_EQ("stdout" , storage->getLoggingInfo()[0].destinations_[0].output_);
  237. }
  238. // More tests will appear here as we develop Daemon class.
  239. };