asio_link_unittest.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. // Copyright (C) 2010 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. // $Id$
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netdb.h>
  18. #include <stdint.h>
  19. #include <functional>
  20. #include <string>
  21. #include <vector>
  22. #include <gtest/gtest.h>
  23. #include <exceptions/exceptions.h>
  24. #include <dns/tests/unittest_util.h>
  25. #include <auth/asio_link.h>
  26. #include <boost/date_time/posix_time/posix_time_types.hpp>
  27. using isc::UnitTestUtil;
  28. using namespace std;
  29. using namespace asio_link;
  30. namespace {
  31. const char* const TEST_PORT = "53535";
  32. const char* const TEST_IPV6_ADDR = "::1";
  33. const char* const TEST_IPV4_ADDR = "127.0.0.1";
  34. // This data is intended to be valid as a DNS/TCP-like message: the first
  35. // two octets encode the length of the rest of the data. This is crucial
  36. // for the tests below.
  37. const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
  38. // TODO: Consider this mergin
  39. const boost::posix_time::time_duration TIMER_MERGIN_MSEC =
  40. boost::posix_time::milliseconds(50);
  41. TEST(IOAddressTest, fromText) {
  42. IOAddress io_address_v4("192.0.2.1");
  43. EXPECT_EQ("192.0.2.1", io_address_v4.toText());
  44. IOAddress io_address_v6("2001:db8::1234");
  45. EXPECT_EQ("2001:db8::1234", io_address_v6.toText());
  46. // bogus IPv4 address-like input
  47. EXPECT_THROW(IOAddress("192.0.2.2.1"), IOError);
  48. // bogus IPv6 address-like input
  49. EXPECT_THROW(IOAddress("2001:db8:::1234"), IOError);
  50. }
  51. TEST(IOEndpointTest, create) {
  52. const IOEndpoint* ep;
  53. ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5300);
  54. EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
  55. delete ep;
  56. ep = IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5300);
  57. EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
  58. delete ep;
  59. ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5300);
  60. EXPECT_EQ("2001:db8::1234", ep->getAddress().toText());
  61. delete ep;
  62. ep = IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5300);
  63. EXPECT_EQ("2001:db8::1234", ep->getAddress().toText());
  64. delete ep;
  65. EXPECT_THROW(IOEndpoint::create(IPPROTO_IP, IOAddress("192.0.2.1"),
  66. 5300)->getAddress().toText(),
  67. IOError);
  68. }
  69. TEST(IOSocketTest, dummySockets) {
  70. EXPECT_EQ(IPPROTO_UDP, IOSocket::getDummyUDPSocket().getProtocol());
  71. EXPECT_EQ(IPPROTO_TCP, IOSocket::getDummyTCPSocket().getProtocol());
  72. EXPECT_EQ(-1, IOSocket::getDummyUDPSocket().getNative());
  73. EXPECT_EQ(-1, IOSocket::getDummyTCPSocket().getNative());
  74. }
  75. TEST(IOServiceTest, badPort) {
  76. EXPECT_THROW(IOService(NULL, *"65536", true, false), IOError);
  77. EXPECT_THROW(IOService(NULL, *"5300.0", true, false), IOError);
  78. EXPECT_THROW(IOService(NULL, *"-1", true, false), IOError);
  79. EXPECT_THROW(IOService(NULL, *"domain", true, false), IOError);
  80. }
  81. TEST(IOServiceTest, badAddress) {
  82. EXPECT_THROW(IOService(NULL, *TEST_PORT, *"192.0.2.1.1"),
  83. IOError);
  84. EXPECT_THROW(IOService(NULL, *TEST_PORT, *"2001:db8:::1"),
  85. IOError);
  86. EXPECT_THROW(IOService(NULL, *TEST_PORT, *"localhost"),
  87. IOError);
  88. }
  89. TEST(IOServiceTest, unavailableAddress) {
  90. // These addresses should generally be unavailable as a valid local
  91. // address, although there's no guarantee in theory.
  92. EXPECT_THROW(IOService(NULL, *TEST_PORT, *"255.255.0.0"), IOError);
  93. // Some OSes would simply reject binding attempt for an AF_INET6 socket
  94. // to an IPv4-mapped IPv6 address. Even if those that allow it, since
  95. // the corresponding IPv4 address is the same as the one used in the
  96. // AF_INET socket case above, it should at least show the same result
  97. // as the previous one.
  98. EXPECT_THROW(IOService(NULL, *TEST_PORT, *"::ffff:255.255.0.0"), IOError);
  99. }
  100. TEST(IOServiceTest, duplicateBind) {
  101. // In each sub test case, second attempt should fail due to duplicate bind
  102. // IPv6, "any" address
  103. IOService* io_service = new IOService(NULL, *TEST_PORT, false, true);
  104. EXPECT_THROW(IOService(NULL, *TEST_PORT, false, true), IOError);
  105. delete io_service;
  106. // IPv6, specific address
  107. io_service = new IOService(NULL, *TEST_PORT, *TEST_IPV6_ADDR);
  108. EXPECT_THROW(IOService(NULL, *TEST_PORT, *TEST_IPV6_ADDR), IOError);
  109. delete io_service;
  110. // IPv4, "any" address
  111. io_service = new IOService(NULL, *TEST_PORT, true, false);
  112. EXPECT_THROW(IOService(NULL, *TEST_PORT, true, false), IOError);
  113. delete io_service;
  114. // IPv4, specific address
  115. io_service = new IOService(NULL, *TEST_PORT, *TEST_IPV4_ADDR);
  116. EXPECT_THROW(IOService(NULL, *TEST_PORT, *TEST_IPV4_ADDR), IOError);
  117. delete io_service;
  118. }
  119. struct addrinfo*
  120. resolveAddress(const int family, const int sock_type, const int protocol) {
  121. const char* const addr = (family == AF_INET6) ?
  122. TEST_IPV6_ADDR : TEST_IPV4_ADDR;
  123. struct addrinfo hints;
  124. memset(&hints, 0, sizeof(hints));
  125. hints.ai_family = family;
  126. hints.ai_socktype = sock_type;
  127. hints.ai_protocol = protocol;
  128. struct addrinfo* res;
  129. const int error = getaddrinfo(addr, TEST_PORT, &hints, &res);
  130. if (error != 0) {
  131. isc_throw(IOError, "getaddrinfo failed: " << gai_strerror(error));
  132. }
  133. return (res);
  134. }
  135. // This fixture is a framework for various types of network operations
  136. // using the ASIO interfaces. Each test case creates an IOService object,
  137. // opens a local "client" socket for testing, sends data via the local socket
  138. // to the service that would run in the IOService object.
  139. // A mock callback function (an ASIOCallBack object) is registered with the
  140. // IOService object, so the test code should be able to examine the data
  141. // receives on the server side. It then checks the received data matches
  142. // expected parameters.
  143. // If initialization parameters of the IOService should be modified, the test
  144. // case can do it using the setIOService() method.
  145. // Note: the set of tests in ASIOLinkTest use actual network services and may
  146. // involve undesirable side effect such as blocking.
  147. class ASIOLinkTest : public ::testing::Test {
  148. protected:
  149. ASIOLinkTest();
  150. ~ASIOLinkTest() {
  151. if (res_ != NULL) {
  152. freeaddrinfo(res_);
  153. }
  154. if (sock_ != -1) {
  155. close(sock_);
  156. }
  157. delete io_service_;
  158. }
  159. void sendUDP(const int family) {
  160. res_ = resolveAddress(family, SOCK_DGRAM, IPPROTO_UDP);
  161. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  162. if (sock_ < 0) {
  163. isc_throw(IOError, "failed to open test socket");
  164. }
  165. const int cc = sendto(sock_, test_data, sizeof(test_data), 0,
  166. res_->ai_addr, res_->ai_addrlen);
  167. if (cc != sizeof(test_data)) {
  168. isc_throw(IOError, "unexpected sendto result: " << cc);
  169. }
  170. io_service_->run();
  171. }
  172. void sendTCP(const int family) {
  173. res_ = resolveAddress(family, SOCK_STREAM, IPPROTO_TCP);
  174. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  175. if (sock_ < 0) {
  176. isc_throw(IOError, "failed to open test socket");
  177. }
  178. if (connect(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
  179. isc_throw(IOError, "failed to connect to the test server");
  180. }
  181. const int cc = send(sock_, test_data, sizeof(test_data), 0);
  182. if (cc != sizeof(test_data)) {
  183. isc_throw(IOError, "unexpected sendto result: " << cc);
  184. }
  185. io_service_->run();
  186. }
  187. void setIOService(const char& address) {
  188. delete io_service_;
  189. io_service_ = NULL;
  190. io_service_ = new IOService(NULL, *TEST_PORT, address);
  191. io_service_->setCallBack(ASIOCallBack(this));
  192. }
  193. void setIOService(const bool use_ipv4, const bool use_ipv6) {
  194. delete io_service_;
  195. io_service_ = NULL;
  196. io_service_ = new IOService(NULL, *TEST_PORT, use_ipv4, use_ipv6);
  197. io_service_->setCallBack(ASIOCallBack(this));
  198. }
  199. void doTest(const int family, const int protocol) {
  200. if (protocol == IPPROTO_UDP) {
  201. sendUDP(family);
  202. } else {
  203. sendTCP(family);
  204. }
  205. // There doesn't seem to be an effective test for the validity of
  206. // 'native'.
  207. // One thing we are sure is it must be different from our local socket.
  208. EXPECT_NE(sock_, callback_native_);
  209. EXPECT_EQ(protocol, callback_protocol_);
  210. EXPECT_EQ(family == AF_INET6 ? TEST_IPV6_ADDR : TEST_IPV4_ADDR,
  211. callback_address_);
  212. const uint8_t* expected_data =
  213. protocol == IPPROTO_UDP ? test_data : test_data + 2;
  214. const size_t expected_datasize =
  215. protocol == IPPROTO_UDP ? sizeof(test_data) :
  216. sizeof(test_data) - 2;
  217. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &callback_data_[0],
  218. callback_data_.size(),
  219. expected_data, expected_datasize);
  220. }
  221. private:
  222. class ASIOCallBack : public std::unary_function<IOMessage, void> {
  223. public:
  224. ASIOCallBack(ASIOLinkTest* test_obj) : test_obj_(test_obj) {}
  225. void operator()(const IOMessage& io_message) const {
  226. test_obj_->callBack(io_message);
  227. }
  228. private:
  229. ASIOLinkTest* test_obj_;
  230. };
  231. void callBack(const IOMessage& io_message) {
  232. callback_protocol_ = io_message.getSocket().getProtocol();
  233. callback_native_ = io_message.getSocket().getNative();
  234. callback_address_ =
  235. io_message.getRemoteEndpoint().getAddress().toText();
  236. callback_data_.assign(
  237. static_cast<const uint8_t*>(io_message.getData()),
  238. static_cast<const uint8_t*>(io_message.getData()) +
  239. io_message.getDataSize());
  240. io_service_->stop();
  241. }
  242. protected:
  243. IOService* io_service_;
  244. int callback_protocol_;
  245. int callback_native_;
  246. string callback_address_;
  247. vector<uint8_t> callback_data_;
  248. int sock_;
  249. private:
  250. struct addrinfo* res_;
  251. };
  252. ASIOLinkTest::ASIOLinkTest() :
  253. io_service_(NULL), sock_(-1), res_(NULL)
  254. {
  255. setIOService(true, true);
  256. }
  257. TEST_F(ASIOLinkTest, v6UDPSend) {
  258. doTest(AF_INET6, IPPROTO_UDP);
  259. }
  260. TEST_F(ASIOLinkTest, v6TCPSend) {
  261. doTest(AF_INET6, IPPROTO_TCP);
  262. }
  263. TEST_F(ASIOLinkTest, v4UDPSend) {
  264. doTest(AF_INET, IPPROTO_UDP);
  265. }
  266. TEST_F(ASIOLinkTest, v4TCPSend) {
  267. doTest(AF_INET, IPPROTO_TCP);
  268. }
  269. TEST_F(ASIOLinkTest, v6UDPSendSpecific) {
  270. // Explicitly set a specific address to be bound to the socket.
  271. // The subsequent test does not directly ensures the underlying socket
  272. // is bound to the expected address, but the success of the tests should
  273. // reasonably suggest it works as intended.
  274. // Specifying an address also implicitly means the service runs in a
  275. // single address-family mode. In tests using TCP we can confirm that
  276. // by trying to make a connection and seeing a failure. In UDP, it'd be
  277. // more complicated because we need to use a connected socket and catch
  278. // an error on a subsequent read operation. We could do it, but for
  279. // simplicity we only tests the easier cases for now.
  280. setIOService(*TEST_IPV6_ADDR);
  281. doTest(AF_INET6, IPPROTO_UDP);
  282. }
  283. TEST_F(ASIOLinkTest, v6TCPSendSpecific) {
  284. setIOService(*TEST_IPV6_ADDR);
  285. doTest(AF_INET6, IPPROTO_TCP);
  286. EXPECT_THROW(sendTCP(AF_INET), IOError);
  287. }
  288. TEST_F(ASIOLinkTest, v4UDPSendSpecific) {
  289. setIOService(*TEST_IPV4_ADDR);
  290. doTest(AF_INET, IPPROTO_UDP);
  291. }
  292. TEST_F(ASIOLinkTest, v4TCPSendSpecific) {
  293. setIOService(*TEST_IPV4_ADDR);
  294. doTest(AF_INET, IPPROTO_TCP);
  295. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  296. }
  297. TEST_F(ASIOLinkTest, v6TCPOnly) {
  298. // Open only IPv6 TCP socket. A subsequent attempt of establishing an
  299. // IPv4/TCP connection should fail. See above for why we only test this
  300. // for TCP.
  301. setIOService(false, true);
  302. EXPECT_THROW(sendTCP(AF_INET), IOError);
  303. }
  304. TEST_F(ASIOLinkTest, v4TCPOnly) {
  305. setIOService(true, false);
  306. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  307. }
  308. // This fixture is for testing IntervalTimer. Some callback functors are
  309. // registered as callback function of the timer to test if they are called
  310. // or not.
  311. class IntervalTimerTest : public ::testing::Test {
  312. protected:
  313. IntervalTimerTest() : io_service_(NULL, *TEST_PORT, false, false) {};
  314. ~IntervalTimerTest() {}
  315. class TimerCallBack : public std::unary_function<void, void> {
  316. public:
  317. TimerCallBack(IntervalTimerTest* test_obj) : test_obj_(test_obj) {}
  318. void operator()() const {
  319. test_obj_->timer_called_ = true;
  320. test_obj_->io_service_.stop();
  321. return;
  322. }
  323. private:
  324. IntervalTimerTest* test_obj_;
  325. };
  326. class TimerCallBackCounter : public std::unary_function<void, void> {
  327. public:
  328. TimerCallBackCounter(IntervalTimerTest* test_obj) : test_obj_(test_obj) {
  329. counter_ = 0;
  330. }
  331. void operator()() {
  332. ++counter_;
  333. return;
  334. }
  335. int counter_;
  336. private:
  337. IntervalTimerTest* test_obj_;
  338. };
  339. class TimerCallBackCancelDeleter : public std::unary_function<void, void> {
  340. public:
  341. TimerCallBackCancelDeleter(IntervalTimerTest* test_obj,
  342. IntervalTimer* timer,
  343. TimerCallBackCounter& counter)
  344. : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0)
  345. {}
  346. void operator()() {
  347. ++count_;
  348. if (count_ == 1) {
  349. // First time of call back.
  350. // Store the value of counter_.counter_.
  351. prev_counter_ = counter_.counter_;
  352. delete timer_;
  353. } else if (count_ == 2) {
  354. // Second time of call back.
  355. // Stop io_service to stop all timers.
  356. test_obj_->io_service_.stop();
  357. // Compare the value of counter_.counter_ with stored one.
  358. // If TimerCallBackCounter was not called (expected behavior),
  359. // they are same.
  360. if (counter_.counter_ == prev_counter_) {
  361. test_obj_->timer_cancel_success_ = true;
  362. }
  363. }
  364. return;
  365. }
  366. private:
  367. IntervalTimerTest* test_obj_;
  368. IntervalTimer* timer_;
  369. TimerCallBackCounter& counter_;
  370. int count_;
  371. int prev_counter_;
  372. };
  373. class TimerCallBackOverwriter : public std::unary_function<void, void> {
  374. public:
  375. TimerCallBackOverwriter(IntervalTimerTest* test_obj,
  376. IntervalTimer& timer)
  377. : test_obj_(test_obj), timer_(timer), count_(0)
  378. {}
  379. void operator()() {
  380. ++count_;
  381. if (count_ == 1) {
  382. // First time of call back.
  383. // Call setupTimer() to update callback function
  384. // to TimerCallBack.
  385. test_obj_->timer_called_ = false;
  386. timer_.setupTimer(TimerCallBack(test_obj_), 1);
  387. } else if (count_ == 2) {
  388. // Second time of call back.
  389. // If it reaches here, re-setupTimer() is failed (unexpected).
  390. // We should stop here.
  391. test_obj_->io_service_.stop();
  392. }
  393. return;
  394. }
  395. private:
  396. IntervalTimerTest* test_obj_;
  397. IntervalTimer& timer_;
  398. int count_;
  399. };
  400. protected:
  401. IOService io_service_;
  402. bool timer_called_;
  403. bool timer_cancel_success_;
  404. };
  405. TEST_F(IntervalTimerTest, invalidArgumentToIntervalTimer) {
  406. // Create asio_link::IntervalTimer and setup.
  407. IntervalTimer itimer(io_service_);
  408. // expect throw if call back function is empty
  409. EXPECT_THROW(itimer.setupTimer(IntervalTimer::Callback(), 1),
  410. isc::InvalidParameter);
  411. // expect throw if interval is 0
  412. EXPECT_THROW(itimer.setupTimer(TimerCallBack(this), 0), isc::BadValue);
  413. }
  414. TEST_F(IntervalTimerTest, startIntervalTimer) {
  415. // Create asio_link::IntervalTimer and setup.
  416. // Then run IOService and test if the callback function is called.
  417. IntervalTimer itimer(io_service_);
  418. timer_called_ = false;
  419. // store start time
  420. boost::posix_time::ptime start;
  421. start = boost::posix_time::microsec_clock::universal_time();
  422. // setup timer
  423. itimer.setupTimer(TimerCallBack(this), 1);
  424. io_service_.run();
  425. // reaches here after timer expired
  426. // delta: difference between elapsed time and 1 second
  427. boost::posix_time::time_duration delta =
  428. (boost::posix_time::microsec_clock::universal_time() - start)
  429. - boost::posix_time::seconds(1);
  430. if (delta.is_negative()) {
  431. delta.invert_sign();
  432. }
  433. // expect TimerCallBack is called; timer_called_ is true
  434. EXPECT_TRUE(timer_called_);
  435. // expect interval is 1 second +/- TIMER_MERGIN_MSEC.
  436. EXPECT_TRUE(delta < TIMER_MERGIN_MSEC);
  437. }
  438. TEST_F(IntervalTimerTest, deleteIntervalTimerBeforeStart) {
  439. // Note: This code isn't exception safe, but we'd rather keep the code
  440. // simpler and more readable as this is only for tests and if it throws
  441. // the program would immediately terminate anyway.
  442. // Create asio_link::IntervalTimer and delete before starting timer.
  443. // Test if the callback function is not called.
  444. IntervalTimer* itimer = new IntervalTimer(io_service_);
  445. timer_called_ = false;
  446. // setup timer...
  447. itimer->setupTimer(TimerCallBack(this), 1);
  448. // and delete
  449. delete itimer;
  450. // expect the callback function is not called
  451. EXPECT_FALSE(timer_called_);
  452. }
  453. TEST_F(IntervalTimerTest, destructIntervalTimer) {
  454. // Note: This test currently takes 6 seconds. The timer should have
  455. // finer granularity and timer periods in this test should be shorter
  456. // in the future.
  457. // This code isn't exception safe, but we'd rather keep the code
  458. // simpler and more readable as this is only for tests and if it throws
  459. // the program would immediately terminate anyway.
  460. // The call back function will not be called after the timer is
  461. // destructed.
  462. //
  463. // There are two timers:
  464. // itimer_counter (A)
  465. // (Calls TimerCallBackCounter)
  466. // - increments internal counter in callback function
  467. // itimer_canceller (B)
  468. // (Calls TimerCallBackCancelDeleter)
  469. // - first time of callback, it stores the counter value of
  470. // callback_canceller and destructs itimer_counter
  471. // - second time of callback, it compares the counter value of
  472. // callback_canceller with stored value
  473. // if they are same the timer was not called; expected result
  474. // if they are different the timer was called after destructed
  475. //
  476. // 0 1 2 3 4 5 6 (s)
  477. // (A) i-----+--x
  478. // ^
  479. // |destruct itimer_counter
  480. // (B) i--------+--------s
  481. // ^stop io_service
  482. // and test itimer_counter have been stopped
  483. //
  484. // itimer_counter will be deleted in TimerCallBackCancelDeleter
  485. IntervalTimer* itimer_counter = new IntervalTimer(io_service_);
  486. IntervalTimer itimer_canceller(io_service_);
  487. timer_cancel_success_ = false;
  488. TimerCallBackCounter callback_canceller(this);
  489. itimer_counter->setupTimer(callback_canceller, 2);
  490. itimer_canceller.setupTimer(
  491. TimerCallBackCancelDeleter(this, itimer_counter,
  492. callback_canceller),
  493. 3);
  494. io_service_.run();
  495. EXPECT_TRUE(timer_cancel_success_);
  496. }
  497. TEST_F(IntervalTimerTest, overwriteIntervalTimer) {
  498. // Note: This test currently takes 4 seconds. The timer should have
  499. // finer granularity and timer periods in this test should be shorter
  500. // in the future.
  501. // Calling setupTimer() multiple times updates call back function
  502. // and interval.
  503. //
  504. // There are two timers:
  505. // itimer (A)
  506. // (Calls TimerCallBackCounter / TimerCallBack)
  507. // - increments internal counter in callback function
  508. // (TimerCallBackCounter)
  509. // interval: 2 seconds
  510. // - io_service_.stop() (TimerCallBack)
  511. // interval: 1 second
  512. // itimer_overwriter (B)
  513. // (Calls TimerCallBackOverwriter)
  514. // - first time of callback, it calls setupTimer() to change
  515. // call back function and interval of itimer to
  516. // TimerCallBack / 1 second
  517. // after 3 + 1 seconds from the beginning of this test,
  518. // TimerCallBack() will be called and io_service_ stops.
  519. // - second time of callback, it means the test fails.
  520. //
  521. // 0 1 2 3 4 5 6 (s)
  522. // (A) i-----+--C--s
  523. // ^ ^stop io_service
  524. // |change call back function
  525. // (B) i--------+--------S
  526. // ^(stop io_service on fail)
  527. //
  528. IntervalTimer itimer(io_service_);
  529. IntervalTimer itimer_overwriter(io_service_);
  530. // store start time
  531. boost::posix_time::ptime start;
  532. start = boost::posix_time::microsec_clock::universal_time();
  533. itimer.setupTimer(TimerCallBackCounter(this), 2);
  534. itimer_overwriter.setupTimer(TimerCallBackOverwriter(this, itimer), 3);
  535. io_service_.run();
  536. // reaches here after timer expired
  537. // if interval is updated, it takes
  538. // 3 seconds for TimerCallBackOverwriter
  539. // + 1 second for TimerCallBack (stop)
  540. // = 4 seconds.
  541. // otherwise (test fails), it takes
  542. // 3 seconds for TimerCallBackOverwriter
  543. // + 3 seconds for TimerCallBackOverwriter (stop)
  544. // = 6 seconds.
  545. // delta: difference between elapsed time and 3 + 1 seconds
  546. boost::posix_time::time_duration delta =
  547. (boost::posix_time::microsec_clock::universal_time() - start)
  548. - boost::posix_time::seconds(3 + 1);
  549. if (delta.is_negative()) {
  550. delta.invert_sign();
  551. }
  552. // expect callback function is updated: TimerCallBack is called
  553. EXPECT_TRUE(timer_called_);
  554. // expect interval is updated
  555. EXPECT_TRUE(delta < TIMER_MERGIN_MSEC);
  556. }
  557. }