d2_process_unittests.cc 25 KB

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