d2_controller_unittests.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config/ccsession.h>
  15. #include <d_test_stubs.h>
  16. #include <d2/d2_controller.h>
  17. #include <d2/d2_process.h>
  18. #include <d2/spec_config.h>
  19. #include <boost/pointer_cast.hpp>
  20. #include <boost/date_time/posix_time/posix_time.hpp>
  21. #include <gtest/gtest.h>
  22. #include <config.h>
  23. #include <sstream>
  24. using namespace boost::posix_time;
  25. namespace isc {
  26. namespace d2 {
  27. /// @brief Test fixture class for testing D2Controller class. This class
  28. /// derives from DControllerTest and wraps a D2Controller. Much of the
  29. /// underlying functionality is in the DControllerBase class which has an
  30. /// extensive set of unit tests that are independent of DHCP-DDNS.
  31. /// @TODO Currently These tests are relatively light and duplicate some of
  32. /// the testing done on the base class. These tests are sufficient to ensure
  33. /// that D2Controller properly derives from its base class and to test the
  34. /// logic that is unique to D2Controller. These tests will be augmented and
  35. /// or new tests added as additional functionality evolves.
  36. /// Unlike the stub testing, there is no use of SimFailure to induce error
  37. /// conditions as this is production code.
  38. class D2ControllerTest : public DControllerTest {
  39. public:
  40. /// @brief Constructor
  41. /// Note the constructor passes in the static D2Controller instance
  42. /// method.
  43. D2ControllerTest() : DControllerTest(D2Controller::instance) {
  44. }
  45. /// @brief Destructor
  46. ~D2ControllerTest() {
  47. }
  48. /// @brief Fetches the D2Controller's D2Process
  49. ///
  50. /// @return A pointer to the process which may be null if it has not yet
  51. /// been instantiated.
  52. D2ProcessPtr getD2Process() {
  53. return (boost::dynamic_pointer_cast<D2Process>(getProcess()));
  54. }
  55. /// @brief Fetches the D2Process's D2Configuration manager
  56. ///
  57. /// @return A pointer to the manager which may be null if it has not yet
  58. /// been instantiated.
  59. D2CfgMgrPtr getD2CfgMgr() {
  60. D2CfgMgrPtr p;
  61. if (getD2Process()) {
  62. p = getD2Process()->getD2CfgMgr();
  63. }
  64. return (p);
  65. }
  66. /// @brief Fetches the D2Configuration manager's D2CfgContext
  67. ///
  68. /// @return A pointer to the context which may be null if it has not yet
  69. /// been instantiated.
  70. D2CfgContextPtr getD2CfgContext() {
  71. D2CfgContextPtr p;
  72. if (getD2CfgMgr()) {
  73. p = getD2CfgMgr()->getD2CfgContext();
  74. }
  75. return (p);
  76. }
  77. };
  78. /// @brief Basic Controller instantiation testing.
  79. /// Verifies that the controller singleton gets created and that the
  80. /// basic derivation from the base class is intact.
  81. TEST_F(D2ControllerTest, basicInstanceTesting) {
  82. // Verify the we can the singleton instance can be fetched and that
  83. // it is the correct type.
  84. DControllerBasePtr& controller = DControllerTest::getController();
  85. ASSERT_TRUE(controller);
  86. ASSERT_NO_THROW(boost::dynamic_pointer_cast<D2Controller>(controller));
  87. // Verify that controller's app name is correct.
  88. EXPECT_TRUE(checkAppName(D2Controller::d2_app_name_));
  89. // Verify that controller's bin name is correct.
  90. EXPECT_TRUE(checkBinName(D2Controller::d2_bin_name_));
  91. // Verify that controller's spec file name is correct.
  92. EXPECT_TRUE(checkSpecFileName(D2_SPECFILE_LOCATION));
  93. // Verify that controller's IOService exists.
  94. EXPECT_TRUE(checkIOService());
  95. // Verify that the Process does NOT exist.
  96. EXPECT_FALSE(checkProcess());
  97. }
  98. /// @brief Tests basic command line processing.
  99. /// Verifies that:
  100. /// 1. Standard command line options are supported.
  101. /// 2. Invalid options are detected.
  102. TEST_F(D2ControllerTest, commandLineArgs) {
  103. char* argv[] = { const_cast<char*>("progName"),
  104. const_cast<char*>("-c"),
  105. const_cast<char*>(DControllerTest::CFG_TEST_FILE),
  106. const_cast<char*>("-v") };
  107. int argc = 4;
  108. // Verify that verbose flag is false initially.
  109. EXPECT_TRUE(checkVerbose(false));
  110. // Verify that standard options can be parsed without error.
  111. EXPECT_NO_THROW(parseArgs(argc, argv));
  112. // Verify that verbose flag is true.
  113. EXPECT_TRUE(checkVerbose(true));
  114. // Verify configuration file name is correct.
  115. EXPECT_TRUE(checkConfigFileName(DControllerTest::CFG_TEST_FILE));
  116. // Verify that an unknown option is detected.
  117. char* argv2[] = { const_cast<char*>("progName"),
  118. const_cast<char*>("-x") };
  119. argc = 2;
  120. EXPECT_THROW(parseArgs(argc, argv2), InvalidUsage);
  121. }
  122. /// @brief Tests application process creation and initialization.
  123. /// Verifies that the process can be successfully created and initialized.
  124. TEST_F(D2ControllerTest, initProcessTesting) {
  125. ASSERT_NO_THROW(initProcess());
  126. EXPECT_TRUE(checkProcess());
  127. }
  128. /// @brief Tests launch and normal shutdown (stand alone mode).
  129. /// This creates an interval timer to generate a normal shutdown and then
  130. /// launches with a valid, stand-alone command line and no simulated errors.
  131. TEST_F(D2ControllerTest, launchNormalShutdown) {
  132. // Write valid_d2_config and then run launch() for 1000 ms.
  133. time_duration elapsed_time;
  134. runWithConfig(valid_d2_config, 1000, elapsed_time);
  135. // Give a generous margin to accomodate slower test environs.
  136. EXPECT_TRUE(elapsed_time.total_milliseconds() >= 800 &&
  137. elapsed_time.total_milliseconds() <= 1300);
  138. }
  139. /// @brief Configuration update event testing.
  140. /// This really tests just the ability of the handlers to invoke the necessary
  141. /// chain of methods and handle error conditions. Configuration parsing and
  142. /// retrieval should be tested as part of the d2 configuration management
  143. /// implementation.
  144. /// This test verifies that:
  145. /// 1. A valid configuration yields a successful parse result.
  146. /// 2. That an application process error in configuration updating is handled
  147. /// properly.
  148. TEST_F(D2ControllerTest, configUpdateTests) {
  149. int rcode = -1;
  150. isc::data::ConstElementPtr answer;
  151. // Initialize the application process.
  152. ASSERT_NO_THROW(initProcess());
  153. EXPECT_TRUE(checkProcess());
  154. // Create a configuration set using a small, valid D2 configuration.
  155. isc::data::ElementPtr config_set =
  156. isc::data::Element::fromJSON(valid_d2_config);
  157. // Verify that given a valid config we get a successful update result.
  158. answer = updateConfig(config_set);
  159. isc::config::parseAnswer(rcode, answer);
  160. EXPECT_EQ(0, rcode);
  161. // Use an invalid configuration to verify parsing error return.
  162. std::string config = "{ \"bogus\": 1000 } ";
  163. config_set = isc::data::Element::fromJSON(config);
  164. answer = updateConfig(config_set);
  165. isc::config::parseAnswer(rcode, answer);
  166. EXPECT_EQ(1, rcode);
  167. }
  168. /// @brief Command execution tests.
  169. /// This really tests just the ability of the handler to invoke the necessary
  170. /// chain of methods and to handle error conditions.
  171. /// This test verifies that:
  172. /// 1. That an unrecognized command is detected and returns a status of
  173. /// d2::COMMAND_INVALID.
  174. /// 2. Shutdown command is recognized and returns a d2::COMMAND_SUCCESS status.
  175. TEST_F(D2ControllerTest, executeCommandTests) {
  176. int rcode = -1;
  177. isc::data::ConstElementPtr answer;
  178. isc::data::ElementPtr arg_set;
  179. // Initialize the application process.
  180. ASSERT_NO_THROW(initProcess());
  181. EXPECT_TRUE(checkProcess());
  182. // Verify that an unknown command returns an COMMAND_INVALID response.
  183. std::string bogus_command("bogus");
  184. answer = executeCommand(bogus_command, arg_set);
  185. isc::config::parseAnswer(rcode, answer);
  186. EXPECT_EQ(COMMAND_INVALID, rcode);
  187. // Verify that shutdown command returns COMMAND_SUCCESS response.
  188. //answer = executeCommand(SHUT_DOWN_COMMAND, isc::data::ElementPtr());
  189. answer = executeCommand(SHUT_DOWN_COMMAND, arg_set);
  190. isc::config::parseAnswer(rcode, answer);
  191. EXPECT_EQ(COMMAND_SUCCESS, rcode);
  192. }
  193. // Tests that the original configuration is retained after a SIGHUP triggered
  194. // reconfiguration fails due to invalid config content.
  195. TEST_F(D2ControllerTest, invalidConfigReload) {
  196. // Schedule to replace the configuration file after launch. This way the
  197. // file is updated after we have done the initial configuration.
  198. scheduleTimedWrite("{ \"string_test\": BOGUS JSON }", 100);
  199. // Setup to raise SIGHUP in 200 ms.
  200. TimedSignal sighup(*getIOService(), SIGHUP, 200);
  201. // Write valid_d2_config and then run launch() for a maximum of 500 ms.
  202. time_duration elapsed_time;
  203. runWithConfig(valid_d2_config, 500, elapsed_time);
  204. // Context is still available post launch.
  205. // Check to see that our configuration matches the original per
  206. // valid_d2_config (see d_test_stubs.cc)
  207. D2CfgMgrPtr d2_cfg_mgr = getD2CfgMgr();
  208. D2ParamsPtr d2_params = d2_cfg_mgr->getD2Params();
  209. ASSERT_TRUE(d2_params);
  210. EXPECT_EQ("127.0.0.1", d2_params->getIpAddress().toText());
  211. EXPECT_EQ(5031, d2_params->getPort());
  212. EXPECT_TRUE(d2_cfg_mgr->forwardUpdatesEnabled());
  213. EXPECT_TRUE(d2_cfg_mgr->reverseUpdatesEnabled());
  214. /// @todo add a way to trap log file and search it
  215. }
  216. // Tests that the original configuration is replaced after a SIGHUP triggered
  217. // reconfiguration succeeds.
  218. TEST_F(D2ControllerTest, validConfigReload) {
  219. // Define a replacement config.
  220. const char* second_cfg =
  221. "{"
  222. " \"ip_address\": \"192.168.77.1\" , "
  223. " \"port\": 777 , "
  224. "\"tsig_keys\": [], "
  225. "\"forward_ddns\" : {}, "
  226. "\"reverse_ddns\" : {} "
  227. "}";
  228. // Schedule to replace the configuration file after launch. This way the
  229. // file is updated after we have done the initial configuration.
  230. scheduleTimedWrite(second_cfg, 100);
  231. // Setup to raise SIGHUP in 200 ms.
  232. TimedSignal sighup(*getIOService(), SIGHUP, 200);
  233. // Write valid_d2_config and then run launch() for a maximum of 500ms.
  234. time_duration elapsed_time;
  235. runWithConfig(valid_d2_config, 500, elapsed_time);
  236. // Context is still available post launch.
  237. // Check to see that our configuration matches the replacement config.
  238. D2CfgMgrPtr d2_cfg_mgr = getD2CfgMgr();
  239. D2ParamsPtr d2_params = d2_cfg_mgr->getD2Params();
  240. ASSERT_TRUE(d2_params);
  241. EXPECT_EQ("192.168.77.1", d2_params->getIpAddress().toText());
  242. EXPECT_EQ(777, d2_params->getPort());
  243. EXPECT_FALSE(d2_cfg_mgr->forwardUpdatesEnabled());
  244. EXPECT_FALSE(d2_cfg_mgr->reverseUpdatesEnabled());
  245. /// @todo add a way to trap log file and search it
  246. }
  247. // Tests that the SIGINT triggers a normal shutdown.
  248. TEST_F(D2ControllerTest, sigintShutdown) {
  249. // Setup to raise SIGHUP in 1 ms.
  250. TimedSignal sighup(*getIOService(), SIGINT, 1);
  251. // Write valid_d2_config and then run launch() for a maximum of 1000 ms.
  252. time_duration elapsed_time;
  253. runWithConfig(valid_d2_config, 1000, elapsed_time);
  254. // Signaled shutdown should make our elapsed time much smaller than
  255. // the maximum run time. Give generous margin to accomodate slow
  256. // test environs.
  257. EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
  258. /// @todo add a way to trap log file and search it
  259. }
  260. // Tests that the SIGTERM triggers a normal shutdown.
  261. TEST_F(D2ControllerTest, sigtermShutdown) {
  262. // Setup to raise SIGHUP in 1 ms.
  263. TimedSignal sighup(*getIOService(), SIGTERM, 1);
  264. // Write valid_d2_config and then run launch() for a maximum of 1 s.
  265. time_duration elapsed_time;
  266. runWithConfig(valid_d2_config, 1000, elapsed_time);
  267. // Signaled shutdown should make our elapsed time much smaller than
  268. // the maximum run time. Give generous margin to accomodate slow
  269. // test environs.
  270. EXPECT_TRUE(elapsed_time.total_milliseconds() < 300);
  271. /// @todo add a way to trap log file and search it
  272. }
  273. }; // end of isc::d2 namespace
  274. }; // end of isc namespace