ncr_udp_unittests.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. // Copyright (C) 2013-2015 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 <asiolink/interval_timer.h>
  16. #include <dhcp_ddns/ncr_io.h>
  17. #include <dhcp_ddns/ncr_udp.h>
  18. #include <util/time_utilities.h>
  19. #include <test_utils.h>
  20. #include <boost/asio/ip/udp.hpp>
  21. #include <boost/function.hpp>
  22. #include <boost/bind.hpp>
  23. #include <gtest/gtest.h>
  24. #include <algorithm>
  25. #include <sys/select.h>
  26. using namespace std;
  27. using namespace isc;
  28. using namespace isc::dhcp_ddns;
  29. namespace {
  30. /// @brief Defines a list of valid JSON NameChangeRequest test messages.
  31. const char *valid_msgs[] =
  32. {
  33. // Valid Add.
  34. "{"
  35. " \"change-type\" : 0 , "
  36. " \"forward-change\" : true , "
  37. " \"reverse-change\" : false , "
  38. " \"fqdn\" : \"walah.walah.com\" , "
  39. " \"ip-address\" : \"192.168.2.1\" , "
  40. " \"dhcid\" : \"010203040A7F8E3D\" , "
  41. " \"lease-expires-on\" : \"20130121132405\" , "
  42. " \"lease-length\" : 1300 "
  43. "}",
  44. // Valid Remove.
  45. "{"
  46. " \"change-type\" : 1 , "
  47. " \"forward-change\" : true , "
  48. " \"reverse-change\" : false , "
  49. " \"fqdn\" : \"walah.walah.com\" , "
  50. " \"ip-address\" : \"192.168.2.1\" , "
  51. " \"dhcid\" : \"010203040A7F8E3D\" , "
  52. " \"lease-expires-on\" : \"20130121132405\" , "
  53. " \"lease-length\" : 1300 "
  54. "}",
  55. // Valid Add with IPv6 address
  56. "{"
  57. " \"change-type\" : 0 , "
  58. " \"forward-change\" : true , "
  59. " \"reverse-change\" : false , "
  60. " \"fqdn\" : \"walah.walah.com\" , "
  61. " \"ip-address\" : \"fe80::2acf:e9ff:fe12:e56f\" , "
  62. " \"dhcid\" : \"010203040A7F8E3D\" , "
  63. " \"lease-expires-on\" : \"20130121132405\" , "
  64. " \"lease-length\" : 1300 "
  65. "}"
  66. };
  67. const char* TEST_ADDRESS = "127.0.0.1";
  68. const uint32_t LISTENER_PORT = 5301;
  69. const uint32_t SENDER_PORT = LISTENER_PORT+1;
  70. const long TEST_TIMEOUT = 5 * 1000;
  71. /// @brief A NOP derivation for constructor test purposes.
  72. class SimpleListenHandler : public NameChangeListener::RequestReceiveHandler {
  73. public:
  74. virtual void operator ()(const NameChangeListener::Result,
  75. NameChangeRequestPtr&) {
  76. }
  77. };
  78. /// @brief Tests the NameChangeUDPListener constructors.
  79. /// This test verifies that:
  80. /// 1. Given valid parameters, the listener constructor works
  81. TEST(NameChangeUDPListenerBasicTest, constructionTests) {
  82. // Verify the default constructor works.
  83. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  84. uint32_t port = LISTENER_PORT;
  85. isc::asiolink::IOService io_service;
  86. SimpleListenHandler ncr_handler;
  87. // Verify that valid constructor works.
  88. EXPECT_NO_THROW(NameChangeUDPListener(ip_address, port, FMT_JSON,
  89. ncr_handler));
  90. }
  91. /// @brief Tests NameChangeUDPListener starting and stopping listening .
  92. /// This test verifies that the listener will:
  93. /// 1. Enter listening state
  94. /// 2. If in the listening state, does not allow calls to start listening
  95. /// 3. Exist the listening state
  96. /// 4. Return to the listening state after stopping
  97. TEST(NameChangeUDPListenerBasicTest, basicListenTests) {
  98. // Verify the default constructor works.
  99. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  100. uint32_t port = LISTENER_PORT;
  101. isc::asiolink::IOService io_service;
  102. SimpleListenHandler ncr_handler;
  103. NameChangeListenerPtr listener;
  104. ASSERT_NO_THROW(listener.reset(
  105. new NameChangeUDPListener(ip_address, port, FMT_JSON, ncr_handler)));
  106. // Verify that we can start listening.
  107. EXPECT_NO_THROW(listener->startListening(io_service));
  108. // Verify that we are in listening mode.
  109. EXPECT_TRUE(listener->amListening());
  110. // Verify that a read is in progress.
  111. EXPECT_TRUE(listener->isIoPending());
  112. // Verify that attempting to listen when we already are is an error.
  113. EXPECT_THROW(listener->startListening(io_service), NcrListenerError);
  114. // Verify that we can stop listening.
  115. EXPECT_NO_THROW(listener->stopListening());
  116. EXPECT_FALSE(listener->amListening());
  117. // Verify that IO pending is still true, as IO cancel event has not yet
  118. // occurred.
  119. EXPECT_TRUE(listener->isIoPending());
  120. // Verify that IO pending is false, after cancel event occurs.
  121. EXPECT_NO_THROW(io_service.run_one());
  122. EXPECT_FALSE(listener->isIoPending());
  123. // Verify that attempting to stop listening when we are not is ok.
  124. EXPECT_NO_THROW(listener->stopListening());
  125. // Verify that we can re-enter listening.
  126. EXPECT_NO_THROW(listener->startListening(io_service));
  127. EXPECT_TRUE(listener->amListening());
  128. }
  129. /// @brief Compares two NameChangeRequests for equality.
  130. bool checkSendVsReceived(NameChangeRequestPtr sent_ncr,
  131. NameChangeRequestPtr received_ncr) {
  132. return ((sent_ncr && received_ncr) &&
  133. (*sent_ncr == *received_ncr));
  134. }
  135. /// @brief Text fixture for testing NameChangeUDPListener
  136. class NameChangeUDPListenerTest : public virtual ::testing::Test,
  137. NameChangeListener::RequestReceiveHandler {
  138. public:
  139. isc::asiolink::IOService io_service_;
  140. NameChangeListener::Result result_;
  141. NameChangeRequestPtr sent_ncr_;
  142. NameChangeRequestPtr received_ncr_;
  143. NameChangeListenerPtr listener_;
  144. isc::asiolink::IntervalTimer test_timer_;
  145. /// @brief Constructor
  146. //
  147. // Instantiates the listener member and the test timer. The timer is used
  148. // to ensure a test doesn't go awry and hang forever.
  149. NameChangeUDPListenerTest()
  150. : io_service_(), result_(NameChangeListener::SUCCESS),
  151. test_timer_(io_service_) {
  152. isc::asiolink::IOAddress addr(TEST_ADDRESS);
  153. listener_.reset(new NameChangeUDPListener(addr, LISTENER_PORT,
  154. FMT_JSON, *this, true));
  155. // Set the test timeout to break any running tasks if they hang.
  156. test_timer_.setup(boost::bind(&NameChangeUDPListenerTest::
  157. testTimeoutHandler, this),
  158. TEST_TIMEOUT);
  159. }
  160. virtual ~NameChangeUDPListenerTest(){
  161. }
  162. /// @brief Converts JSON string into an NCR and sends it to the listener.
  163. ///
  164. void sendNcr(const std::string& msg) {
  165. // Build an NCR from json string. This verifies that the
  166. // test string is valid.
  167. ASSERT_NO_THROW(sent_ncr_ = NameChangeRequest::fromJSON(msg));
  168. // Now use the NCR to write JSON to an output buffer.
  169. isc::util::OutputBuffer ncr_buffer(1024);
  170. ASSERT_NO_THROW(sent_ncr_->toFormat(FMT_JSON, ncr_buffer));
  171. // Create a UDP socket through which our "sender" will send the NCR.
  172. boost::asio::ip::udp::socket
  173. udp_socket(io_service_.get_io_service(), boost::asio::ip::udp::v4());
  174. // Create an endpoint pointed at the listener.
  175. boost::asio::ip::udp::endpoint
  176. listener_endpoint(boost::asio::ip::address::from_string(TEST_ADDRESS),
  177. LISTENER_PORT);
  178. // A response message is now ready to send. Send it!
  179. // Note this uses a synchronous send so it ships immediately.
  180. // If listener isn't in listening mode, it will get missed.
  181. udp_socket.send_to(boost::asio::buffer(ncr_buffer.getData(),
  182. ncr_buffer.getLength()),
  183. listener_endpoint);
  184. }
  185. /// @brief RequestReceiveHandler operator implementation for receiving NCRs.
  186. ///
  187. /// The fixture acts as the "application" layer. It derives from
  188. /// RequestReceiveHandler and as such implements operator() in order to
  189. /// receive NCRs.
  190. virtual void operator ()(const NameChangeListener::Result result,
  191. NameChangeRequestPtr& ncr) {
  192. // save the result and the NCR we received
  193. result_ = result;
  194. received_ncr_ = ncr;
  195. }
  196. // @brief Handler invoked when test timeout is hit.
  197. //
  198. // This callback stops all running (hanging) tasks on IO service.
  199. void testTimeoutHandler() {
  200. io_service_.stop();
  201. FAIL() << "Test timeout hit.";
  202. }
  203. };
  204. /// @brief Tests NameChangeUDPListener ability to receive NCRs.
  205. /// This test verifies that a listener can enter listening mode and
  206. /// receive NCRs in wire format on its UDP socket; reconstruct the
  207. /// NCRs and delivery them to the "application" layer.
  208. TEST_F(NameChangeUDPListenerTest, basicReceivetest) {
  209. // Verify we can enter listening mode.
  210. ASSERT_FALSE(listener_->amListening());
  211. ASSERT_NO_THROW(listener_->startListening(io_service_));
  212. ASSERT_TRUE(listener_->amListening());
  213. ASSERT_TRUE(listener_->isIoPending());
  214. // Iterate over a series of requests, sending and receiving one
  215. /// at time.
  216. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  217. for (int i = 0; i < num_msgs; i++) {
  218. // We are not verifying ability to send, so if we can't test is over.
  219. ASSERT_NO_THROW(sendNcr(valid_msgs[i]));
  220. // Execute no more then one event, which should be receive complete.
  221. EXPECT_NO_THROW(io_service_.run_one());
  222. // Verify the "application" status value for a successful complete.
  223. EXPECT_EQ(NameChangeListener::SUCCESS, result_);
  224. // Verify the received request matches the sent request.
  225. EXPECT_TRUE(checkSendVsReceived(sent_ncr_, received_ncr_));
  226. }
  227. // Verify we can gracefully stop listening.
  228. EXPECT_NO_THROW(listener_->stopListening());
  229. EXPECT_FALSE(listener_->amListening());
  230. // Verify that IO pending is false, after cancel event occurs.
  231. EXPECT_NO_THROW(io_service_.run_one());
  232. EXPECT_FALSE(listener_->isIoPending());
  233. }
  234. /// @brief A NOP derivation for constructor test purposes.
  235. class SimpleSendHandler : public NameChangeSender::RequestSendHandler {
  236. public:
  237. SimpleSendHandler() : pass_count_(0), error_count_(0) {
  238. }
  239. virtual void operator ()(const NameChangeSender::Result result,
  240. NameChangeRequestPtr&) {
  241. if (result == NameChangeSender::SUCCESS) {
  242. ++pass_count_;
  243. } else {
  244. ++error_count_;
  245. }
  246. }
  247. int pass_count_;
  248. int error_count_;
  249. };
  250. /// @brief Tests the NameChangeUDPSender constructors.
  251. /// This test verifies that:
  252. /// 1. Constructing with a max queue size of 0 is not allowed
  253. /// 2. Given valid parameters, the sender constructor works
  254. /// 3. Default construction provides default max queue size
  255. /// 4. Construction with a custom max queue size works
  256. TEST(NameChangeUDPSenderBasicTest, constructionTests) {
  257. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  258. uint32_t port = SENDER_PORT;
  259. isc::asiolink::IOService io_service;
  260. SimpleSendHandler ncr_handler;
  261. // Verify that constructing with an queue size of zero is not allowed.
  262. EXPECT_THROW(NameChangeUDPSender(ip_address, port,
  263. ip_address, port, FMT_JSON, ncr_handler, 0), NcrSenderError);
  264. NameChangeSenderPtr sender;
  265. // Verify that valid constructor works.
  266. EXPECT_NO_THROW(sender.reset(
  267. new NameChangeUDPSender(ip_address, port, ip_address, port,
  268. FMT_JSON, ncr_handler)));
  269. // Verify that send queue default max is correct.
  270. size_t expected = NameChangeSender::MAX_QUEUE_DEFAULT;
  271. EXPECT_EQ(expected, sender->getQueueMaxSize());
  272. // Verify that constructor with a valid custom queue size works.
  273. EXPECT_NO_THROW(sender.reset(
  274. new NameChangeUDPSender(ip_address, port, ip_address, port,
  275. FMT_JSON, ncr_handler, 100)));
  276. EXPECT_EQ(100, sender->getQueueMaxSize());
  277. }
  278. /// @brief Tests NameChangeUDPSender basic send functionality
  279. /// This test verifies that:
  280. TEST(NameChangeUDPSenderBasicTest, basicSendTests) {
  281. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  282. isc::asiolink::IOService io_service;
  283. SimpleSendHandler ncr_handler;
  284. // Tests are based on a list of messages, get the count now.
  285. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  286. // Create the sender, setting the queue max equal to the number of
  287. // messages we will have in the list.
  288. NameChangeUDPSender sender(ip_address, SENDER_PORT, ip_address,
  289. LISTENER_PORT, FMT_JSON, ncr_handler,
  290. num_msgs, true);
  291. // Verify that we can start sending.
  292. EXPECT_NO_THROW(sender.startSending(io_service));
  293. EXPECT_TRUE(sender.amSending());
  294. // Verify that attempting to send when we already are is an error.
  295. EXPECT_THROW(sender.startSending(io_service), NcrSenderError);
  296. // Verify that we can stop sending.
  297. EXPECT_NO_THROW(sender.stopSending());
  298. EXPECT_FALSE(sender.amSending());
  299. // Verify that attempting to stop sending when we are not is ok.
  300. EXPECT_NO_THROW(sender.stopSending());
  301. // Verify that we can re-enter sending after stopping.
  302. EXPECT_NO_THROW(sender.startSending(io_service));
  303. EXPECT_TRUE(sender.amSending());
  304. // Fetch the sender's select-fd.
  305. int select_fd = sender.getSelectFd();
  306. // Verify select_fd is valid and currently shows no ready to read.
  307. ASSERT_NE(util::WatchSocket::SOCKET_NOT_VALID, select_fd);
  308. // Make sure select_fd does evaluates to not ready via select and
  309. // that ioReady() method agrees.
  310. ASSERT_EQ(0, selectCheck(select_fd));
  311. ASSERT_FALSE(sender.ioReady());
  312. // Iterate over a series of messages, sending each one. Since we
  313. // do not invoke IOService::run, then the messages should accumulate
  314. // in the queue.
  315. NameChangeRequestPtr ncr;
  316. NameChangeRequestPtr ncr2;
  317. for (int i = 0; i < num_msgs; i++) {
  318. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  319. EXPECT_NO_THROW(sender.sendRequest(ncr));
  320. // Verify that the queue count increments in step with each send.
  321. EXPECT_EQ(i+1, sender.getQueueSize());
  322. // Verify that peekAt(i) returns the NCR we just added.
  323. ASSERT_NO_THROW(ncr2 = sender.peekAt(i));
  324. ASSERT_TRUE(ncr2);
  325. EXPECT_TRUE(*ncr == *ncr2);
  326. }
  327. // Verify that attempting to peek beyond the end of the queue, throws.
  328. ASSERT_THROW(sender.peekAt(sender.getQueueSize()+1), NcrSenderError);
  329. // Verify that attempting to send an additional message results in a
  330. // queue full exception.
  331. EXPECT_THROW(sender.sendRequest(ncr), NcrSenderQueueFull);
  332. // Loop for the number of valid messages. So long as there is at least
  333. // on NCR in the queue, select-fd indicate ready to read. Invoke
  334. // IOService::run_one. This should complete the send of exactly one
  335. // message and the queue count should decrement accordingly.
  336. for (int i = num_msgs; i > 0; i--) {
  337. // Make sure select_fd does evaluates to ready via select and
  338. // that ioReady() method agrees.
  339. ASSERT_TRUE(selectCheck(select_fd) > 0);
  340. ASSERT_TRUE(sender.ioReady());
  341. // Execute at one ready handler.
  342. ASSERT_NO_THROW(sender.runReadyIO());
  343. // Verify that the queue count decrements in step with each run.
  344. EXPECT_EQ(i-1, sender.getQueueSize());
  345. }
  346. // Make sure select_fd does evaluates to not ready via select and
  347. // that ioReady() method agrees.
  348. ASSERT_EQ(0, selectCheck(select_fd));
  349. ASSERT_FALSE(sender.ioReady());
  350. // Verify that the queue is empty.
  351. EXPECT_EQ(0, sender.getQueueSize());
  352. // Verify that we can add back to the queue
  353. EXPECT_NO_THROW(sender.sendRequest(ncr));
  354. EXPECT_EQ(1, sender.getQueueSize());
  355. // Verify that we can remove the current entry at the front of the queue.
  356. EXPECT_NO_THROW(sender.skipNext());
  357. EXPECT_EQ(0, sender.getQueueSize());
  358. // Verify that flushing the queue is not allowed in sending state.
  359. EXPECT_THROW(sender.clearSendQueue(), NcrSenderError);
  360. // Put num_msgs messages on the queue.
  361. for (int i = 0; i < num_msgs; i++) {
  362. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  363. EXPECT_NO_THROW(sender.sendRequest(ncr));
  364. }
  365. // Make sure we have number of messages expected.
  366. EXPECT_EQ(num_msgs, sender.getQueueSize());
  367. // Verify that we can gracefully stop sending.
  368. EXPECT_NO_THROW(sender.stopSending());
  369. EXPECT_FALSE(sender.amSending());
  370. // Verify that the queue is preserved after leaving sending state.
  371. EXPECT_EQ(num_msgs - 1, sender.getQueueSize());
  372. // Verify that flushing the queue works when not sending.
  373. EXPECT_NO_THROW(sender.clearSendQueue());
  374. EXPECT_EQ(0, sender.getQueueSize());
  375. }
  376. /// @brief Tests that sending gets kick-started if the queue isn't empty
  377. /// when startSending is called.
  378. TEST(NameChangeUDPSenderBasicTest, autoStart) {
  379. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  380. isc::asiolink::IOService io_service;
  381. SimpleSendHandler ncr_handler;
  382. // Tests are based on a list of messages, get the count now.
  383. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  384. // Create the sender, setting the queue max equal to the number of
  385. // messages we will have in the list.
  386. NameChangeUDPSender sender(ip_address, SENDER_PORT, ip_address,
  387. LISTENER_PORT, FMT_JSON, ncr_handler,
  388. num_msgs, true);
  389. // Verify that we can start sending.
  390. EXPECT_NO_THROW(sender.startSending(io_service));
  391. EXPECT_TRUE(sender.amSending());
  392. // Queue up messages.
  393. NameChangeRequestPtr ncr;
  394. for (int i = 0; i < num_msgs; i++) {
  395. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  396. EXPECT_NO_THROW(sender.sendRequest(ncr));
  397. }
  398. // Make sure queue count is what we expect.
  399. EXPECT_EQ(num_msgs, sender.getQueueSize());
  400. // Stop sending.
  401. ASSERT_NO_THROW(sender.stopSending());
  402. ASSERT_FALSE(sender.amSending());
  403. // We should have completed the first message only.
  404. EXPECT_EQ(--num_msgs, sender.getQueueSize());
  405. // Restart sending.
  406. EXPECT_NO_THROW(sender.startSending(io_service));
  407. // We should be able to loop through remaining messages and send them.
  408. for (int i = num_msgs; i > 0; i--) {
  409. // ioReady() should evaluate to true.
  410. ASSERT_TRUE(sender.ioReady());
  411. // Execute at one ready handler.
  412. ASSERT_NO_THROW(sender.runReadyIO());
  413. }
  414. // Verify that the queue is empty.
  415. EXPECT_EQ(0, sender.getQueueSize());
  416. }
  417. /// @brief Tests NameChangeUDPSender basic send with INADDR_ANY and port 0.
  418. TEST(NameChangeUDPSenderBasicTest, anyAddressSend) {
  419. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  420. isc::asiolink::IOAddress any_address("0.0.0.0");
  421. isc::asiolink::IOService io_service;
  422. SimpleSendHandler ncr_handler;
  423. // Tests are based on a list of messages, get the count now.
  424. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  425. // Create the sender, setting the queue max equal to the number of
  426. // messages we will have in the list.
  427. NameChangeUDPSender sender(any_address, 0, ip_address, LISTENER_PORT,
  428. FMT_JSON, ncr_handler, num_msgs);
  429. // Enter send mode.
  430. ASSERT_NO_THROW(sender.startSending(io_service));
  431. EXPECT_TRUE(sender.amSending());
  432. // Create and queue up a message.
  433. NameChangeRequestPtr ncr;
  434. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[0]));
  435. EXPECT_NO_THROW(sender.sendRequest(ncr));
  436. EXPECT_EQ(1, sender.getQueueSize());
  437. // Verify we have a ready IO, then execute at one ready handler.
  438. ASSERT_TRUE(sender.ioReady());
  439. ASSERT_NO_THROW(sender.runReadyIO());
  440. // Verify that sender shows no IO ready.
  441. // and that the queue is empty.
  442. ASSERT_FALSE(sender.ioReady());
  443. EXPECT_EQ(0, sender.getQueueSize());
  444. }
  445. /// @brief Test the NameChangeSender::assumeQueue method.
  446. TEST(NameChangeSender, assumeQueue) {
  447. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  448. uint32_t port = SENDER_PORT;
  449. isc::asiolink::IOService io_service;
  450. SimpleSendHandler ncr_handler;
  451. NameChangeRequestPtr ncr;
  452. // Tests are based on a list of messages, get the count now.
  453. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  454. // Create two senders with queue max equal to the number of
  455. // messages we will have in the list.
  456. NameChangeUDPSender sender1(ip_address, port, ip_address, port,
  457. FMT_JSON, ncr_handler, num_msgs);
  458. NameChangeUDPSender sender2(ip_address, port+1, ip_address, port,
  459. FMT_JSON, ncr_handler, num_msgs);
  460. // Place sender1 into send mode and queue up messages.
  461. ASSERT_NO_THROW(sender1.startSending(io_service));
  462. for (int i = 0; i < num_msgs; i++) {
  463. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  464. ASSERT_NO_THROW(sender1.sendRequest(ncr));
  465. }
  466. // Make sure sender1's queue count is as expected.
  467. ASSERT_EQ(num_msgs, sender1.getQueueSize());
  468. // Verify sender1 is sending, sender2 is not.
  469. ASSERT_TRUE(sender1.amSending());
  470. ASSERT_FALSE(sender2.amSending());
  471. // Transfer from sender1 to sender2 should fail because
  472. // sender1 is in send mode.
  473. ASSERT_THROW(sender2.assumeQueue(sender1), NcrSenderError);
  474. // Take sender1 out of send mode.
  475. ASSERT_NO_THROW(sender1.stopSending());
  476. ASSERT_FALSE(sender1.amSending());
  477. // Stopping should have completed the first message.
  478. --num_msgs;
  479. EXPECT_EQ(num_msgs, sender1.getQueueSize());
  480. // Transfer should succeed. Verify sender1 has none,
  481. // and sender2 has num_msgs queued.
  482. EXPECT_NO_THROW(sender2.assumeQueue(sender1));
  483. EXPECT_EQ(0, sender1.getQueueSize());
  484. EXPECT_EQ(num_msgs, sender2.getQueueSize());
  485. // Reduce sender1's max queue size.
  486. ASSERT_NO_THROW(sender1.setQueueMaxSize(num_msgs - 1));
  487. // Transfer should fail as sender1's queue is not large enough.
  488. ASSERT_THROW(sender1.assumeQueue(sender2), NcrSenderError);
  489. // Place sender1 into send mode and queue up a message.
  490. ASSERT_NO_THROW(sender1.startSending(io_service));
  491. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[0]));
  492. ASSERT_NO_THROW(sender1.sendRequest(ncr));
  493. // Take sender1 out of send mode.
  494. ASSERT_NO_THROW(sender1.stopSending());
  495. // Try to transfer from sender1 to sender2. This should fail
  496. // as sender2's queue is not empty.
  497. ASSERT_THROW(sender2.assumeQueue(sender1), NcrSenderError);
  498. }
  499. /// @brief Text fixture that allows testing a listener and sender together
  500. /// It derives from both the receive and send handler classes and contains
  501. /// and instance of UDP listener and UDP sender.
  502. class NameChangeUDPTest : public virtual ::testing::Test,
  503. NameChangeListener::RequestReceiveHandler,
  504. NameChangeSender::RequestSendHandler {
  505. public:
  506. isc::asiolink::IOService io_service_;
  507. NameChangeListener::Result recv_result_;
  508. NameChangeSender::Result send_result_;
  509. NameChangeListenerPtr listener_;
  510. NameChangeSenderPtr sender_;
  511. isc::asiolink::IntervalTimer test_timer_;
  512. std::vector<NameChangeRequestPtr> sent_ncrs_;
  513. std::vector<NameChangeRequestPtr> received_ncrs_;
  514. NameChangeUDPTest()
  515. : io_service_(), recv_result_(NameChangeListener::SUCCESS),
  516. send_result_(NameChangeSender::SUCCESS), test_timer_(io_service_) {
  517. isc::asiolink::IOAddress addr(TEST_ADDRESS);
  518. // Create our listener instance. Note that reuse_address is true.
  519. listener_.reset(
  520. new NameChangeUDPListener(addr, LISTENER_PORT, FMT_JSON,
  521. *this, true));
  522. // Create our sender instance. Note that reuse_address is true.
  523. sender_.reset(
  524. new NameChangeUDPSender(addr, SENDER_PORT, addr, LISTENER_PORT,
  525. FMT_JSON, *this, 100, true));
  526. // Set the test timeout to break any running tasks if they hang.
  527. test_timer_.setup(boost::bind(&NameChangeUDPTest::testTimeoutHandler,
  528. this),
  529. TEST_TIMEOUT);
  530. }
  531. void reset_results() {
  532. sent_ncrs_.clear();
  533. received_ncrs_.clear();
  534. }
  535. /// @brief Implements the receive completion handler.
  536. virtual void operator ()(const NameChangeListener::Result result,
  537. NameChangeRequestPtr& ncr) {
  538. // save the result and the NCR received.
  539. recv_result_ = result;
  540. received_ncrs_.push_back(ncr);
  541. }
  542. /// @brief Implements the send completion handler.
  543. virtual void operator ()(const NameChangeSender::Result result,
  544. NameChangeRequestPtr& ncr) {
  545. // save the result and the NCR sent.
  546. send_result_ = result;
  547. sent_ncrs_.push_back(ncr);
  548. }
  549. // @brief Handler invoked when test timeout is hit.
  550. //
  551. // This callback stops all running (hanging) tasks on IO service.
  552. void testTimeoutHandler() {
  553. io_service_.stop();
  554. FAIL() << "Test timeout hit.";
  555. }
  556. };
  557. /// @brief Uses a sender and listener to test UDP-based NCR delivery
  558. /// Conducts a "round-trip" test using a sender to transmit a set of valid
  559. /// NCRs to a listener. The test verifies that what was sent matches what
  560. /// was received both in quantity and in content.
  561. TEST_F (NameChangeUDPTest, roundTripTest) {
  562. // Place the listener into listening state.
  563. ASSERT_NO_THROW(listener_->startListening(io_service_));
  564. EXPECT_TRUE(listener_->amListening());
  565. // Get the number of messages in the list of test messages.
  566. int num_msgs = sizeof(valid_msgs)/sizeof(char*);
  567. // Place the sender into sending state.
  568. ASSERT_NO_THROW(sender_->startSending(io_service_));
  569. EXPECT_TRUE(sender_->amSending());
  570. for (int i = 0; i < num_msgs; i++) {
  571. NameChangeRequestPtr ncr;
  572. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  573. sender_->sendRequest(ncr);
  574. EXPECT_EQ(i+1, sender_->getQueueSize());
  575. }
  576. // Execute callbacks until we have sent and received all of messages.
  577. while (sender_->getQueueSize() > 0 || (received_ncrs_.size() < num_msgs)) {
  578. EXPECT_NO_THROW(io_service_.run_one());
  579. }
  580. // Send queue should be empty.
  581. EXPECT_EQ(0, sender_->getQueueSize());
  582. // We should have the same number of sends and receives as we do messages.
  583. ASSERT_EQ(num_msgs, sent_ncrs_.size());
  584. ASSERT_EQ(num_msgs, received_ncrs_.size());
  585. // Verify that what we sent matches what we received.
  586. for (int i = 0; i < num_msgs; i++) {
  587. EXPECT_TRUE (checkSendVsReceived(sent_ncrs_[i], received_ncrs_[i]));
  588. }
  589. // Verify that we can gracefully stop listening.
  590. EXPECT_NO_THROW(listener_->stopListening());
  591. EXPECT_FALSE(listener_->amListening());
  592. // Verify that IO pending is false, after cancel event occurs.
  593. EXPECT_NO_THROW(io_service_.run_one());
  594. EXPECT_FALSE(listener_->isIoPending());
  595. // Verify that we can gracefully stop sending.
  596. EXPECT_NO_THROW(sender_->stopSending());
  597. EXPECT_FALSE(sender_->amSending());
  598. }
  599. // Tests error handling of a failure to mark the watch socket ready, when
  600. // sendRequestt() is called.
  601. TEST(NameChangeUDPSenderBasicTest, watchClosedBeforeSendRequest) {
  602. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  603. isc::asiolink::IOService io_service;
  604. SimpleSendHandler ncr_handler;
  605. // Create the sender and put into send mode.
  606. NameChangeUDPSender sender(ip_address, 0, ip_address, LISTENER_PORT,
  607. FMT_JSON, ncr_handler, 100, true);
  608. ASSERT_NO_THROW(sender.startSending(io_service));
  609. ASSERT_TRUE(sender.amSending());
  610. // Create an NCR.
  611. NameChangeRequestPtr ncr;
  612. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[0]));
  613. // Tamper with the watch socket by closing the select-fd.
  614. close(sender.getSelectFd());
  615. // Send should fail as we interferred by closing the select-fd.
  616. ASSERT_THROW(sender.sendRequest(ncr), util::WatchSocketError);
  617. // Verify we didn't invoke the handler.
  618. EXPECT_EQ(0, ncr_handler.pass_count_);
  619. EXPECT_EQ(0, ncr_handler.error_count_);
  620. // Request remains in the queue. Technically it was sent but its
  621. // completion handler won't get called.
  622. EXPECT_EQ(1, sender.getQueueSize());
  623. }
  624. // Tests error handling of a failure to mark the watch socket ready, when
  625. // sendNext() is called during completion handling.
  626. TEST(NameChangeUDPSenderBasicTest, watchClosedAfterSendRequest) {
  627. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  628. isc::asiolink::IOService io_service;
  629. SimpleSendHandler ncr_handler;
  630. // Create the sender and put into send mode.
  631. NameChangeUDPSender sender(ip_address, 0, ip_address, LISTENER_PORT,
  632. FMT_JSON, ncr_handler, 100, true);
  633. ASSERT_NO_THROW(sender.startSending(io_service));
  634. ASSERT_TRUE(sender.amSending());
  635. // Build and queue up 2 messages. No handlers will get called yet.
  636. for (int i = 0; i < 2; i++) {
  637. NameChangeRequestPtr ncr;
  638. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  639. sender.sendRequest(ncr);
  640. EXPECT_EQ(i+1, sender.getQueueSize());
  641. }
  642. // Tamper with the watch socket by closing the select-fd.
  643. close (sender.getSelectFd());
  644. // Run one handler. This should execute the send completion handler
  645. // after sending the first message. Duing completion handling, we will
  646. // attempt to queue the second message which should fail.
  647. ASSERT_NO_THROW(sender.runReadyIO());
  648. // Verify handler got called twice. First request should have be sent
  649. // without error, second call should have failed to send due to watch
  650. // socket markReady failure.
  651. EXPECT_EQ(1, ncr_handler.pass_count_);
  652. EXPECT_EQ(1, ncr_handler.error_count_);
  653. // The second request should still be in the queue.
  654. EXPECT_EQ(1, sender.getQueueSize());
  655. }
  656. // Tests error handling of a failure to clear the watch socket during
  657. // completion handling.
  658. TEST(NameChangeUDPSenderBasicTest, watchSocketBadRead) {
  659. isc::asiolink::IOAddress ip_address(TEST_ADDRESS);
  660. isc::asiolink::IOService io_service;
  661. SimpleSendHandler ncr_handler;
  662. // Create the sender and put into send mode.
  663. NameChangeUDPSender sender(ip_address, 0, ip_address, LISTENER_PORT,
  664. FMT_JSON, ncr_handler, 100, true);
  665. ASSERT_NO_THROW(sender.startSending(io_service));
  666. ASSERT_TRUE(sender.amSending());
  667. // Build and queue up 2 messages. No handlers will get called yet.
  668. for (int i = 0; i < 2; i++) {
  669. NameChangeRequestPtr ncr;
  670. ASSERT_NO_THROW(ncr = NameChangeRequest::fromJSON(valid_msgs[i]));
  671. sender.sendRequest(ncr);
  672. EXPECT_EQ(i+1, sender.getQueueSize());
  673. }
  674. // Fetch the sender's select-fd.
  675. int select_fd = sender.getSelectFd();
  676. // Verify that select_fd appears ready.
  677. ASSERT_TRUE(selectCheck(select_fd) > 0);
  678. // Interfere by reading part of the marker from the select-fd.
  679. uint32_t buf = 0;
  680. ASSERT_EQ((read (select_fd, &buf, 1)), 1);
  681. ASSERT_NE(util::WatchSocket::MARKER, buf);
  682. // Run one handler. This should execute the send completion handler
  683. // after sending the message. Duing completion handling clearing the
  684. // watch socket should fail, which will close the socket, but not
  685. // result in a throw.
  686. ASSERT_NO_THROW(sender.runReadyIO());
  687. // Verify handler got called twice. First request should have be sent
  688. // without error, second call should have failed to send due to watch
  689. // socket markReady failure.
  690. EXPECT_EQ(1, ncr_handler.pass_count_);
  691. EXPECT_EQ(1, ncr_handler.error_count_);
  692. // The second request should still be in the queue.
  693. EXPECT_EQ(1, sender.getQueueSize());
  694. }
  695. } // end of anonymous namespace