interval_timer_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright (C) 2011 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 <gtest/gtest.h>
  16. #include <asio.hpp>
  17. #include <asiolink/asiolink.h>
  18. #include <boost/date_time/posix_time/posix_time_types.hpp>
  19. namespace {
  20. // TODO: Consider this margin
  21. const boost::posix_time::time_duration TIMER_MARGIN_MSEC =
  22. boost::posix_time::milliseconds(50);
  23. }
  24. using namespace asiolink;
  25. // This fixture is for testing IntervalTimer. Some callback functors are
  26. // registered as callback function of the timer to test if they are called
  27. // or not.
  28. class IntervalTimerTest : public ::testing::Test {
  29. protected:
  30. IntervalTimerTest() : io_service_() {}
  31. ~IntervalTimerTest() {}
  32. class TimerCallBack : public std::unary_function<void, void> {
  33. public:
  34. TimerCallBack(IntervalTimerTest* test_obj) : test_obj_(test_obj) {}
  35. void operator()() const {
  36. test_obj_->timer_called_ = true;
  37. test_obj_->io_service_.stop();
  38. return;
  39. }
  40. private:
  41. IntervalTimerTest* test_obj_;
  42. };
  43. class TimerCallBackCounter : public std::unary_function<void, void> {
  44. public:
  45. TimerCallBackCounter(IntervalTimerTest* test_obj) : test_obj_(test_obj) {
  46. counter_ = 0;
  47. }
  48. void operator()() {
  49. ++counter_;
  50. return;
  51. }
  52. int counter_;
  53. private:
  54. IntervalTimerTest* test_obj_;
  55. };
  56. class TimerCallBackCancelDeleter : public std::unary_function<void, void> {
  57. public:
  58. TimerCallBackCancelDeleter(IntervalTimerTest* test_obj,
  59. IntervalTimer* timer,
  60. TimerCallBackCounter& counter)
  61. : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0)
  62. {}
  63. void operator()() {
  64. ++count_;
  65. if (count_ == 1) {
  66. // First time of call back.
  67. // Store the value of counter_.counter_.
  68. prev_counter_ = counter_.counter_;
  69. delete timer_;
  70. } else if (count_ == 2) {
  71. // Second time of call back.
  72. // Stop io_service to stop all timers.
  73. test_obj_->io_service_.stop();
  74. // Compare the value of counter_.counter_ with stored one.
  75. // If TimerCallBackCounter was not called (expected behavior),
  76. // they are same.
  77. if (counter_.counter_ == prev_counter_) {
  78. test_obj_->timer_cancel_success_ = true;
  79. }
  80. }
  81. return;
  82. }
  83. private:
  84. IntervalTimerTest* test_obj_;
  85. IntervalTimer* timer_;
  86. TimerCallBackCounter& counter_;
  87. int count_;
  88. int prev_counter_;
  89. };
  90. class TimerCallBackCanceller {
  91. public:
  92. TimerCallBackCanceller(unsigned int& counter, IntervalTimer& itimer) :
  93. counter_(counter), itimer_(itimer)
  94. {}
  95. void operator()() {
  96. ++counter_;
  97. itimer_.cancel();
  98. }
  99. private:
  100. unsigned int& counter_;
  101. IntervalTimer& itimer_;
  102. };
  103. class TimerCallBackOverwriter : public std::unary_function<void, void> {
  104. public:
  105. TimerCallBackOverwriter(IntervalTimerTest* test_obj,
  106. IntervalTimer& timer)
  107. : test_obj_(test_obj), timer_(timer), count_(0)
  108. {}
  109. void operator()() {
  110. ++count_;
  111. if (count_ == 1) {
  112. // First time of call back.
  113. // Call setup() to update callback function to TimerCallBack.
  114. test_obj_->timer_called_ = false;
  115. timer_.setup(TimerCallBack(test_obj_), 100);
  116. } else if (count_ == 2) {
  117. // Second time of call back.
  118. // If it reaches here, re-setup() is failed (unexpected).
  119. // We should stop here.
  120. test_obj_->io_service_.stop();
  121. }
  122. return;
  123. }
  124. private:
  125. IntervalTimerTest* test_obj_;
  126. IntervalTimer& timer_;
  127. int count_;
  128. };
  129. protected:
  130. IOService io_service_;
  131. bool timer_called_;
  132. bool timer_cancel_success_;
  133. };
  134. TEST_F(IntervalTimerTest, invalidArgumentToIntervalTimer) {
  135. // Create asio_link::IntervalTimer and setup.
  136. IntervalTimer itimer(io_service_);
  137. // expect throw if call back function is empty
  138. EXPECT_THROW(itimer.setup(IntervalTimer::Callback(), 1),
  139. isc::InvalidParameter);
  140. // expect throw if interval is not greater than 0
  141. EXPECT_THROW(itimer.setup(TimerCallBack(this), 0), isc::BadValue);
  142. EXPECT_THROW(itimer.setup(TimerCallBack(this), -1), isc::BadValue);
  143. }
  144. TEST_F(IntervalTimerTest, startIntervalTimer) {
  145. // Create asio_link::IntervalTimer and setup.
  146. // Then run IOService and test if the callback function is called.
  147. IntervalTimer itimer(io_service_);
  148. timer_called_ = false;
  149. // store start time
  150. boost::posix_time::ptime start;
  151. start = boost::posix_time::microsec_clock::universal_time();
  152. // setup timer
  153. itimer.setup(TimerCallBack(this), 100);
  154. EXPECT_EQ(100, itimer.getInterval());
  155. io_service_.run();
  156. // reaches here after timer expired
  157. // delta: difference between elapsed time and 100 milliseconds.
  158. boost::posix_time::time_duration delta =
  159. (boost::posix_time::microsec_clock::universal_time() - start)
  160. - boost::posix_time::millisec(100);
  161. if (delta.is_negative()) {
  162. delta.invert_sign();
  163. }
  164. // expect TimerCallBack is called; timer_called_ is true
  165. EXPECT_TRUE(timer_called_);
  166. // expect interval is 100 milliseconds +/- TIMER_MARGIN_MSEC.
  167. EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
  168. }
  169. TEST_F(IntervalTimerTest, destructIntervalTimer) {
  170. // This code isn't exception safe, but we'd rather keep the code
  171. // simpler and more readable as this is only for tests and if it throws
  172. // the program would immediately terminate anyway.
  173. // The call back function will not be called after the timer is
  174. // destroyed.
  175. //
  176. // There are two timers:
  177. // itimer_counter (A)
  178. // (Calls TimerCallBackCounter)
  179. // - increments internal counter in callback function
  180. // itimer_canceller (B)
  181. // (Calls TimerCallBackCancelDeleter)
  182. // - first time of callback, it stores the counter value of
  183. // callback_canceller and destroys itimer_counter
  184. // - second time of callback, it compares the counter value of
  185. // callback_canceller with stored value
  186. // if they are same the timer was not called; expected result
  187. // if they are different the timer was called after destroyed
  188. //
  189. // 0 100 200 300 400 500 600 (ms)
  190. // (A) i--------+----x
  191. // ^
  192. // |destroy itimer_counter
  193. // (B) i-------------+--------------s
  194. // ^stop io_service
  195. // and check if itimer_counter have been
  196. // stopped
  197. // itimer_counter will be deleted in TimerCallBackCancelDeleter
  198. IntervalTimer* itimer_counter = new IntervalTimer(io_service_);
  199. IntervalTimer itimer_canceller(io_service_);
  200. timer_cancel_success_ = false;
  201. TimerCallBackCounter callback_canceller(this);
  202. itimer_counter->setup(callback_canceller, 200);
  203. itimer_canceller.setup(
  204. TimerCallBackCancelDeleter(this, itimer_counter, callback_canceller),
  205. 300);
  206. io_service_.run();
  207. EXPECT_TRUE(timer_cancel_success_);
  208. }
  209. TEST_F(IntervalTimerTest, cancel) {
  210. // Similar to destructIntervalTimer test, but the first timer explicitly
  211. // cancels itself on first callback.
  212. IntervalTimer itimer_counter(io_service_);
  213. IntervalTimer itimer_watcher(io_service_);
  214. unsigned int counter = 0;
  215. itimer_counter.setup(TimerCallBackCanceller(counter, itimer_counter), 100);
  216. itimer_watcher.setup(TimerCallBack(this), 200);
  217. io_service_.run();
  218. EXPECT_EQ(1, counter);
  219. EXPECT_EQ(0, itimer_counter.getInterval());
  220. // canceling an already canceled timer shouldn't cause any surprise.
  221. EXPECT_NO_THROW(itimer_counter.cancel());
  222. }
  223. TEST_F(IntervalTimerTest, overwriteIntervalTimer) {
  224. // Calling setup() multiple times updates call back function and interval.
  225. //
  226. // There are two timers:
  227. // itimer (A)
  228. // (Calls TimerCallBackCounter / TimerCallBack)
  229. // - increments internal counter in callback function
  230. // (TimerCallBackCounter)
  231. // interval: 300 milliseconds
  232. // - io_service_.stop() (TimerCallBack)
  233. // interval: 100 milliseconds
  234. // itimer_overwriter (B)
  235. // (Calls TimerCallBackOverwriter)
  236. // - first time of callback, it calls setup() to change call back
  237. // function to TimerCallBack and interval of itimer to 100
  238. // milliseconds
  239. // after 300 + 100 milliseconds from the beginning of this test,
  240. // TimerCallBack() will be called and io_service_ stops.
  241. // - second time of callback, it means the test fails.
  242. //
  243. // 0 100 200 300 400 500 600 700 800 (ms)
  244. // (A) i-------------+----C----s
  245. // ^ ^stop io_service
  246. // |change call back function
  247. // (B) i------------------+-------------------S
  248. // ^(stop io_service on fail)
  249. //
  250. IntervalTimer itimer(io_service_);
  251. IntervalTimer itimer_overwriter(io_service_);
  252. // store start time
  253. boost::posix_time::ptime start;
  254. start = boost::posix_time::microsec_clock::universal_time();
  255. itimer.setup(TimerCallBackCounter(this), 300);
  256. itimer_overwriter.setup(TimerCallBackOverwriter(this, itimer), 400);
  257. io_service_.run();
  258. // reaches here after timer expired
  259. // if interval is updated, it takes
  260. // 400 milliseconds for TimerCallBackOverwriter
  261. // + 100 milliseconds for TimerCallBack (stop)
  262. // = 500 milliseconds.
  263. // otherwise (test fails), it takes
  264. // 400 milliseconds for TimerCallBackOverwriter
  265. // + 400 milliseconds for TimerCallBackOverwriter (stop)
  266. // = 800 milliseconds.
  267. // delta: difference between elapsed time and 400 + 100 milliseconds
  268. boost::posix_time::time_duration delta =
  269. (boost::posix_time::microsec_clock::universal_time() - start)
  270. - boost::posix_time::millisec(400 + 100);
  271. if (delta.is_negative()) {
  272. delta.invert_sign();
  273. }
  274. // expect callback function is updated: TimerCallBack is called
  275. EXPECT_TRUE(timer_called_);
  276. // expect interval is updated
  277. EXPECT_TRUE(delta < TIMER_MARGIN_MSEC);
  278. }