timer_mgr_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // Copyright (C) 2016-2017 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 <asiolink/interval_timer.h>
  9. #include <asiolink/io_service.h>
  10. #include <dhcpsrv/timer_mgr.h>
  11. #include <exceptions/exceptions.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 Pointer to IO service used by the tests.
  75. IOServicePtr io_service_;
  76. /// @brief Holds the calls count for test timers.
  77. ///
  78. /// The key of this map holds the timer names. The value holds the number
  79. /// of calls to the timer handlers.
  80. CallsCount calls_count_;
  81. /// @brief Instance of @c TimerMgr used by the tests.
  82. TimerMgrPtr timer_mgr_;
  83. };
  84. void
  85. TimerMgrTest::SetUp() {
  86. io_service_.reset(new IOService());
  87. timer_mgr_ = TimerMgr::instance();
  88. timer_mgr_->setIOService(io_service_);
  89. calls_count_.clear();
  90. }
  91. void
  92. TimerMgrTest::TearDown() {
  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. IntervalTimer timer(*io_service_);
  110. timer.setup([this]() {
  111. io_service_->stop();
  112. }, timeout, IntervalTimer::ONE_SHOT);
  113. io_service_->run();
  114. io_service_->get_io_service().reset();
  115. }
  116. void
  117. TimerMgrTest::timerCallback(const std::string& timer_name) {
  118. // Accumulate the number of calls to the timer handler.
  119. ++calls_count_[timer_name];
  120. // The timer installed is the ONE_SHOT timer, so we have
  121. // to reschedule the timer.
  122. timer_mgr_->setup(timer_name);
  123. }
  124. void
  125. TimerMgrTest::timerCallbackWithException() {
  126. isc_throw(Exception, "timerCallbackWithException");
  127. }
  128. boost::function<void ()>
  129. TimerMgrTest::makeCallback(const std::string& timer_name) {
  130. return (boost::bind(&TimerMgrTest::timerCallback, this, timer_name));
  131. }
  132. boost::function<void ()>
  133. TimerMgrTest::makeCallbackWithException() {
  134. return (boost::bind(&TimerMgrTest::timerCallbackWithException, this));
  135. }
  136. // This test checks that certain errors are returned when invalid
  137. // parameters are specified when registering a timer, or when
  138. // the registration can't be made.
  139. TEST_F(TimerMgrTest, registerTimer) {
  140. // Empty timer name is not allowed.
  141. ASSERT_THROW(timer_mgr_->registerTimer("", makeCallback("timer1"), 1,
  142. IntervalTimer::ONE_SHOT),
  143. BadValue);
  144. // Add a timer with a correct name.
  145. ASSERT_NO_THROW(timer_mgr_->registerTimer("timer2", makeCallback("timer2"), 1,
  146. IntervalTimer::ONE_SHOT));
  147. // Adding the timer with the same name as the existing timer is not
  148. // allowed.
  149. ASSERT_THROW(timer_mgr_->registerTimer("timer2", makeCallback("timer2"), 1,
  150. IntervalTimer::ONE_SHOT),
  151. BadValue);
  152. }
  153. // This test verifies that it is possible to unregister a timer from
  154. // the TimerMgr.
  155. TEST_F(TimerMgrTest, unregisterTimer) {
  156. // Register a timer and start it.
  157. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1));
  158. ASSERT_EQ(1, timer_mgr_->timersCount());
  159. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  160. // Wait for the timer to execute several times.
  161. doWait(100);
  162. // Remember how many times the timer's callback was executed.
  163. const unsigned int calls_count = calls_count_["timer1"];
  164. ASSERT_GT(calls_count, 0);
  165. // Check that an attempt to unregister a non-existing timer would
  166. // result in exception.
  167. ASSERT_THROW(timer_mgr_->unregisterTimer("timer2"), BadValue);
  168. // Number of timers shouldn't have changed.
  169. ASSERT_EQ(1, timer_mgr_->timersCount());
  170. // Now unregister the correct one.
  171. ASSERT_NO_THROW(timer_mgr_->unregisterTimer("timer1"));
  172. ASSERT_EQ(0, timer_mgr_->timersCount());
  173. doWait(100);
  174. // The number of calls for the timer1 shouldn't change as the
  175. // timer had been unregistered.
  176. EXPECT_EQ(calls_count_["timer1"], calls_count);
  177. }
  178. // This test verifies taht it is possible to unregister all timers.
  179. TEST_F(TimerMgrTest, unregisterTimers) {
  180. // Register 10 timers.
  181. for (int i = 1; i <= 20; ++i) {
  182. std::ostringstream s;
  183. s << "timer" << i;
  184. ASSERT_NO_FATAL_FAILURE(registerTimer(s.str(), 1))
  185. << "fatal failure occurred while registering "
  186. << s.str();
  187. ASSERT_EQ(i, timer_mgr_->timersCount())
  188. << "invalid number of registered timers returned";
  189. ASSERT_NO_THROW(timer_mgr_->setup(s.str()))
  190. << "exception thrown while calling setup() for the "
  191. << s.str();
  192. }
  193. doWait(500);
  194. // Make sure that all timers have been executed at least once.
  195. for (CallsCount::iterator it = calls_count_.begin();
  196. it != calls_count_.end(); ++it) {
  197. unsigned int calls_count = it->second;
  198. ASSERT_GT(calls_count, 0)
  199. << "expected calls counter for timer"
  200. << (std::distance(calls_count_.begin(), it) + 1)
  201. << " greater than 0";
  202. }
  203. // Copy counters for all timers.
  204. CallsCount calls_count(calls_count_);
  205. // Let's unregister all timers.
  206. ASSERT_NO_THROW(timer_mgr_->unregisterTimers());
  207. // Make sure there are no timers registered.
  208. ASSERT_EQ(0, timer_mgr_->timersCount());
  209. doWait(500);
  210. // The calls counter shouldn't change because there are
  211. // no timers registered.
  212. EXPECT_TRUE(calls_count == calls_count_);
  213. }
  214. // This test verifies that the timer execution can be cancelled.
  215. TEST_F(TimerMgrTest, cancel) {
  216. // Register timer.
  217. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 1));
  218. // Kick in the timer and wait for 500ms.
  219. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  220. doWait(500);
  221. // Cancelling non-existing timer should fail.
  222. EXPECT_THROW(timer_mgr_->cancel("timer2"), BadValue);
  223. // Cancelling the good one should pass, even when the worker
  224. // thread is running.
  225. ASSERT_NO_THROW(timer_mgr_->cancel("timer1"));
  226. // Remember how many calls have been invoked and wait for
  227. // another 500ms.
  228. unsigned int calls_count = calls_count_["timer1"];
  229. doWait(500);
  230. // The number of calls shouldn't change because the timer had been
  231. // cancelled.
  232. ASSERT_EQ(calls_count, calls_count_["timer1"]);
  233. // Setup the timer again.
  234. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  235. // Restart the thread.
  236. doWait(500);
  237. // New calls should be recorded.
  238. EXPECT_GT(calls_count_["timer1"], calls_count);
  239. }
  240. // This test verifies that the callbacks for the scheduled timers are
  241. // actually called.
  242. TEST_F(TimerMgrTest, scheduleTimers) {
  243. // Register two timers: 'timer1' and 'timer2'. The first timer will
  244. // be executed at the 50ms interval. The second one at the 100ms
  245. // interval.
  246. ASSERT_NO_FATAL_FAILURE(registerTimer("timer1", 50));
  247. ASSERT_NO_FATAL_FAILURE(registerTimer("timer2", 100));
  248. // Kick in the timers.
  249. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  250. ASSERT_NO_THROW(timer_mgr_->setup("timer2"));
  251. // Run IfaceMgr::receive6() in the loop for 1000ms. This function
  252. // will read data from the watch sockets created when the timers
  253. // were registered. The data is delivered to the watch sockets
  254. // at the interval of the timers, which should break the blocking
  255. // call to receive6(). As a result, the callbacks associated
  256. // with the watch sockets should be called.
  257. doWait(1000);
  258. // We have been running the timer for 1000ms at the interval of
  259. // 50ms. The maximum number of callbacks is 20. However, the
  260. // callback itself takes time. Stopping the thread takes time.
  261. // So, the real number differs significantly. We don't know
  262. // exactly how many have been executed. It should be more
  263. // than 10 for sure. But we really made up the numbers here.
  264. EXPECT_GT(calls_count_["timer1"], 10);
  265. // For the second timer it should be more than 5.
  266. EXPECT_GT(calls_count_["timer2"], 5);
  267. // Because the interval of the 'timer1' is lower than the
  268. // interval of the 'timer2' the number of calls should
  269. // be higher for the 'timer1'.
  270. EXPECT_GT(calls_count_["timer1"], calls_count_["timer2"]);
  271. // Remember the number of calls from 'timer1' and 'timer2'.
  272. unsigned int calls_count_timer1 = calls_count_["timer1"];
  273. unsigned int calls_count_timer2 = calls_count_["timer2"];
  274. // Unregister the 'timer1'.
  275. ASSERT_NO_THROW(timer_mgr_->unregisterTimer("timer1"));
  276. // Wait another 500ms. The 'timer1' was unregistered so it
  277. // should not make any more calls. The 'timer2' should still
  278. // work as previously.
  279. doWait(500);
  280. // The number of calls shouldn't have changed.
  281. EXPECT_EQ(calls_count_timer1, calls_count_["timer1"]);
  282. // There should be some new calls registered for the 'timer2'.
  283. EXPECT_GT(calls_count_["timer2"], calls_count_timer2);
  284. }
  285. // This test verifies that exceptions emitted from the callback would
  286. // be handled by the TimerMgr.
  287. TEST_F(TimerMgrTest, callbackWithException) {
  288. // Create timer which will trigger callback generating exception.
  289. ASSERT_NO_THROW(
  290. timer_mgr_->registerTimer("timer1", makeCallbackWithException(), 1,
  291. IntervalTimer::ONE_SHOT)
  292. );
  293. // Setup the timer.
  294. ASSERT_NO_THROW(timer_mgr_->setup("timer1"));
  295. // Start thread. We hope that exception will be caught by the @c TimerMgr
  296. // and will not kill the process.
  297. doWait(500);
  298. }
  299. // This test verifies that IO service specified for the TimerMgr
  300. // must not be null.
  301. TEST_F(TimerMgrTest, setIOService) {
  302. EXPECT_THROW(timer_mgr_->setIOService(IOServicePtr()),
  303. BadValue);
  304. }
  305. } // end of anonymous namespace