diff --git a/repertory/repertory_test/src/packet_comm_common_test.cpp b/repertory/repertory_test/src/packet_comm_common_test.cpp index 56509cdb..79602835 100644 --- a/repertory/repertory_test/src/packet_comm_common_test.cpp +++ b/repertory/repertory_test/src/packet_comm_common_test.cpp @@ -19,10 +19,9 @@ #include "comm/packet/common.hpp" -using namespace repertory; -using namespace repertory::comm; using boost::asio::ip::tcp; +namespace repertory { TEST(packet_comm_common_test, operation_completes_prior_to_timeout) { boost::asio::io_context io_ctx; tcp::socket sock(io_ctx); @@ -36,9 +35,9 @@ TEST(packet_comm_common_test, operation_completes_prior_to_timeout) { }); }; - EXPECT_NO_THROW(run_with_deadline(io_ctx, sock, operation, - std::chrono::milliseconds(300), "read", - "packet_deadline_test")); + EXPECT_NO_THROW(comm::run_with_deadline(io_ctx, sock, operation, + std::chrono::milliseconds(300), + "read", "packet_deadline_test")); EXPECT_TRUE(completed); @@ -60,9 +59,9 @@ TEST(packet_comm_common_test, timeout_completes_prior_to_operation) { }); }; - EXPECT_THROW(run_with_deadline(io_ctx, sock, operation, - std::chrono::milliseconds(300), "read", - "packet_deadline_test"), + EXPECT_THROW(comm::run_with_deadline(io_ctx, sock, operation, + std::chrono::milliseconds(300), "read", + "packet_deadline_test"), std::runtime_error); for (std::uint8_t idx = 0; idx < 80U && not completed; ++idx) { @@ -72,3 +71,102 @@ TEST(packet_comm_common_test, timeout_completes_prior_to_operation) { EXPECT_TRUE(completed); } + +TEST(packet_comm_common_test, idle_socket_considered_alive) { + using boost::asio::ip::tcp; + + boost::asio::io_context io_ctx; + std::uint16_t port{}; + ASSERT_TRUE(utils::get_next_available_port(50000U, port)); + + tcp::acceptor acceptor{io_ctx, tcp::endpoint{tcp::v4(), port}}; + std::shared_ptr server_sock = + std::make_shared(io_ctx); + std::atomic accepted{false}; + + acceptor.async_accept(*server_sock, + [&](const boost::system::error_code &err) { + if (not err) { + accepted = true; + } + }); + + std::thread io_thread{[&]() { io_ctx.run(); }}; + + boost::asio::io_context client_ctx; + tcp::socket client_sock{client_ctx}; + client_sock.connect( + tcp::endpoint{boost::asio::ip::address_v4::loopback(), port}); + + for (int attempt = 0; attempt < 50 and not accepted; ++attempt) { + std::this_thread::sleep_for(std::chrono::milliseconds{2}); + } + ASSERT_TRUE(accepted); + + EXPECT_TRUE(comm::is_socket_still_alive(client_sock)); + + boost::system::error_code ec; + client_sock.shutdown(tcp::socket::shutdown_both, ec); + client_sock.close(ec); + + if (server_sock and server_sock->is_open()) { + server_sock->shutdown(tcp::socket::shutdown_both, ec); + server_sock->close(ec); + } + + acceptor.close(ec); + io_ctx.stop(); + if (io_thread.joinable()) { + io_thread.join(); + } +} + +TEST(packet_comm_common_test, closed_socket_is_not_reused) { + using boost::asio::ip::tcp; + + boost::asio::io_context io_ctx; + std::uint16_t port{}; + ASSERT_TRUE(utils::get_next_available_port(50000U, port)); + + tcp::acceptor acceptor{io_ctx, tcp::endpoint{tcp::v4(), port}}; + std::shared_ptr server_sock = + std::make_shared(io_ctx); + std::atomic accepted{false}; + + acceptor.async_accept(*server_sock, + [&](const boost::system::error_code &err) { + if (not err) { + accepted = true; + } + }); + + std::thread io_thread{[&]() { io_ctx.run(); }}; + + boost::asio::io_context client_ctx; + tcp::socket client_sock{client_ctx}; + client_sock.connect( + tcp::endpoint{boost::asio::ip::address_v4::loopback(), port}); + + for (int attempt = 0; attempt < 50 and not accepted; ++attempt) { + std::this_thread::sleep_for(std::chrono::milliseconds{2}); + } + ASSERT_TRUE(accepted); + + boost::system::error_code ec; + client_sock.shutdown(tcp::socket::shutdown_both, ec); + client_sock.close(ec); + + EXPECT_FALSE(comm::is_socket_still_alive(client_sock)); + + if (server_sock and server_sock->is_open()) { + server_sock->shutdown(tcp::socket::shutdown_both, ec); + server_sock->close(ec); + } + + acceptor.close(ec); + io_ctx.stop(); + if (io_thread.joinable()) { + io_thread.join(); + } +} +} // namespace repertory