udpdns_unittest.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright (C) 2010 CZ.NIC
  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 <gtest/gtest.h>
  15. #include <asio.hpp>
  16. #include <boost/bind.hpp>
  17. #include <cstdlib>
  18. #include <dns/question.h>
  19. #include <asiolink/internal/udpdns.h>
  20. using namespace asio;
  21. using namespace isc::dns;
  22. using asio::ip::udp;
  23. namespace {
  24. const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
  25. const uint16_t TEST_PORT(5301);
  26. // FIXME Shouldn't we send something that is real message?
  27. const char TEST_DATA[] = "TEST DATA";
  28. // Test fixture for the asiolink::UDPQuery.
  29. class UDPQueryTest : public ::testing::Test,
  30. public asiolink::UDPQuery::Callback
  31. {
  32. public:
  33. // Expected result of the callback
  34. asiolink::UDPQuery::Result expected_;
  35. // Did the callback run already?
  36. bool run_;
  37. // We use an io_service to run the query
  38. io_service service_;
  39. // Something to ask
  40. Question question_;
  41. // Buffer where the UDPQuery will store response
  42. OutputBufferPtr buffer_;
  43. // The query we are testing
  44. asiolink::UDPQuery query_;
  45. UDPQueryTest() :
  46. run_(false),
  47. question_(Name("example.net"), RRClass::IN(), RRType::A()),
  48. buffer_(new OutputBuffer(512)),
  49. query_(service_, question_, asiolink::IOAddress(TEST_HOST),
  50. TEST_PORT, buffer_, this, 100)
  51. { }
  52. // This is the callback's (), so it can be called.
  53. void operator()(asiolink::UDPQuery::Result result) {
  54. // We check the query returns the correct result
  55. EXPECT_EQ(expected_, result);
  56. // Check it is called only once
  57. EXPECT_FALSE(run_);
  58. // And mark the callback was called
  59. run_ = true;
  60. }
  61. // A response handler, pretending to be remote DNS server
  62. void respond(udp::endpoint* remote, udp::socket* socket) {
  63. // Some data came, just send something back.
  64. socket->send_to(asio::buffer(TEST_DATA, sizeof TEST_DATA),
  65. *remote);
  66. socket->close();
  67. }
  68. };
  69. /*
  70. * Test that when we run the query and stop it after it was run,
  71. * it returns "stopped" correctly.
  72. *
  73. * That is why stop() is posted to the service_ as well instead
  74. * of calling it.
  75. */
  76. TEST_F(UDPQueryTest, stop) {
  77. expected_ = asiolink::UDPQuery::STOPPED;
  78. // Post the query
  79. service_.post(query_);
  80. // Post query_.stop() (yes, the boost::bind thing is just
  81. // query_.stop()).
  82. service_.post(boost::bind(&asiolink::UDPQuery::stop, query_,
  83. asiolink::UDPQuery::STOPPED));
  84. // Run both of them
  85. service_.run();
  86. EXPECT_TRUE(run_);
  87. }
  88. /*
  89. * Test that when we queue the query to service_ and call stop()
  90. * before it gets executed, it acts sanely as well (eg. has the
  91. * same result as running stop() after - calls the callback).
  92. */
  93. TEST_F(UDPQueryTest, prematureStop) {
  94. expected_ = asiolink::UDPQuery::STOPPED;
  95. // Stop before it is started
  96. query_.stop();
  97. service_.post(query_);
  98. service_.run();
  99. EXPECT_TRUE(run_);
  100. }
  101. /*
  102. * Test that it will timeout when no answer will arrive.
  103. */
  104. TEST_F(UDPQueryTest, timeout) {
  105. expected_ = asiolink::UDPQuery::TIME_OUT;
  106. service_.post(query_);
  107. service_.run();
  108. EXPECT_TRUE(run_);
  109. }
  110. /*
  111. * Test that it will succeed when we fake an answer and
  112. * stores the same data we send.
  113. *
  114. * This is done through a real socket on loopback address.
  115. */
  116. TEST_F(UDPQueryTest, receive) {
  117. expected_ = asiolink::UDPQuery::SUCCESS;
  118. udp::socket socket(service_, udp::v4());
  119. socket.set_option(socket_base::reuse_address(true));
  120. socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
  121. char inbuff[512];
  122. udp::endpoint remote;
  123. socket.async_receive_from(asio::buffer(inbuff, 512), remote, boost::bind(
  124. &UDPQueryTest::respond, this, &remote, &socket));
  125. service_.post(query_);
  126. service_.run();
  127. EXPECT_TRUE(run_);
  128. ASSERT_EQ(sizeof TEST_DATA, buffer_->getLength());
  129. EXPECT_EQ(0, memcmp(TEST_DATA, buffer_->getData(), sizeof TEST_DATA));
  130. }
  131. }