timer_mgr_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. // Copyright (C) 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/asio_wrapper.h>
  8. #include <dhcp/iface_mgr.h>
  9. #include <dhcpsrv/timer_mgr.h>
  10. #include <exceptions/exceptions.h>
  11. #include <util/stopwatch.h>
  12. #include <boost/bind.hpp>
  13. #include <gtest/gtest.h>
  14. #include <sstream>
  15. #include <unistd.h>
  16. using namespace isc;
  17. using namespace isc::dhcp;
  18. using namespace isc::asiolink;
  19. namespace {
  20. /// @brief Test fixture class for @c TimerMgr.
  21. class TimerMgrTest : public ::testing::Test {
  22. private:
  23. /// @brief Prepares the class for a test.
  24. virtual void SetUp();
  25. /// @brief Cleans up after the test.
  26. virtual void TearDown();
  27. public:
  28. /// @brief Wrapper method for registering a new timer.
  29. ///
  30. /// This method registers a new timer in the @c TimerMgr. It associates a
  31. /// @c timerCallback method with a timer. This method registers a number of
  32. /// calls to the particular timer in the @c calls_count_ map.
  33. ///
  34. /// @param timer_name Unique timer name.
  35. /// @param timer_interval Timer interval.
  36. /// @param mode Interval timer mode, which defaults to
  37. /// @c IntervalTimer::ONE_SHOT.
  38. void registerTimer(const std::string& timer_name, const long timer_interval,
  39. const IntervalTimer::Mode& timer_mode = IntervalTimer::ONE_SHOT);
  40. /// @brief Wait for one or many ready handlers.
  41. ///
  42. /// @param timeout Wait timeout in milliseconds.
  43. /// @param call_receive Indicates if the @c IfaceMgr::receive6
  44. /// should be called to run pending callbacks and clear
  45. /// watch sockets.
  46. void doWait(const long timeout, const bool call_receive = true);
  47. /// @brief Generic callback for timers under test.
  48. ///
  49. /// This callback increases the calls count for specified timer name.
  50. ///
  51. /// @param timer_name Name of the timer for which callback counter should
  52. /// be increased.
  53. void timerCallback(const std::string& timer_name);
  54. /// @brief Callback which generates exception.
  55. ///
  56. /// This callback is used to test that the @c TimerMgr can handle
  57. /// the case when the callback generates exceptions.
  58. void timerCallbackWithException();
  59. /// @brief Create a generic callback function for the timer.
  60. ///
  61. /// This is just a wrapped to make it a bit more convenient
  62. /// in the test.
  63. boost::function<void ()> makeCallback(const std::string& timer_name);
  64. /// @brief Create a callback which generates exception.
  65. boost::function<void ()> makeCallbackWithException();
  66. /// @brief Callback for timeout.
  67. ///
  68. /// This callback indicates the test timeout by setting the
  69. /// @c timeout_ member.
  70. void timeoutCallback();
  71. /// @brief Type definition for a map holding calls counters for
  72. /// timers.
  73. typedef std::map<std::string, unsigned int> CallsCount;
  74. /// @brief Holds the calls count for test timers.
  75. ///
  76. /// The key of this map holds the timer names. The value holds the number
  77. /// of calls to the timer handlers.
  78. CallsCount calls_count_;
  79. /// @brief Instance of @c TimerMgr used by the tests.
  80. TimerMgrPtr timer_mgr_;
  81. };
  82. void
  83. TimerMgrTest::SetUp() {
  84. timer_mgr_ = TimerMgr::instance();
  85. calls_count_.clear();
  86. // Make sure there are no dangling threads.
  87. timer_mgr_->stopThread();
  88. }
  89. void
  90. TimerMgrTest::TearDown() {
  91. // Make sure there are no dangling threads.
  92. timer_mgr_->stopThread();
  93. // Remove all timers.
  94. timer_mgr_->unregisterTimers();
  95. }
  96. void
  97. TimerMgrTest::registerTimer(const std::string& timer_name, const long timer_interval,
  98. const IntervalTimer::Mode& timer_mode) {
  99. // Register the timer with the generic callback that counts the
  100. // number of callback invocations.
  101. ASSERT_NO_THROW(
  102. timer_mgr_->registerTimer(timer_name, makeCallback(timer_name), timer_interval,
  103. timer_mode)
  104. );
  105. calls_count_[timer_name] = 0;
  106. }
  107. void
  108. TimerMgrTest::doWait(const long timeout, const bool call_receive) {
  109. util::Stopwatch stopwatch;
  110. while (stopwatch.getTotalMilliseconds() < timeout) {
  111. if (call_receive) {
  112. // Block for one 1 millisecond.
  113. IfaceMgr::instancePtr()->receive6(0, 1000);
  114. }
  115. }
  116. }
  117. void
  118. TimerMgrTest::timerCallback(const std::string& timer_name) {
  119. // Accumulate the number of calls to the timer handler.
  120. ++calls_count_[timer_name];
  121. // The timer installed is the ONE_SHOT timer, so we have
  122. // to reschedule the timer.
  123. timer_mgr_->setup(timer_name);
  124. }
  125. void
  126. TimerMgrTest::timerCallbackWithException() {
  127. isc_throw(Exception, "timerCallbackWithException");
  128. }
  129. boost::function<void ()>
  130. TimerMgrTest::makeCallback(const std::string& timer_name) {
  131. return (boost::bind(&TimerMgrTest::timerCallback, this, timer_name));
  132. }
  133. boost::function<void ()>
  134. TimerMgrTest::makeCallbackWithException() {
  135. return (boost::bind(&TimerMgrTest::timerCallbackWithException, this));
  136. }
  137. // This test checks that certain errors are returned when invalid
  138. // parameters are specified when registering a timer, or when
  139. // the registration can't be made.
  140. TEST_F(TimerMgrTest, registerTimer) {
  141. // Empty timer name is not allowed.
  142. ASSERT_THROW(timer_mgr_->registerTimer("", makeCallback("timer1"), 1,
  143. IntervalTimer::ONE_SHOT),
  144. BadValue);
  145. // Add a timer with a correct name.
  146. ASSERT_NO_THROW(timer_mgr_->registerTimer("timer2", makeCallback("timer2"), 1,
  147. IntervalTimer::ONE_SHOT));
  148. // Adding the timer with the same name as the existing timer is not
  149. // allowed.
  150. ASSERT_THROW(timer_mgr_->registerTimer("timer2", makeCallback("timer2"), 1,
  151. IntervalTimer::ONE_SHOT),
  152. BadValue);
  153. // Start worker thread.
  154. ASSERT_NO_THROW(timer_mgr_->startThread());
  155. // Can't register the timer when the thread is running.
  156. ASSERT_THROW(timer_mgr_->registerTimer("timer1", makeCallback("timer1"), 1,
  157. IntervalTimer::ONE_SHOT),
  158. InvalidOperation);
  159. // Stop the thread and retry.
  160. ASSERT_NO_THROW(timer_mgr_->stopThread());
  161. EXPECT_NO_THROW(timer_mgr_->registerTimer("timer1", makeCallback("timer1"), 1,
  162. IntervalTimer::ONE_SHOT));
  163. }
  164. // This test verifies that it is possible to unregister a timer from
  165. // the TimerMgr.
  166. TEST_F(TimerMgrTest, unregisterTimer) {
  167. // Register a timer and start it.
  168. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1));
  169. ASSERT_EQ(1, timer_mgr_->timersCount());
  170. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  171. ASSERT_NO_THROW(timer_mgr_->startThread());
  172. // Wait for the timer to execute several times.
  173. doWait(100);
  174. // Stop the thread but execute pending callbacks.
  175. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  176. // Remember how many times the timer's callback was executed.
  177. const unsigned int calls_count = calls_count_["timer1"];
  178. ASSERT_GT(calls_count, 0);
  179. // Check that an attempt to unregister a non-existing timer would
  180. // result in exeception.
  181. ASSERT_THROW(timer_mgr_->unregisterTimer("timer2"), BadValue);
  182. // Number of timers shouldn't have changed.
  183. ASSERT_EQ(1, timer_mgr_->timersCount());
  184. // Now unregister the correct one.
  185. ASSERT_NO_THROW(timer_mgr_->unregisterTimer("timer1"));
  186. ASSERT_EQ(0, timer_mgr_->timersCount());
  187. // Start the thread again and wait another 100ms.
  188. ASSERT_NO_THROW(timer_mgr_->startThread());
  189. doWait(100);
  190. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  191. // The number of calls for the timer1 shouldn't change as the
  192. // timer had been unregistered.
  193. EXPECT_EQ(calls_count_["timer1"], calls_count);
  194. }
  195. // This test verifies taht it is possible to unregister all timers.
  196. TEST_F(TimerMgrTest, unregisterTimers) {
  197. // Register 10 timers.
  198. for (int i = 1; i <= 20; ++i) {
  199. std::ostringstream s;
  200. s << "timer" << i;
  201. ASSERT_NO_FATAL_FAILURE(registerTimer(s.str(), 1))
  202. << "fatal failure occurred while registering "
  203. << s.str();
  204. ASSERT_EQ(i, timer_mgr_->timersCount())
  205. << "invalid number of registered timers returned";
  206. ASSERT_NO_THROW(timer_mgr_->setup(s.str()))
  207. << "exception thrown while calling setup() for the "
  208. << s.str();
  209. }
  210. // Start worker thread and wait for 500ms.
  211. ASSERT_NO_THROW(timer_mgr_->startThread());
  212. doWait(500);
  213. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  214. // Make sure that all timers have been executed at least once.
  215. for (CallsCount::iterator it = calls_count_.begin();
  216. it != calls_count_.end(); ++it) {
  217. unsigned int calls_count = it->second;
  218. ASSERT_GT(calls_count, 0)
  219. << "expected calls counter for timer"
  220. << (std::distance(calls_count_.begin(), it) + 1)
  221. << " greater than 0";
  222. }
  223. // Copy counters for all timers.
  224. CallsCount calls_count(calls_count_);
  225. // Let's unregister all timers.
  226. ASSERT_NO_THROW(timer_mgr_->unregisterTimers());
  227. // Make sure there are no timers registered.
  228. ASSERT_EQ(0, timer_mgr_->timersCount());
  229. // Start worker thread again and wait for 500ms.
  230. ASSERT_NO_THROW(timer_mgr_->startThread());
  231. doWait(500);
  232. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  233. // The calls counter shouldn't change because there are
  234. // no timers registered.
  235. EXPECT_TRUE(calls_count == calls_count_);
  236. }
  237. // This test checks that it is not possible to unregister timers
  238. // while the thread is running.
  239. TEST_F(TimerMgrTest, unregisterTimerWhileRunning) {
  240. // Register two timers.
  241. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1));
  242. ASSERT_NO_FATAL_FAILURE(registerTimer("timer2", 1));
  243. // Start the thread and make sure we can't unregister them.
  244. ASSERT_NO_THROW(timer_mgr_->startThread());
  245. EXPECT_THROW(timer_mgr_->unregisterTimer("timer1"), InvalidOperation);
  246. EXPECT_THROW(timer_mgr_->unregisterTimers(), InvalidOperation);
  247. // No need to stop the thread as it will be stopped by the
  248. // test fixture destructor.
  249. }
  250. // This test verifies that the timer execution can be cancelled.
  251. TEST_F(TimerMgrTest, cancel) {
  252. // Register timer.
  253. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1));
  254. // Kick in the timer and wait for 500ms.
  255. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  256. ASSERT_NO_THROW(timer_mgr_->startThread());
  257. doWait(500);
  258. ASSERT_NO_THROW(timer_mgr_->stopThread());
  259. // Cancelling non-existing timer should fail.
  260. EXPECT_THROW(timer_mgr_->cancel("timer2"), BadValue);
  261. // Cancelling the good one should pass, even when the worker
  262. // thread is running.
  263. ASSERT_NO_THROW(timer_mgr_->cancel("timer1"));
  264. // Remember how many calls have been invoked and wait for
  265. // another 500ms.
  266. unsigned int calls_count = calls_count_["timer1"];
  267. ASSERT_NO_THROW(timer_mgr_->startThread());
  268. doWait(500);
  269. // Stop thread before we setup again.
  270. ASSERT_NO_THROW(timer_mgr_->stopThread());
  271. // The number of calls shouldn't change because the timer had been
  272. // cancelled.
  273. ASSERT_EQ(calls_count, calls_count_["timer1"]);
  274. // Setup the timer again.
  275. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  276. // Restart the thread.
  277. ASSERT_NO_THROW(timer_mgr_->startThread());
  278. doWait(500);
  279. // New calls should be recorded.
  280. EXPECT_GT(calls_count_["timer1"], calls_count);
  281. }
  282. // This test verifies that the callbacks for the scheduled timers are
  283. // actually called.
  284. TEST_F(TimerMgrTest, scheduleTimers) {
  285. // Register two timers: 'timer1' and 'timer2'. The first timer will
  286. // be executed at the 50ms interval. The second one at the 100ms
  287. // interval.
  288. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 50));
  289. ASSERT_NO_FATAL_FAILURE(registerTimer("timer2", 100));
  290. // Kick in the timers.
  291. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  292. ASSERT_NO_THROW(timer_mgr_->setup("timer2"));
  293. // We can start the worker thread before we even kick in the timers.
  294. ASSERT_NO_THROW(timer_mgr_->startThread());
  295. // Run IfaceMgr::receive6() in the loop for 1000ms. This function
  296. // will read data from the watch sockets created when the timers
  297. // were registered. The data is delivered to the watch sockets
  298. // at the interval of the timers, which should break the blocking
  299. // call to receive6(). As a result, the callbacks associated
  300. // with the watch sockets should be called.
  301. doWait(1000);
  302. // Stop the worker thread, which would halt the execution of
  303. // the timers.
  304. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  305. // We have been running the timer for 1000ms at the interval of
  306. // 50ms. The maximum number of callbacks is 20. However, the
  307. // callback itself takes time. Stoping the thread takes time.
  308. // So, the real number differs significantly. We don't know
  309. // exactly how many have been executed. It should be more
  310. // than 10 for sure. But we really made up the numbers here.
  311. EXPECT_GT(calls_count_["timer1"], 10);
  312. // For the second timer it should be more than 5.
  313. EXPECT_GT(calls_count_["timer2"], 5);
  314. // Because the interval of the 'timer1' is lower than the
  315. // interval of the 'timer2' the number of calls should
  316. // be higher for the 'timer1'.
  317. EXPECT_GT(calls_count_["timer1"], calls_count_["timer2"]);
  318. // Remember the number of calls from 'timer1' and 'timer2'.
  319. unsigned int calls_count_timer1 = calls_count_["timer1"];
  320. unsigned int calls_count_timer2 = calls_count_["timer2"];
  321. // Unregister the 'timer1'.
  322. ASSERT_NO_THROW(timer_mgr_->unregisterTimer("timer1"));
  323. // Restart the thread.
  324. ASSERT_NO_THROW(timer_mgr_->startThread());
  325. // Wait another 500ms. The 'timer1' was unregistered so it
  326. // should not make any more calls. The 'timer2' should still
  327. // work as previously.
  328. doWait(500);
  329. // The number of calls shouldn't have changed.
  330. EXPECT_EQ(calls_count_timer1, calls_count_["timer1"]);
  331. // There should be some new calls registered for the 'timer2'.
  332. EXPECT_GT(calls_count_["timer2"], calls_count_timer2);
  333. }
  334. // This test verifies that it is possible to force that the pending
  335. // timer callbacks are executed when the worker thread is stopped.
  336. TEST_F(TimerMgrTest, stopThreadWithRunningHandlers) {
  337. // Register 'timer1'.
  338. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1));
  339. // Kick in the timer.
  340. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  341. ASSERT_NO_THROW(timer_mgr_->startThread());
  342. // Run the thread for 100ms. This should run some timers. The 'false'
  343. // value indicates that the IfaceMgr::receive6 is not called, so the
  344. // watch socket is never cleared.
  345. doWait(100, false);
  346. // There should be no calls registered for the timer1.
  347. EXPECT_EQ(0, calls_count_["timer1"]);
  348. // Stop the worker thread without completing pending callbacks.
  349. ASSERT_NO_THROW(timer_mgr_->stopThread(false));
  350. // There should be still not be any calls registered.
  351. EXPECT_EQ(0, calls_count_["timer1"]);
  352. // We can restart the worker thread before we even kick in the timers.
  353. ASSERT_NO_THROW(timer_mgr_->startThread());
  354. // Run the thread for 100ms. This should run some timers. The 'false'
  355. // value indicates that the IfaceMgr::receive6 is not called, so the
  356. // watch socket is never cleared.
  357. doWait(100, false);
  358. // There should be no calls registered for the timer1.
  359. EXPECT_EQ(0, calls_count_["timer1"]);
  360. // Stop the worker thread with completing pending callbacks.
  361. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  362. // There should be one call registered.
  363. EXPECT_EQ(1, calls_count_["timer1"]);
  364. }
  365. // This test verifies that exceptions emitted from the callback would
  366. // be handled by the TimerMgr.
  367. TEST_F(TimerMgrTest, callbackWithException) {
  368. // Create timer which will trigger callback generating exception.
  369. ASSERT_NO_THROW(
  370. timer_mgr_->registerTimer("timer1", makeCallbackWithException(), 1,
  371. IntervalTimer::ONE_SHOT)
  372. );
  373. // Setup the timer.
  374. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  375. // Start thread. We hope that exception will be caught by the @c TimerMgr
  376. // and will not kill the process.
  377. ASSERT_NO_THROW(timer_mgr_->startThread());
  378. doWait(500);
  379. ASSERT_NO_THROW(timer_mgr_->stopThread(true));
  380. }
  381. } // end of anonymous namespace