unix_domain_socket_unittest.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #include <config.h>
  7. #include <asiolink/asio_wrapper.h>
  8. #include <asiolink/interval_timer.h>
  9. #include <asiolink/io_service.h>
  10. #include <asiolink/unix_domain_socket.h>
  11. #include <boost/bind.hpp>
  12. #include <gtest/gtest.h>
  13. #include <array>
  14. #include <cstdio>
  15. #include <sstream>
  16. #include <string>
  17. using namespace boost::asio;
  18. using namespace boost::asio::local;
  19. using namespace isc::asiolink;
  20. namespace {
  21. /// @brief Test unix socket file name.
  22. const std::string TEST_SOCKET = "test-socket";
  23. /// @brief Test timeout in ms.
  24. const long TEST_TIMEOUT = 10000;
  25. /// @brief Test fixture class for @ref UnixDomainSocket class.
  26. class UnixDomainSocketTest : public ::testing::Test {
  27. public:
  28. /// @brief Constructor.
  29. ///
  30. /// Removes unix socket descriptor before the test.
  31. UnixDomainSocketTest() : io_service_(),
  32. server_endpoint_(unixSocketFilePath()),
  33. server_acceptor_(io_service_.get_io_service()),
  34. server_socket_(io_service_.get_io_service()),
  35. test_timer_(io_service_) {
  36. removeUnixSocketFile();
  37. test_timer_.setup(boost::bind(&UnixDomainSocketTest::timeoutHandler, this),
  38. TEST_TIMEOUT, IntervalTimer::ONE_SHOT);
  39. }
  40. /// @brief Destructor.
  41. ///
  42. /// Removes unix socket descriptor after the test.
  43. virtual ~UnixDomainSocketTest() {
  44. removeUnixSocketFile();
  45. }
  46. /// @brief Returns socket file path.
  47. static std::string unixSocketFilePath() {
  48. std::ostringstream s;
  49. s << TEST_DATA_BUILDDIR << "/" << TEST_SOCKET;
  50. return (s.str());
  51. }
  52. /// @brief Removes unix socket descriptor.
  53. void removeUnixSocketFile() {
  54. static_cast<void>(remove(unixSocketFilePath().c_str()));
  55. }
  56. /// @brief Creates and binds server socket.
  57. void bindServerSocket() {
  58. server_acceptor_.open();
  59. server_acceptor_.bind(server_endpoint_);
  60. server_acceptor_.listen();
  61. server_acceptor_.async_accept(server_socket_,
  62. boost::bind(&UnixDomainSocketTest::
  63. acceptHandler, this, _1));
  64. }
  65. /// @brief Server acceptor handler.
  66. ///
  67. /// @param ec Error code.
  68. void acceptHandler(const boost::system::error_code& ec) {
  69. if (ec) {
  70. ADD_FAILURE() << ec.message();
  71. }
  72. server_socket_.async_read_some(boost::asio::buffer(&raw_buf_[0],
  73. raw_buf_.size()),
  74. boost::bind(&UnixDomainSocketTest::
  75. readHandler, this, _1, _2));
  76. }
  77. /// @brief Server read handler.
  78. ///
  79. /// @param ec Error code.
  80. /// @param bytes_transferred Number of bytes read.
  81. void readHandler(const boost::system::error_code& ec,
  82. size_t bytes_transferred) {
  83. std::string received(&raw_buf_[0], bytes_transferred);
  84. std::string response("received " + received);
  85. boost::asio::write(server_socket_, boost::asio::buffer(response.c_str(),
  86. response.size()));
  87. io_service_.stop();
  88. }
  89. /// @brief Callback function invoke upon test timeout.
  90. ///
  91. /// It stops the IO service and reports test timeout.
  92. void timeoutHandler() {
  93. ADD_FAILURE() << "Timeout occurred while running the test!";
  94. io_service_.stop();
  95. }
  96. /// @brief IO service used by the tests.
  97. IOService io_service_;
  98. /// @brief Server endpoint.
  99. local::stream_protocol::endpoint server_endpoint_;
  100. /// @brief Server acceptor.
  101. local::stream_protocol::acceptor server_acceptor_;
  102. /// @brief Server side unix domain socket.
  103. stream_protocol::socket server_socket_;
  104. /// @brief Receive buffer.
  105. std::array<char, 1024> raw_buf_;
  106. /// @brief Asynchronous timer service to detect timeouts.
  107. IntervalTimer test_timer_;
  108. };
  109. // This test verifies that the client can send data over the unix
  110. // domain socket and receive a response.
  111. TEST_F(UnixDomainSocketTest, sendReceive) {
  112. // Start the server.
  113. bindServerSocket();
  114. // Setup client side.
  115. UnixDomainSocket socket(io_service_);
  116. ASSERT_NO_THROW(socket.connect(TEST_SOCKET));
  117. // Send "foo".
  118. const std::string outbound_data = "foo";
  119. size_t sent_size = 0;
  120. ASSERT_NO_THROW(sent_size = socket.write(outbound_data.c_str(),
  121. outbound_data.size()));
  122. // Make sure all data have been sent.
  123. ASSERT_EQ(outbound_data.size(), sent_size);
  124. // Run IO service to generate server's response.
  125. io_service_.run();
  126. // Receive response from the socket.
  127. std::array<char, 1024> read_buf;
  128. size_t bytes_read = 0;
  129. ASSERT_NO_THROW(bytes_read = socket.receive(&read_buf[0], read_buf.size()));
  130. std::string response(&read_buf[0], bytes_read);
  131. // The server should prepend "received" to the data we had sent.
  132. EXPECT_EQ("received foo", response);
  133. }
  134. // This test verifies that UnixDomainSocketError exception is thrown
  135. // on attempt to connect, write or receive when the server socket
  136. // is not available.
  137. TEST_F(UnixDomainSocketTest, clientErrors) {
  138. UnixDomainSocket socket(io_service_);
  139. ASSERT_THROW(socket.connect(TEST_SOCKET), UnixDomainSocketError);
  140. const std::string outbound_data = "foo";
  141. ASSERT_THROW(socket.write(outbound_data.c_str(), outbound_data.size()),
  142. UnixDomainSocketError);
  143. std::array<char, 1024> read_buf;
  144. ASSERT_THROW(socket.receive(&read_buf[0], read_buf.size()),
  145. UnixDomainSocketError);
  146. }
  147. // Check that native socket descriptor is returned correctly when
  148. // the socket is connected.
  149. TEST_F(UnixDomainSocketTest, getNative) {
  150. // Start the server.
  151. bindServerSocket();
  152. // Setup client side.
  153. UnixDomainSocket socket(io_service_);
  154. ASSERT_NO_THROW(socket.connect(TEST_SOCKET));
  155. ASSERT_GE(socket.getNative(), 0);
  156. }
  157. // Check that protocol returned is 0.
  158. TEST_F(UnixDomainSocketTest, getProtocol) {
  159. UnixDomainSocket socket(io_service_);
  160. EXPECT_EQ(0, socket.getProtocol());
  161. }
  162. }