added unit test
This commit is contained in:
@@ -22,6 +22,8 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_COMM_PACKET_COMMON_HPP_
|
#ifndef REPERTORY_INCLUDE_COMM_PACKET_COMMON_HPP_
|
||||||
#define REPERTORY_INCLUDE_COMM_PACKET_COMMON_HPP_
|
#define REPERTORY_INCLUDE_COMM_PACKET_COMMON_HPP_
|
||||||
|
|
||||||
|
#include "events/event_system.hpp"
|
||||||
|
#include "events/types/packet_client_timeout.hpp"
|
||||||
#include "utils/common.hpp"
|
#include "utils/common.hpp"
|
||||||
|
|
||||||
namespace repertory::comm {
|
namespace repertory::comm {
|
||||||
@@ -46,6 +48,14 @@ private:
|
|||||||
boost::asio::ip::tcp::socket &sock;
|
boost::asio::ip::tcp::socket &sock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class op_t>
|
||||||
|
inline void run_with_deadline(boost::asio::io_context &io_ctx,
|
||||||
|
boost::asio::ip::tcp::socket &sock,
|
||||||
|
op_t operation,
|
||||||
|
std::chrono::milliseconds deadline,
|
||||||
|
const std::string &event_name,
|
||||||
|
const std::string &function_name);
|
||||||
|
|
||||||
void apply_common_socket_properties(boost::asio::ip::tcp::socket &sock);
|
void apply_common_socket_properties(boost::asio::ip::tcp::socket &sock);
|
||||||
|
|
||||||
[[nodiscard]] auto is_socket_still_alive(boost::asio::ip::tcp::socket &sock)
|
[[nodiscard]] auto is_socket_still_alive(boost::asio::ip::tcp::socket &sock)
|
||||||
@@ -66,6 +76,59 @@ void write_all_with_deadline(boost::asio::io_context &io_ctx,
|
|||||||
boost::asio::ip::tcp::socket &sock,
|
boost::asio::ip::tcp::socket &sock,
|
||||||
boost::asio::mutable_buffer buf,
|
boost::asio::mutable_buffer buf,
|
||||||
std::chrono::milliseconds deadline);
|
std::chrono::milliseconds deadline);
|
||||||
|
|
||||||
|
template <class op_t>
|
||||||
|
inline void run_with_deadline(boost::asio::io_context &io_ctx,
|
||||||
|
boost::asio::ip::tcp::socket &sock,
|
||||||
|
op_t operation,
|
||||||
|
std::chrono::milliseconds deadline,
|
||||||
|
const std::string &event_name,
|
||||||
|
const std::string &function_name) {
|
||||||
|
deadline = std::max(deadline, std::chrono::milliseconds{250});
|
||||||
|
|
||||||
|
struct request_state final {
|
||||||
|
std::atomic<bool> done{false};
|
||||||
|
std::atomic<bool> timed_out{false};
|
||||||
|
boost::system::error_code err;
|
||||||
|
};
|
||||||
|
auto state = std::make_shared<request_state>();
|
||||||
|
|
||||||
|
boost::asio::steady_timer timer{io_ctx};
|
||||||
|
timer.expires_after(deadline);
|
||||||
|
|
||||||
|
timer.async_wait([state, &sock](auto &&err) {
|
||||||
|
if (not err && not state->done) {
|
||||||
|
state->timed_out = true;
|
||||||
|
boost::system::error_code ignored_ec;
|
||||||
|
[[maybe_unused]] auto res = sock.cancel(ignored_ec);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
operation([state](auto &&err) {
|
||||||
|
state->err = err;
|
||||||
|
state->done = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
io_ctx.restart();
|
||||||
|
while (not state->done && not state->timed_out) {
|
||||||
|
io_ctx.run_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.cancel();
|
||||||
|
|
||||||
|
io_ctx.poll();
|
||||||
|
|
||||||
|
if (state->timed_out) {
|
||||||
|
repertory::event_system::instance().raise<repertory::packet_client_timeout>(
|
||||||
|
std::string(event_name), std::string(function_name));
|
||||||
|
throw std::runtime_error(event_name + " timed-out");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->err) {
|
||||||
|
throw std::runtime_error(event_name + " failed|err|" +
|
||||||
|
state->err.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace repertory::comm
|
} // namespace repertory::comm
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_COMM_PACKET_COMMON_HPP_
|
#endif // REPERTORY_INCLUDE_COMM_PACKET_COMMON_HPP_
|
||||||
|
@@ -21,9 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
#include "comm/packet/common.hpp"
|
#include "comm/packet/common.hpp"
|
||||||
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "events/types/packet_client_timeout.hpp"
|
|
||||||
|
|
||||||
namespace repertory::comm {
|
namespace repertory::comm {
|
||||||
non_blocking_guard::non_blocking_guard(boost::asio::ip::tcp::socket &sock_)
|
non_blocking_guard::non_blocking_guard(boost::asio::ip::tcp::socket &sock_)
|
||||||
: non_blocking(sock_.non_blocking()), sock(sock_) {
|
: non_blocking(sock_.non_blocking()), sock(sock_) {
|
||||||
@@ -83,59 +80,6 @@ void apply_common_socket_properties(boost::asio::ip::tcp::socket &sock) {
|
|||||||
sock.set_option(boost::asio::socket_base::keep_alive(true));
|
sock.set_option(boost::asio::socket_base::keep_alive(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class op_t>
|
|
||||||
static void run_with_deadline(boost::asio::io_context &io_ctx,
|
|
||||||
boost::asio::ip::tcp::socket &sock,
|
|
||||||
op_t &&operation,
|
|
||||||
std::chrono::milliseconds deadline,
|
|
||||||
const std::string &event_name,
|
|
||||||
const std::string &function_name) {
|
|
||||||
deadline = std::max(deadline, std::chrono::milliseconds{250});
|
|
||||||
|
|
||||||
struct request_state final {
|
|
||||||
std::atomic<bool> done{false};
|
|
||||||
std::atomic<bool> timed_out{false};
|
|
||||||
boost::system::error_code err;
|
|
||||||
};
|
|
||||||
auto state = std::make_shared<request_state>();
|
|
||||||
|
|
||||||
boost::asio::steady_timer timer{io_ctx};
|
|
||||||
timer.expires_after(deadline);
|
|
||||||
|
|
||||||
timer.async_wait([state, &sock](auto &&err) {
|
|
||||||
if (not err && not state->done) {
|
|
||||||
state->timed_out = true;
|
|
||||||
boost::system::error_code ignored_ec;
|
|
||||||
[[maybe_unused]] auto res = sock.cancel(ignored_ec);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
operation([state](auto &&err) {
|
|
||||||
state->err = err;
|
|
||||||
state->done = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
io_ctx.restart();
|
|
||||||
while (not state->done && not state->timed_out) {
|
|
||||||
io_ctx.run_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.cancel();
|
|
||||||
|
|
||||||
io_ctx.poll();
|
|
||||||
|
|
||||||
if (state->timed_out) {
|
|
||||||
repertory::event_system::instance().raise<repertory::packet_client_timeout>(
|
|
||||||
std::string(event_name), std::string(function_name));
|
|
||||||
throw std::runtime_error(event_name + " timed-out");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->err) {
|
|
||||||
throw std::runtime_error(event_name + " failed|err|" +
|
|
||||||
state->err.message());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void connect_with_deadline(
|
void connect_with_deadline(
|
||||||
boost::asio::io_context &io_ctx, boost::asio::ip::tcp::socket &sock,
|
boost::asio::io_context &io_ctx, boost::asio::ip::tcp::socket &sock,
|
||||||
boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::results_type
|
boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::results_type
|
||||||
|
74
repertory/repertory_test/src/packet_comm_common_test.cpp
Normal file
74
repertory/repertory_test/src/packet_comm_common_test.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions: The above copyright
|
||||||
|
notice and this permission notice shall be included in all copies or
|
||||||
|
substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",
|
||||||
|
WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
|
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "test_common.hpp"
|
||||||
|
|
||||||
|
#include "comm/packet/common.hpp"
|
||||||
|
|
||||||
|
using namespace repertory;
|
||||||
|
using namespace repertory::comm;
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
TEST(packet_comm_common_test, operation_completes_prior_to_timeout) {
|
||||||
|
boost::asio::io_context io_ctx;
|
||||||
|
tcp::socket sock(io_ctx);
|
||||||
|
|
||||||
|
std::atomic<bool> completed{false};
|
||||||
|
|
||||||
|
auto operation = [&](auto &&handler) {
|
||||||
|
boost::asio::post(io_ctx, [&completed, handler]() {
|
||||||
|
completed = true;
|
||||||
|
handler(boost::system::error_code{});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_NO_THROW(run_with_deadline(io_ctx, sock, operation,
|
||||||
|
std::chrono::milliseconds(300), "read",
|
||||||
|
"packet_deadline_test"));
|
||||||
|
|
||||||
|
EXPECT_TRUE(completed);
|
||||||
|
|
||||||
|
io_ctx.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(packet_comm_common_test, timeout_completes_prior_to_operation) {
|
||||||
|
boost::asio::io_context io_ctx;
|
||||||
|
tcp::socket sock(io_ctx);
|
||||||
|
|
||||||
|
std::atomic<bool> completed{false};
|
||||||
|
|
||||||
|
auto operation = [&](auto &&handler) {
|
||||||
|
auto delayed = std::make_shared<boost::asio::steady_timer>(io_ctx);
|
||||||
|
delayed->expires_after(std::chrono::milliseconds(500));
|
||||||
|
delayed->async_wait([&completed, delayed, handler](auto &&) {
|
||||||
|
completed = true;
|
||||||
|
handler(boost::system::error_code{});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_THROW(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) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
io_ctx.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(completed);
|
||||||
|
}
|
Reference in New Issue
Block a user