d2_process_unittests.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // Copyright (C) 2013-2015 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.h>
  15. #include <asiolink/io_service.h>
  16. #include <config/command_interpreter.h>
  17. #include <d2/d2_process.h>
  18. #include <dhcp_ddns/ncr_io.h>
  19. #include <d_test_stubs.h>
  20. #include <boost/bind.hpp>
  21. #include <boost/date_time/posix_time/posix_time.hpp>
  22. #include <gtest/gtest.h>
  23. #include <sstream>
  24. using namespace std;
  25. using namespace isc;
  26. using namespace isc::config;
  27. using namespace isc::d2;
  28. using namespace boost::posix_time;
  29. namespace {
  30. /// @brief Valid configuration containing an unavailable IP address.
  31. const char* bad_ip_d2_config = "{ "
  32. "\"ip_address\" : \"1.1.1.1\" , "
  33. "\"port\" : 5031, "
  34. "\"tsig_keys\": ["
  35. "{ \"name\": \"d2_key.tmark.org\" , "
  36. " \"algorithm\": \"HMAC-MD5\" ,"
  37. " \"secret\": \"LSWXnfkKZjdPJI5QxlpnfQ==\" "
  38. "} ],"
  39. "\"forward_ddns\" : {"
  40. "\"ddns_domains\": [ "
  41. "{ \"name\": \"tmark.org\" , "
  42. " \"key_name\": \"d2_key.tmark.org\" , "
  43. " \"dns_servers\" : [ "
  44. " { \"ip_address\": \"127.0.0.101\" } "
  45. "] } ] }, "
  46. "\"reverse_ddns\" : {"
  47. "\"ddns_domains\": [ "
  48. "{ \"name\": \" 0.168.192.in.addr.arpa.\" , "
  49. " \"key_name\": \"d2_key.tmark.org\" , "
  50. " \"dns_servers\" : [ "
  51. " { \"ip_address\": \"127.0.0.101\" , "
  52. " \"port\": 100 } ] } "
  53. "] } }";
  54. /// @brief D2Process test fixture class
  55. //class D2ProcessTest : public D2Process, public ::testing::Test {
  56. class D2ProcessTest : public D2Process, public ConfigParseTest {
  57. public:
  58. /// @brief Constructor
  59. D2ProcessTest() :
  60. D2Process("d2test",
  61. asiolink::IOServicePtr(new isc::asiolink::IOService())) {
  62. }
  63. /// @brief Destructor
  64. virtual ~D2ProcessTest() {
  65. }
  66. /// @brief Callback that will invoke shutdown method.
  67. void genShutdownCallback() {
  68. shutdown(isc::data::ConstElementPtr());
  69. }
  70. /// @brief Callback that throws an exception.
  71. void genFatalErrorCallback() {
  72. isc_throw (DProcessBaseError, "simulated fatal error");
  73. }
  74. /// @brief Reconfigures and starts the queue manager given a configuration.
  75. ///
  76. /// This method emulates the reception of a new configuration and should
  77. /// conclude with the Queue manager placed in the RUNNING state.
  78. ///
  79. /// @param config is the configuration to use
  80. ///
  81. /// @return Returns AssertionSuccess if the queue manager was successfully
  82. /// reconfigured, AssertionFailure otherwise.
  83. ::testing::AssertionResult runWithConfig(const char* config) {
  84. int rcode = -1;
  85. // Convert the string configuration into an Element set.
  86. ::testing::AssertionResult res = fromJSON(config);
  87. if (res != ::testing::AssertionSuccess()) {
  88. return res;
  89. }
  90. isc::data::ConstElementPtr answer = configure(config_set_);
  91. isc::data::ConstElementPtr comment;
  92. comment = isc::config::parseAnswer(rcode, answer);
  93. if (rcode) {
  94. return (::testing::AssertionFailure(::testing::Message() <<
  95. "configure() failed:"
  96. << comment));
  97. }
  98. // Must call checkQueueStatus, to cause queue manager to reconfigure
  99. // and start.
  100. checkQueueStatus();
  101. const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();
  102. // If queue manager isn't in the RUNNING state, return failure.
  103. if (D2QueueMgr::RUNNING != queue_mgr->getMgrState()) {
  104. return (::testing::AssertionFailure(::testing::Message() <<
  105. "queue manager did not start"));
  106. }
  107. // Good to go.
  108. return (::testing::AssertionSuccess());
  109. }
  110. /// @brief Checks if shutdown criteria would be met given a shutdown type.
  111. ///
  112. /// This method sets the D2Process shutdown type to the given value, and
  113. /// calls the canShutdown() method, returning its return value.
  114. ///
  115. /// @return Returns the boolean result canShutdown.
  116. bool checkCanShutdown(ShutdownType shutdown_type) {
  117. setShutdownType(shutdown_type);
  118. return (canShutdown());
  119. }
  120. };
  121. /// @brief Verifies D2Process construction behavior.
  122. /// 1. Verifies that constructor fails with an invalid IOService
  123. /// 2. Verifies that constructor succeeds with a valid IOService
  124. /// 3. Verifies that all managers are accessible
  125. TEST(D2Process, construction) {
  126. // Verify that the constructor will fail if given an empty
  127. // io service.
  128. asiolink::IOServicePtr lcl_io_service;
  129. EXPECT_THROW (D2Process("TestProcess", lcl_io_service), DProcessBaseError);
  130. // Verify that the constructor succeeds with a valid io_service
  131. lcl_io_service.reset(new isc::asiolink::IOService());
  132. ASSERT_NO_THROW (D2Process("TestProcess", lcl_io_service));
  133. // Verify that the configuration, queue, and update managers
  134. // are all accessible after construction.
  135. D2Process d2process("TestProcess", lcl_io_service);
  136. D2CfgMgrPtr cfg_mgr = d2process.getD2CfgMgr();
  137. ASSERT_TRUE(cfg_mgr);
  138. D2QueueMgrPtr queue_mgr = d2process.getD2QueueMgr();
  139. ASSERT_TRUE(queue_mgr);
  140. const D2UpdateMgrPtr& update_mgr = d2process.getD2UpdateMgr();
  141. ASSERT_TRUE(update_mgr);
  142. }
  143. /// @brief Verifies basic configure method behavior.
  144. /// This test primarily verifies that upon receipt of a new configuration,
  145. /// D2Process will reconfigure the queue manager if the configuration is valid,
  146. /// or leave queue manager unaffected if not. Currently, the queue manager is
  147. /// only D2 component that must adapt to new configurations. Other components,
  148. /// such as Transactions will be unaffected as they are transient and use
  149. /// whatever configuration was in play at the time they were created.
  150. /// If other components need to provide "dynamic" configuration responses,
  151. /// those tests would need to be added.
  152. TEST_F(D2ProcessTest, configure) {
  153. // Verify the queue manager is not yet initialized.
  154. D2QueueMgrPtr queue_mgr = getD2QueueMgr();
  155. ASSERT_TRUE(queue_mgr);
  156. ASSERT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr->getMgrState());
  157. // Verify that reconfigure queue manager flag is false.
  158. ASSERT_FALSE(getReconfQueueFlag());
  159. // Create a valid configuration set from text config.
  160. ASSERT_TRUE(fromJSON(valid_d2_config));
  161. // Invoke configure() with a valid D2 configuration.
  162. isc::data::ConstElementPtr answer = configure(config_set_);
  163. // Verify that configure result is success and reconfigure queue manager
  164. // flag is true.
  165. ASSERT_TRUE(checkAnswer(answer, 0));
  166. ASSERT_TRUE(getReconfQueueFlag());
  167. // Call checkQueueStatus, to cause queue manager to reconfigure and start.
  168. checkQueueStatus();
  169. // Verify that queue manager is now in the RUNNING state, and flag is false.
  170. ASSERT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
  171. ASSERT_FALSE(getReconfQueueFlag());
  172. // Create an invalid configuration set from text config.
  173. ASSERT_TRUE(fromJSON("{ \"bogus\": 1000 } "));
  174. // Invoke configure() with the invalid configuration.
  175. answer = configure(config_set_);
  176. // Verify that configure result is failure, the reconfigure flag is
  177. // false, and that the queue manager is still running.
  178. ASSERT_TRUE(checkAnswer(answer, 1));
  179. EXPECT_FALSE(getReconfQueueFlag());
  180. EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
  181. }
  182. /// @brief Tests checkQueueStatus() logic for stopping the queue on shutdown
  183. /// This test manually sets shutdown flag and verifies that queue manager
  184. /// stop is initiated.
  185. TEST_F(D2ProcessTest, queueStopOnShutdown) {
  186. ASSERT_TRUE(runWithConfig(valid_d2_config));
  187. const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();
  188. setShutdownFlag(true);
  189. // Calling checkQueueStatus restart queue manager
  190. checkQueueStatus();
  191. // Verify that the queue manager is stopping.
  192. EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());
  193. // Verify that a subsequent call with no events occurring in between,
  194. // results in no change to queue manager
  195. checkQueueStatus();
  196. // Verify that the queue manager is still stopping.
  197. EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());
  198. // Call runIO so the IO cancel event occurs and verify that queue manager
  199. // has stopped.
  200. runIO();
  201. ASSERT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState());
  202. }
  203. /// @brief Tests checkQueueStatus() logic for stopping the queue on reconfigure.
  204. /// This test manually sets queue reconfiguration flag and verifies that queue
  205. /// manager stop is initiated.
  206. TEST_F(D2ProcessTest, queueStopOnReconf) {
  207. ASSERT_TRUE(runWithConfig(valid_d2_config));
  208. const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();
  209. // Manually set the reconfigure indicator.
  210. setReconfQueueFlag(true);
  211. // Calling checkQueueStatus should initiate stopping the queue manager.
  212. checkQueueStatus();
  213. // Verify that the queue manager is stopping.
  214. EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());
  215. // Call runIO so the IO cancel event occurs and verify that queue manager
  216. // has stopped.
  217. runIO();
  218. ASSERT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState());
  219. }
  220. /// @brief Tests checkQueueStatus() logic for recovering from queue full
  221. /// This test manually creates a receive queue full condition and then
  222. /// "drains" the queue until the queue manager resumes listening. This
  223. /// verifies D2Process's ability to recover from a queue full condition.
  224. TEST_F(D2ProcessTest, queueFullRecovery) {
  225. // Valid test message, contents are unimportant.
  226. const char* test_msg =
  227. "{"
  228. " \"change_type\" : 0 , "
  229. " \"forward_change\" : true , "
  230. " \"reverse_change\" : false , "
  231. " \"fqdn\" : \"walah.walah.com\" , "
  232. " \"ip_address\" : \"192.168.2.1\" , "
  233. " \"dhcid\" : \"010203040A7F8E3D\" , "
  234. " \"lease_expires_on\" : \"20130121132405\" , "
  235. " \"lease_length\" : 1300 "
  236. "}";
  237. // Start queue manager with known good config.
  238. ASSERT_TRUE(runWithConfig(valid_d2_config));
  239. const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();
  240. // Set the maximum queue size to manageable number.
  241. size_t max_queue_size = 5;
  242. queue_mgr->setMaxQueueSize(max_queue_size);
  243. // Manually enqueue max requests.
  244. dhcp_ddns::NameChangeRequestPtr ncr;
  245. ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(test_msg));
  246. for (int i = 0; i < max_queue_size; i++) {
  247. // Verify that the request can be added to the queue and queue
  248. // size increments accordingly.
  249. ASSERT_NO_THROW(queue_mgr->enqueue(ncr));
  250. ASSERT_EQ(i+1, queue_mgr->getQueueSize());
  251. }
  252. // Since we are not really receiving, we will simulate QUEUE FULL
  253. // detection.
  254. queue_mgr->stopListening(D2QueueMgr::STOPPED_QUEUE_FULL);
  255. ASSERT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());
  256. // Call runIO so the IO cancel event occurs and verify that queue manager
  257. // has stopped.
  258. runIO();
  259. ASSERT_EQ(D2QueueMgr::STOPPED_QUEUE_FULL, queue_mgr->getMgrState());
  260. // Dequeue requests one at a time, calling checkQueueStatus after each
  261. // dequeue, until we reach the resume threshold. This simulates update
  262. // manager consuming jobs. Queue manager should remain stopped during
  263. // this loop.
  264. int resume_threshold = (max_queue_size * QUEUE_RESTART_PERCENT);
  265. while (queue_mgr->getQueueSize() > resume_threshold) {
  266. checkQueueStatus();
  267. ASSERT_EQ(D2QueueMgr::STOPPED_QUEUE_FULL, queue_mgr->getMgrState());
  268. ASSERT_NO_THROW(queue_mgr->dequeue());
  269. }
  270. // Dequeue one more, which brings us under the threshold and call
  271. // checkQueueStatus.
  272. // Verify that the queue manager is again running.
  273. ASSERT_NO_THROW(queue_mgr->dequeue());
  274. checkQueueStatus();
  275. EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
  276. }
  277. /// @brief Tests checkQueueStatus() logic for queue receive error recovery
  278. /// This test manually creates a queue receive error condition and tests
  279. /// verifies that checkQueueStatus reacts properly to recover.
  280. TEST_F(D2ProcessTest, queueErrorRecovery) {
  281. ASSERT_TRUE(runWithConfig(valid_d2_config));
  282. const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();
  283. // Since we are not really receiving, we have to stage an error.
  284. queue_mgr->stopListening(D2QueueMgr::STOPPED_RECV_ERROR);
  285. ASSERT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());
  286. // Call runIO so the IO cancel event occurs and verify that queue manager
  287. // has stopped.
  288. runIO();
  289. ASSERT_EQ(D2QueueMgr::STOPPED_RECV_ERROR, queue_mgr->getMgrState());
  290. // Calling checkQueueStatus should restart queue manager
  291. checkQueueStatus();
  292. // Verify that queue manager is again running.
  293. EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
  294. }
  295. /// @brief Verifies queue manager recovery from unusable configuration
  296. /// This test checks D2Process's gracefully handle a configuration which
  297. /// while valid is not operationally usable (i.e. IP address is unavailable),
  298. /// and to subsequently recover given a usable configuration.
  299. TEST_F(D2ProcessTest, badConfigureRecovery) {
  300. D2QueueMgrPtr queue_mgr = getD2QueueMgr();
  301. ASSERT_TRUE(queue_mgr);
  302. // Verify the queue manager is not initialized.
  303. EXPECT_EQ(D2QueueMgr::NOT_INITTED, queue_mgr->getMgrState());
  304. // Invoke configure() with a valid config that contains an unusable IP
  305. ASSERT_TRUE(fromJSON(bad_ip_d2_config));
  306. isc::data::ConstElementPtr answer = configure(config_set_);
  307. // Verify that configure result is success and reconfigure queue manager
  308. // flag is true.
  309. ASSERT_TRUE(checkAnswer(answer, 0));
  310. ASSERT_TRUE(getReconfQueueFlag());
  311. // Call checkQueueStatus to cause queue manager to attempt to reconfigure.
  312. checkQueueStatus();
  313. // Verify that queue manager failed to start, (i.e. is in INITTED state),
  314. // and the the reconfigure flag is false.
  315. ASSERT_EQ(D2QueueMgr::INITTED, queue_mgr->getMgrState());
  316. ASSERT_FALSE(getReconfQueueFlag());
  317. // Verify we can recover given a valid config with an usable IP address.
  318. ASSERT_TRUE(fromJSON(valid_d2_config));
  319. answer = configure(config_set_);
  320. // Verify that configure result is success and reconfigure queue manager
  321. // flag is true.
  322. ASSERT_TRUE(checkAnswer(answer, 0));
  323. ASSERT_TRUE(getReconfQueueFlag());
  324. // Call checkQueueStatus to cause queue manager to reconfigure and start.
  325. checkQueueStatus();
  326. // Verify that queue manager is now in the RUNNING state, and reconfigure
  327. // flag is false.
  328. EXPECT_EQ(D2QueueMgr::RUNNING, queue_mgr->getMgrState());
  329. EXPECT_FALSE(getReconfQueueFlag());
  330. }
  331. /// @brief Verifies basic command method behavior.
  332. /// @TODO IF the D2Process is extended to support extra commands this testing
  333. /// will need to augmented accordingly.
  334. TEST_F(D2ProcessTest, command) {
  335. // Verify that the process will process unsupported command and
  336. // return a failure response.
  337. int rcode = -1;
  338. string args = "{ \"arg1\": 77 } ";
  339. isc::data::ElementPtr json = isc::data::Element::fromJSON(args);
  340. isc::data::ConstElementPtr answer = command("bogus_command", json);
  341. parseAnswer(rcode, answer);
  342. EXPECT_EQ(COMMAND_INVALID, rcode);
  343. }
  344. /// @brief Tests shutdown command argument parsing
  345. /// The shutdown command supports an optional "type" argument. This test
  346. /// checks that for valid values, the shutdown() method: sets the shutdown
  347. /// type to correct value, set the shutdown flag to true, and returns a
  348. /// success response; and for invalid values: sets the shutdown flag to false
  349. /// and returns a failure response.
  350. TEST_F(D2ProcessTest, shutdownArgs) {
  351. isc::data::ElementPtr args;
  352. isc::data::ConstElementPtr answer;
  353. const char* default_args = "{}";
  354. const char* normal_args = "{ \"type\" : \"normal\" }";
  355. const char* drain_args = "{ \"type\" : \"drain_first\" }";
  356. const char* now_args = "{ \"type\" : \"now\" }";
  357. const char* bogus_args = "{ \"type\" : \"bogus\" }";
  358. // Verify defaulting to SD_NORMAL if no argument is given.
  359. ASSERT_NO_THROW(args = isc::data::Element::fromJSON(default_args));
  360. EXPECT_NO_THROW(answer = shutdown(args));
  361. ASSERT_TRUE(checkAnswer(answer, 0));
  362. EXPECT_EQ(SD_NORMAL, getShutdownType());
  363. EXPECT_TRUE(shouldShutdown());
  364. // Verify argument value "normal".
  365. ASSERT_NO_THROW(args = isc::data::Element::fromJSON(normal_args));
  366. EXPECT_NO_THROW(answer = shutdown(args));
  367. ASSERT_TRUE(checkAnswer(answer, 0));
  368. EXPECT_EQ(SD_NORMAL, getShutdownType());
  369. EXPECT_TRUE(shouldShutdown());
  370. // Verify argument value "drain_first".
  371. ASSERT_NO_THROW(args = isc::data::Element::fromJSON(drain_args));
  372. EXPECT_NO_THROW(answer = shutdown(args));
  373. ASSERT_TRUE(checkAnswer(answer, 0));
  374. EXPECT_EQ(SD_DRAIN_FIRST, getShutdownType());
  375. EXPECT_TRUE(shouldShutdown());
  376. // Verify argument value "now".
  377. ASSERT_NO_THROW(args = isc::data::Element::fromJSON(now_args));
  378. EXPECT_NO_THROW(answer = shutdown(args));
  379. ASSERT_TRUE(checkAnswer(answer, 0));
  380. EXPECT_EQ(SD_NOW, getShutdownType());
  381. EXPECT_TRUE(shouldShutdown());
  382. // Verify correct handling of an invalid value.
  383. ASSERT_NO_THROW(args = isc::data::Element::fromJSON(bogus_args));
  384. EXPECT_NO_THROW(answer = shutdown(args));
  385. ASSERT_TRUE(checkAnswer(answer, 1));
  386. EXPECT_FALSE(shouldShutdown());
  387. }
  388. /// @brief Tests shutdown criteria logic
  389. /// D2Process using the method canShutdown() to determine if a shutdown
  390. /// can be performed given the value of the shutdown flag and the type of
  391. /// shutdown requested. For each shutdown type certain criteria must be met
  392. /// before the shutdown is permitted. This method is invoked once each pass
  393. /// through the main event loop. This test checks the operation of the
  394. /// canShutdown method. It uses a convenience method, checkCanShutdown(),
  395. /// which sets the shutdown type to the given value and invokes canShutdown(),
  396. /// returning its result.
  397. TEST_F(D2ProcessTest, canShutdown) {
  398. ASSERT_TRUE(runWithConfig(valid_d2_config));
  399. const D2QueueMgrPtr& queue_mgr = getD2QueueMgr();
  400. // Shutdown flag is false. Method should return false for all types.
  401. EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
  402. EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
  403. EXPECT_FALSE(checkCanShutdown(SD_NOW));
  404. // Set shutdown flag to true.
  405. setShutdownFlag(true);
  406. // Queue Manager is running, queue is empty, no transactions.
  407. // Only SD_NOW should return true.
  408. EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
  409. EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
  410. EXPECT_TRUE(checkCanShutdown(SD_NOW));
  411. // Tell queue manager to stop.
  412. queue_mgr->stopListening();
  413. // Verify that the queue manager is stopping.
  414. EXPECT_EQ(D2QueueMgr::STOPPING, queue_mgr->getMgrState());
  415. // Queue Manager is stopping, queue is empty, no transactions.
  416. // Only SD_NOW should return true.
  417. EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
  418. EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
  419. EXPECT_TRUE(checkCanShutdown(SD_NOW));
  420. // Allow cancel event to process.
  421. ASSERT_NO_THROW(runIO());
  422. // Verify that queue manager is stopped.
  423. EXPECT_EQ(D2QueueMgr::STOPPED, queue_mgr->getMgrState());
  424. // Queue Manager is stopped, queue is empty, no transactions.
  425. // All types should return true.
  426. EXPECT_TRUE(checkCanShutdown(SD_NORMAL));
  427. EXPECT_TRUE(checkCanShutdown(SD_DRAIN_FIRST));
  428. EXPECT_TRUE(checkCanShutdown(SD_NOW));
  429. const char* test_msg =
  430. "{"
  431. " \"change_type\" : 0 , "
  432. " \"forward_change\" : true , "
  433. " \"reverse_change\" : false , "
  434. " \"fqdn\" : \"fish.tmark.org\" , "
  435. " \"ip_address\" : \"192.168.2.1\" , "
  436. " \"dhcid\" : \"010203040A7F8E3D\" , "
  437. " \"lease_expires_on\" : \"20130121132405\" , "
  438. " \"lease_length\" : 1300 "
  439. "}";
  440. // Manually enqueue a request. This lets us test logic with queue
  441. // not empty.
  442. dhcp_ddns::NameChangeRequestPtr ncr;
  443. ASSERT_NO_THROW(ncr = dhcp_ddns::NameChangeRequest::fromJSON(test_msg));
  444. ASSERT_NO_THROW(queue_mgr->enqueue(ncr));
  445. ASSERT_EQ(1, queue_mgr->getQueueSize());
  446. // Queue Manager is stopped. Queue is not empty, no transactions.
  447. // SD_DRAIN_FIRST should be false, SD_NORMAL and SD_NOW should be true.
  448. EXPECT_TRUE(checkCanShutdown(SD_NORMAL));
  449. EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
  450. EXPECT_TRUE(checkCanShutdown(SD_NOW));
  451. // Now use update manager to dequeue the request and make a transaction.
  452. // This lets us verify transaction list not empty logic.
  453. const D2UpdateMgrPtr& update_mgr = getD2UpdateMgr();
  454. ASSERT_TRUE(update_mgr);
  455. ASSERT_NO_THROW(update_mgr->sweep());
  456. ASSERT_EQ(0, queue_mgr->getQueueSize());
  457. ASSERT_EQ(1, update_mgr->getTransactionCount());
  458. // Queue Manager is stopped. Queue is empty, one transaction.
  459. // Only SD_NOW should be true.
  460. EXPECT_FALSE(checkCanShutdown(SD_NORMAL));
  461. EXPECT_FALSE(checkCanShutdown(SD_DRAIN_FIRST));
  462. EXPECT_TRUE(checkCanShutdown(SD_NOW));
  463. }
  464. /// @brief Verifies that an "external" call to shutdown causes the run method
  465. /// to exit gracefully.
  466. TEST_F(D2ProcessTest, normalShutdown) {
  467. // Use an asiolink IntervalTimer and callback to generate the
  468. // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
  469. isc::asiolink::IntervalTimer timer(*getIoService());
  470. timer.setup(boost::bind(&D2ProcessTest::genShutdownCallback, this),
  471. 2 * 1000);
  472. // Record start time, and invoke run().
  473. ptime start = microsec_clock::universal_time();
  474. EXPECT_NO_THROW(run());
  475. // Record stop time.
  476. ptime stop = microsec_clock::universal_time();
  477. // Verify that duration of the run invocation is the same as the
  478. // timer duration. This demonstrates that the shutdown was driven
  479. // by an io_service event and callback.
  480. time_duration elapsed = stop - start;
  481. EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
  482. elapsed.total_milliseconds() <= 2200);
  483. }
  484. /// @brief Verifies that an "uncaught" exception thrown during event loop
  485. /// execution is treated as a fatal error.
  486. TEST_F(D2ProcessTest, fatalErrorShutdown) {
  487. // Use an asiolink IntervalTimer and callback to generate the
  488. // the exception. (Note IntervalTimer setup is in milliseconds).
  489. isc::asiolink::IntervalTimer timer(*getIoService());
  490. timer.setup(boost::bind(&D2ProcessTest::genFatalErrorCallback, this),
  491. 2 * 1000);
  492. // Record start time, and invoke run().
  493. ptime start = microsec_clock::universal_time();
  494. EXPECT_THROW(run(), DProcessBaseError);
  495. // Record stop time.
  496. ptime stop = microsec_clock::universal_time();
  497. // Verify that duration of the run invocation is the same as the
  498. // timer duration. This demonstrates that the anomaly occurred
  499. // during io callback processing.
  500. time_duration elapsed = stop - start;
  501. EXPECT_TRUE(elapsed.total_milliseconds() >= 1900 &&
  502. elapsed.total_milliseconds() <= 2200);
  503. }
  504. /// @brief Used to permit visual inspection of logs to ensure
  505. /// DHCP_DDNS_NOT_ON_LOOPBACK is issued when ip_address is not
  506. /// loopback.
  507. TEST_F(D2ProcessTest, notLoopbackTest) {
  508. const char* config = "{ "
  509. "\"ip_address\" : \"0.0.0.0\" , "
  510. "\"port\" : 53001, "
  511. "\"tsig_keys\": [],"
  512. "\"forward_ddns\" : {},"
  513. "\"reverse_ddns\" : {}"
  514. "}";
  515. // Note we don't care nor can we predict if this
  516. // succeeds or fails. The address and port may or may
  517. // not be valid on the test host.
  518. runWithConfig(config);
  519. }
  520. /// @brief Used to permit visual inspection of logs to ensure
  521. /// DHCP_DDNS_NOT_ON_LOOPBACK is not issued.
  522. TEST_F(D2ProcessTest, v4LoopbackTest) {
  523. const char* config = "{ "
  524. "\"ip_address\" : \"127.0.0.1\" , "
  525. "\"port\" : 53001, "
  526. "\"tsig_keys\": [],"
  527. "\"forward_ddns\" : {},"
  528. "\"reverse_ddns\" : {}"
  529. "}";
  530. ASSERT_TRUE(runWithConfig(config));
  531. }
  532. /// @brief Used to permit visual inspection of logs to ensure
  533. /// DHCP_DDNS_NOT_ON_LOOPBACK is not issued.
  534. TEST_F(D2ProcessTest, v6LoopbackTest) {
  535. const char* config = "{ "
  536. "\"ip_address\" : \"::1\" , "
  537. "\"port\" : 53001, "
  538. "\"tsig_keys\": [],"
  539. "\"forward_ddns\" : {},"
  540. "\"reverse_ddns\" : {}"
  541. "}";
  542. ASSERT_TRUE(runWithConfig(config));
  543. }
  544. } // end of anonymous namespace