interval_timer_unittest.cc 11 KB

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