mirror of
https://github.com/boostorg/mysql.git
synced 2025-05-12 14:11:41 +00:00
Support for reset_connection
Refactored integration tests network functions Close #141
This commit is contained in:
parent
cc73a0592f
commit
c60de9cee4
7
.github/workflows/fuzz.yml
vendored
7
.github/workflows/fuzz.yml
vendored
@ -1,3 +1,10 @@
|
||||
#
|
||||
# Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
|
||||
name: fuzz
|
||||
|
||||
on:
|
||||
|
@ -1493,6 +1493,71 @@ public:
|
||||
return detail::async_ping_interface(channel_.get(), diag, std::forward<CompletionToken>(token));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resets server-side session state, like variables and prepared statements.
|
||||
* \details
|
||||
* Resets all server-side state for the current session:
|
||||
* \n
|
||||
* \li Rolls back any active transactions and resets autocommit mode.
|
||||
* \li Releases all table locks.
|
||||
* \li Drops all temporary tables.
|
||||
* \li Resets all session system variables to their default values (including the ones set by `SET
|
||||
* NAMES`) and clears all user-defined variables. \li Closes all prepared statements.
|
||||
* \n
|
||||
* A full reference on the affected session state can be found
|
||||
* <a href="https://dev.mysql.com/doc/c-api/8.0/en/mysql-reset-connection.html">here</a>.
|
||||
* \n
|
||||
* This function will not reset the current physical connection and won't cause re-authentication.
|
||||
* It is faster than closing and re-opening a connection.
|
||||
* \n
|
||||
* The connection must be connected and authenticated before calling this function.
|
||||
* This function involves communication with the server, and thus may fail.
|
||||
*/
|
||||
void reset_connection(error_code& err, diagnostics& diag)
|
||||
{
|
||||
detail::reset_connection_interface(channel_.get(), err, diag);
|
||||
}
|
||||
|
||||
/// \copydoc reset_connection
|
||||
void reset_connection()
|
||||
{
|
||||
error_code err;
|
||||
diagnostics diag;
|
||||
reset_connection(err, diag);
|
||||
detail::throw_on_error_loc(err, diag, BOOST_CURRENT_LOCATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* \copydoc reset_connection
|
||||
* \details
|
||||
* \n
|
||||
* \par Handler signature
|
||||
* The handler signature for this operation is `void(boost::mysql::error_code)`.
|
||||
*/
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_reset_connection(CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
|
||||
{
|
||||
return async_reset_connection(shared_diag(), std::forward<CompletionToken>(token));
|
||||
}
|
||||
|
||||
/// \copydoc async_reset_connection
|
||||
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
|
||||
CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_reset_connection(
|
||||
diagnostics& diag,
|
||||
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
|
||||
)
|
||||
{
|
||||
return detail::async_reset_connection_interface(
|
||||
channel_.get(),
|
||||
diag,
|
||||
std::forward<CompletionToken>(token)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Closes the connection to the server.
|
||||
* \details
|
||||
|
@ -685,6 +685,41 @@ async_ping_interface(channel& chan, diagnostics& diag, CompletionToken&& token)
|
||||
return asio::async_initiate<CompletionToken, void(error_code)>(ping_initiation(), token, &chan, &diag);
|
||||
}
|
||||
|
||||
//
|
||||
// reset_connection
|
||||
//
|
||||
BOOST_MYSQL_DECL
|
||||
void reset_connection_erased(channel& chan, error_code& code, diagnostics& diag);
|
||||
|
||||
BOOST_MYSQL_DECL
|
||||
void async_reset_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler);
|
||||
|
||||
struct reset_connection_initiation
|
||||
{
|
||||
template <class Handler>
|
||||
void operator()(Handler&& handler, channel* chan, diagnostics* diag)
|
||||
{
|
||||
async_reset_connection_erased(*chan, *diag, std::forward<Handler>(handler));
|
||||
}
|
||||
};
|
||||
|
||||
inline void reset_connection_interface(channel& chan, error_code& code, diagnostics& diag)
|
||||
{
|
||||
reset_connection_erased(chan, code, diag);
|
||||
}
|
||||
|
||||
template <class CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_reset_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token)
|
||||
{
|
||||
return asio::async_initiate<CompletionToken, void(error_code)>(
|
||||
reset_connection_initiation(),
|
||||
token,
|
||||
&chan,
|
||||
&diag
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// close connection
|
||||
//
|
||||
|
@ -61,7 +61,7 @@ struct ping_op : boost::asio::coroutine
|
||||
BOOST_ASIO_CORO_YIELD chan_.async_read_one(chan_.shared_sequence_number(), std::move(self));
|
||||
|
||||
// Verify it's what we expected
|
||||
self.complete(deserialize_ping_response(buff, chan_.flavor(), diag_));
|
||||
self.complete(deserialize_ok_response(buff, chan_.flavor(), diag_));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -86,7 +86,7 @@ inline void ping_impl(channel& chan, error_code& err, diagnostics& diag)
|
||||
return;
|
||||
|
||||
// Verify it's what we expected
|
||||
err = deserialize_ping_response(response, chan.flavor(), diag);
|
||||
err = deserialize_ok_response(response, chan.flavor(), diag);
|
||||
}
|
||||
|
||||
template <class CompletionToken>
|
||||
|
@ -0,0 +1,109 @@
|
||||
//
|
||||
// Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_MYSQL_IMPL_INTERNAL_NETWORK_ALGORITHMS_RESET_CONNECTION_HPP
|
||||
#define BOOST_MYSQL_IMPL_INTERNAL_NETWORK_ALGORITHMS_RESET_CONNECTION_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/mysql/client_errc.hpp>
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
|
||||
#include <boost/mysql/detail/config.hpp>
|
||||
|
||||
#include <boost/mysql/impl/internal/channel/channel.hpp>
|
||||
#include <boost/mysql/impl/internal/protocol/protocol.hpp>
|
||||
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/coroutine.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
inline void serialize_reset_connection_message(channel& chan)
|
||||
{
|
||||
chan.serialize(reset_connection_command(), chan.reset_sequence_number());
|
||||
}
|
||||
|
||||
struct reset_connection_op : boost::asio::coroutine
|
||||
{
|
||||
channel& chan_;
|
||||
diagnostics& diag_;
|
||||
|
||||
reset_connection_op(channel& chan, diagnostics& diag) noexcept : chan_(chan), diag_(diag) {}
|
||||
|
||||
template <class Self>
|
||||
void operator()(Self& self, error_code err = {}, span<const std::uint8_t> buff = {})
|
||||
{
|
||||
// Error checking
|
||||
if (err)
|
||||
{
|
||||
self.complete(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Regular coroutine body; if there has been an error, we don't get here
|
||||
BOOST_ASIO_CORO_REENTER(*this)
|
||||
{
|
||||
diag_.clear();
|
||||
|
||||
// Serialize the message
|
||||
serialize_reset_connection_message(chan_);
|
||||
|
||||
// Write message
|
||||
BOOST_ASIO_CORO_YIELD chan_.async_write(std::move(self));
|
||||
|
||||
// Read response
|
||||
BOOST_ASIO_CORO_YIELD chan_.async_read_one(chan_.shared_sequence_number(), std::move(self));
|
||||
|
||||
// Verify it's what we expected
|
||||
self.complete(deserialize_ok_response(buff, chan_.flavor(), diag_));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Interface
|
||||
inline void reset_connection_impl(channel& chan, error_code& err, diagnostics& diag)
|
||||
{
|
||||
err.clear();
|
||||
diag.clear();
|
||||
|
||||
// Serialize the message
|
||||
serialize_reset_connection_message(chan);
|
||||
|
||||
// Send it
|
||||
chan.write(err);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
// Read response
|
||||
auto response = chan.read_one(chan.shared_sequence_number(), err);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
// Verify it's what we expected
|
||||
err = deserialize_ok_response(response, chan.flavor(), diag);
|
||||
}
|
||||
|
||||
template <class CompletionToken>
|
||||
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
async_reset_connection_impl(channel& chan, diagnostics& diag, CompletionToken&& token)
|
||||
{
|
||||
return asio::async_compose<CompletionToken, void(error_code)>(
|
||||
reset_connection_op(chan, diag),
|
||||
token,
|
||||
chan
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_IMPL_CLOSE_STATEMENT_HPP_ */
|
@ -84,8 +84,18 @@ struct ping_command
|
||||
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
|
||||
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
|
||||
};
|
||||
|
||||
// Reset connection
|
||||
struct reset_connection_command
|
||||
{
|
||||
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
|
||||
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
|
||||
};
|
||||
|
||||
// Deserializes a response that may be an OK or an error packet.
|
||||
// Applicable for ping and reset connection
|
||||
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code
|
||||
deserialize_ping_response(span<const std::uint8_t> message, db_flavor flavor, diagnostics& diag);
|
||||
deserialize_ok_response(span<const std::uint8_t> message, db_flavor flavor, diagnostics& diag);
|
||||
|
||||
// Query
|
||||
struct query_command
|
||||
|
@ -305,7 +305,14 @@ void boost::mysql::detail::ping_command::serialize(span<std::uint8_t> buff) cons
|
||||
serialize_command_id(buff, 0x0e);
|
||||
}
|
||||
|
||||
boost::mysql::error_code boost::mysql::detail::deserialize_ping_response(
|
||||
// reset connection
|
||||
std::size_t boost::mysql::detail::reset_connection_command::get_size() const noexcept { return 1u; }
|
||||
void boost::mysql::detail::reset_connection_command::serialize(span<std::uint8_t> buff) const noexcept
|
||||
{
|
||||
serialize_command_id(buff, 0x1f);
|
||||
}
|
||||
|
||||
boost::mysql::error_code boost::mysql::detail::deserialize_ok_response(
|
||||
span<const std::uint8_t> message,
|
||||
db_flavor flavor,
|
||||
diagnostics& diag
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <boost/mysql/impl/internal/network_algorithms/read_resultset_head.hpp>
|
||||
#include <boost/mysql/impl/internal/network_algorithms/read_some_rows.hpp>
|
||||
#include <boost/mysql/impl/internal/network_algorithms/read_some_rows_dynamic.hpp>
|
||||
#include <boost/mysql/impl/internal/network_algorithms/reset_connection.hpp>
|
||||
#include <boost/mysql/impl/internal/network_algorithms/start_execution.hpp>
|
||||
|
||||
void boost::mysql::detail::connect_erased(
|
||||
@ -223,6 +224,20 @@ void boost::mysql::detail::async_ping_erased(channel& chan, diagnostics& diag, a
|
||||
async_ping_impl(chan, diag, std::move(handler));
|
||||
}
|
||||
|
||||
void boost::mysql::detail::reset_connection_erased(channel& chan, error_code& code, diagnostics& diag)
|
||||
{
|
||||
reset_connection_impl(chan, code, diag);
|
||||
}
|
||||
|
||||
void boost::mysql::detail::async_reset_connection_erased(
|
||||
channel& chan,
|
||||
diagnostics& diag,
|
||||
any_void_handler handler
|
||||
)
|
||||
{
|
||||
async_reset_connection_impl(chan, diag, std::move(handler));
|
||||
}
|
||||
|
||||
void boost::mysql::detail::close_connection_erased(channel& chan, error_code& code, diagnostics& diag)
|
||||
{
|
||||
close_connection_impl(chan, code, diag);
|
||||
|
@ -10,13 +10,9 @@
|
||||
|
||||
#include <boost/mysql/common_server_errc.hpp>
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
#include <boost/mysql/error_with_diagnostics.hpp>
|
||||
|
||||
#include <boost/mysql/detail/void_t.hpp>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
@ -97,45 +93,6 @@ network_result<R> create_initial_netresult(bool with_diag = true)
|
||||
return res;
|
||||
}
|
||||
|
||||
// The synchronous implementations are common between unit and integ tests
|
||||
template <class R, class... Args>
|
||||
struct netfun_maker_sync_impl
|
||||
{
|
||||
using signature = std::function<network_result<R>(Args...)>;
|
||||
|
||||
template <class Pfn>
|
||||
static signature sync_errc(Pfn fn)
|
||||
{
|
||||
return [fn](Args... args) {
|
||||
auto res = create_initial_netresult<R>();
|
||||
invoke_and_assign(res, fn, std::forward<Args>(args)..., res.err, *res.diag);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
template <class Pfn>
|
||||
static signature sync_exc(Pfn fn)
|
||||
{
|
||||
return [fn](Args... args) {
|
||||
network_result<R> res;
|
||||
try
|
||||
{
|
||||
invoke_and_assign(res, fn, std::forward<Args>(args)...);
|
||||
}
|
||||
catch (const boost::mysql::error_with_diagnostics& err)
|
||||
{
|
||||
res.err = err.code();
|
||||
res.diag = err.get_diagnostics();
|
||||
}
|
||||
catch (const boost::system::system_error& err)
|
||||
{
|
||||
res.err = err.code();
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
inline boost::asio::io_context& get_context(boost::asio::any_io_executor ex) noexcept
|
||||
{
|
||||
return static_cast<boost::asio::io_context&>(ex.context());
|
||||
|
@ -12,16 +12,16 @@
|
||||
|
||||
using namespace boost::mysql::detail;
|
||||
|
||||
static bool parse_ping_response(const uint8_t* data, size_t size) noexcept
|
||||
static bool parse_ok_response(const uint8_t* data, size_t size) noexcept
|
||||
{
|
||||
boost::mysql::diagnostics diag;
|
||||
auto ec = deserialize_ping_response({data, size}, db_flavor::mariadb, diag);
|
||||
auto ec = deserialize_ok_response({data, size}, db_flavor::mariadb, diag);
|
||||
return !ec.failed() && diag.server_message().empty();
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||
{
|
||||
// Note: this code should never throw exceptions, for any kind of input
|
||||
parse_ping_response(data, size);
|
||||
parse_ok_response(data, size);
|
||||
return 0;
|
||||
}
|
Binary file not shown.
@ -77,6 +77,7 @@ public:
|
||||
virtual network_result<void> read_resultset_head(execution_state& st) = 0;
|
||||
virtual network_result<rows_view> read_some_rows(execution_state& st) = 0;
|
||||
virtual network_result<void> ping() = 0;
|
||||
virtual network_result<void> reset_connection() = 0;
|
||||
virtual network_result<void> quit() = 0;
|
||||
virtual network_result<void> close() = 0;
|
||||
|
||||
|
@ -5,69 +5,73 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <boost/mysql/connection.hpp>
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/execution_state.hpp>
|
||||
#include <boost/mysql/handshake_params.hpp>
|
||||
#include <boost/mysql/statement.hpp>
|
||||
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
|
||||
#include "er_impl_common.hpp"
|
||||
#include "test_common/netfun_helpers.hpp"
|
||||
#include "test_common/tracker_executor.hpp"
|
||||
#include "test_integration/er_connection.hpp"
|
||||
#include "test_integration/streams.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using boost::mysql::diagnostics;
|
||||
|
||||
namespace {
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
struct async_callback_maker
|
||||
template <class Stream>
|
||||
class async_callback_connection : public connection_base<Stream>
|
||||
{
|
||||
static constexpr const char* name() { return "async_callback"; }
|
||||
using conn_type = connection<Stream>;
|
||||
using base_type = connection_base<Stream>;
|
||||
|
||||
static void verify_exec_info(executor_info v) { BOOST_TEST(v.total() > 0u); }
|
||||
template <class R, class... Args>
|
||||
using pmem_t = void (conn_type::*)(Args..., diagnostics&, as_network_result<R>&&);
|
||||
|
||||
template <class Signature>
|
||||
struct type;
|
||||
|
||||
template <class R, class Obj, class... Args>
|
||||
struct type<network_result<R>(Obj&, Args...)>
|
||||
template <class R, class... Args>
|
||||
network_result<R> fn_impl(pmem_t<R, Args...> p, Args... args)
|
||||
{
|
||||
using signature = std::function<network_result<R>(Obj&, Args...)>;
|
||||
using async_sig = void (Obj::*)(Args..., diagnostics&, as_network_result<R>&&);
|
||||
executor_info exec_info{};
|
||||
auto res = create_initial_netresult<R>();
|
||||
invoke_polyfill(
|
||||
p,
|
||||
this->conn(),
|
||||
std::forward<Args>(args)...,
|
||||
*res.diag,
|
||||
as_network_result<R>(res, create_tracker_executor(this->conn().get_executor(), &exec_info))
|
||||
);
|
||||
run_until_completion(this->conn().get_executor());
|
||||
BOOST_TEST(exec_info.total() > 0u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static signature call(async_sig fn)
|
||||
{
|
||||
return [fn](Obj& obj, Args... args) {
|
||||
executor_info exec_info{};
|
||||
auto res = create_initial_netresult<R>();
|
||||
invoke_polyfill(
|
||||
fn,
|
||||
obj,
|
||||
std::forward<Args>(args)...,
|
||||
*res.diag,
|
||||
as_network_result<R>(res, create_tracker_executor(obj.get_executor(), &exec_info))
|
||||
);
|
||||
run_until_completion(obj.get_executor());
|
||||
verify_exec_info(exec_info);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_MYSQL_TEST_IMPLEMENT_ASYNC()
|
||||
static constexpr const char* name() noexcept { return "async_callback"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
template <class Stream>
|
||||
void add_async_callback_variant(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
add_variant<async_callback_connection<Stream>>(output);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
void boost::mysql::test::add_async_callback(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
// Spotcheck for both streams
|
||||
static auto tcp = create_async_variant<tcp_socket, async_callback_maker>();
|
||||
static auto tcp_ssl = create_async_variant<tcp_ssl_socket, async_callback_maker>();
|
||||
add_async_callback_variant<tcp_socket>(output);
|
||||
add_async_callback_variant<tcp_ssl_socket>(output);
|
||||
#if BOOST_ASIO_HAS_LOCAL_SOCKETS
|
||||
static auto unix_ssl = create_async_variant<unix_ssl_socket, async_callback_maker>();
|
||||
#endif
|
||||
|
||||
output.push_back(&tcp);
|
||||
output.push_back(&tcp_ssl);
|
||||
#if BOOST_ASIO_HAS_LOCAL_SOCKETS
|
||||
output.push_back(&unix_ssl);
|
||||
add_async_callback_variant<unix_socket>(output);
|
||||
#endif
|
||||
}
|
||||
|
@ -14,46 +14,46 @@
|
||||
#include "test_common/netfun_helpers.hpp"
|
||||
#include "test_integration/streams.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
|
||||
namespace {
|
||||
|
||||
// Coroutines test async without diagnostics overloads
|
||||
struct async_coroutine_maker
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
template <class Stream>
|
||||
class async_coroutine_connection : public connection_base<Stream>
|
||||
{
|
||||
static constexpr const char* name() { return "async_coroutines"; }
|
||||
using conn_type = connection<Stream>;
|
||||
using base_type = connection_base<Stream>;
|
||||
|
||||
template <class Signature>
|
||||
struct type;
|
||||
template <class R, class... Args>
|
||||
using pmem_t = R (conn_type::*)(Args..., boost::asio::yield_context&&);
|
||||
|
||||
template <class R, class Obj, class... Args>
|
||||
struct type<network_result<R>(Obj&, Args...)>
|
||||
template <class R, class... Args>
|
||||
network_result<R> fn_impl(pmem_t<R, Args...> p, Args... args)
|
||||
{
|
||||
using signature = std::function<network_result<R>(Obj&, Args...)>;
|
||||
using async_sig = R (Obj::*)(Args..., boost::asio::yield_context&&);
|
||||
auto res = create_initial_netresult<R>(false);
|
||||
boost::asio::spawn(
|
||||
this->conn().get_executor(),
|
||||
[&](boost::asio::yield_context yield) {
|
||||
invoke_and_assign(res, p, this->conn(), std::forward<Args>(args)..., yield[res.err]);
|
||||
},
|
||||
&rethrow_on_failure
|
||||
);
|
||||
run_until_completion(this->conn().get_executor());
|
||||
return res;
|
||||
}
|
||||
|
||||
static signature call(async_sig fn)
|
||||
{
|
||||
return [fn](Obj& obj, Args... args) {
|
||||
auto res = create_initial_netresult<R>(false);
|
||||
boost::asio::spawn(
|
||||
obj.get_executor(),
|
||||
[&](boost::asio::yield_context yield) {
|
||||
invoke_and_assign(res, fn, obj, std::forward<Args>(args)..., yield[res.err]);
|
||||
},
|
||||
&rethrow_on_failure
|
||||
);
|
||||
run_until_completion(obj.get_executor());
|
||||
return res;
|
||||
};
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_MYSQL_TEST_IMPLEMENT_ASYNC()
|
||||
static constexpr const char* name() noexcept { return "async_coroutines"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
void boost::mysql::test::add_async_coroutines(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
static auto tcp = create_async_variant<tcp_socket, async_coroutine_maker>();
|
||||
output.push_back(&tcp);
|
||||
add_variant<async_coroutine_connection<tcp_socket>>(output);
|
||||
}
|
||||
|
@ -5,41 +5,31 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/tcp_ssl.hpp>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/as_tuple.hpp>
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
#include <boost/asio/co_spawn.hpp>
|
||||
#include <boost/asio/use_awaitable.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <exception>
|
||||
|
||||
#include "er_impl_common.hpp"
|
||||
#include "test_common/netfun_helpers.hpp"
|
||||
#include "test_common/network_result.hpp"
|
||||
#include "test_integration/streams.hpp"
|
||||
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using boost::asio::any_io_executor;
|
||||
using boost::asio::awaitable;
|
||||
using boost::mysql::diagnostics;
|
||||
using boost::mysql::error_code;
|
||||
// C++20 coroutines test async with diagnostics overloads & deferred tokens
|
||||
|
||||
namespace {
|
||||
|
||||
// C++20 coroutines also test default completion tokens.
|
||||
// Default completion tokens can't use the netmaker concept, because
|
||||
// they rely on default function args, which can't be represented with function pointers
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
template <class R>
|
||||
using result_tuple = std::
|
||||
conditional_t<std::is_same_v<R, void>, std::tuple<error_code>, std::tuple<error_code, R>>;
|
||||
|
||||
using token_t = boost::asio::as_tuple_t<boost::asio::use_awaitable_t<>>;
|
||||
|
||||
template <class R>
|
||||
void to_network_result(const std::tuple<error_code, R>& tup, network_result<R>& netresult)
|
||||
{
|
||||
@ -52,114 +42,46 @@ void to_network_result(const std::tuple<error_code>& tup, network_result<void>&
|
||||
netresult.err = std::get<0>(tup);
|
||||
}
|
||||
|
||||
void verify_message(const network_result_base& r)
|
||||
template <class Stream>
|
||||
class async_coroutinecpp20_connection : public connection_base<Stream>
|
||||
{
|
||||
BOOST_TEST(r.diag->server_message() == "diagnostics not cleared properly");
|
||||
}
|
||||
using conn_type = connection<Stream>;
|
||||
using base_type = connection_base<Stream>;
|
||||
|
||||
template <class R>
|
||||
using awaitable_fn = std::function<awaitable<result_tuple<R>>(diagnostics&)>;
|
||||
template <class R, class... Args>
|
||||
using pmem_t = boost::asio::awaitable<result_tuple<R>> (conn_type::*)(Args..., diagnostics&, token_t&&);
|
||||
|
||||
template <class R>
|
||||
network_result<R> impl_aux(any_io_executor ex, awaitable_fn<R> fn)
|
||||
{
|
||||
auto res = create_initial_netresult<R>();
|
||||
|
||||
boost::asio::co_spawn(
|
||||
ex,
|
||||
[&]() -> boost::asio::awaitable<void> {
|
||||
// Create the task
|
||||
auto aw = fn(*res.diag);
|
||||
|
||||
// Verify that initiation didn't have side effects
|
||||
verify_message(res);
|
||||
|
||||
// Run the task
|
||||
auto tup = co_await std::move(aw);
|
||||
to_network_result(tup, res);
|
||||
},
|
||||
// Regular errors are handled via error_code's. This will just
|
||||
// propagate unexpected ones.
|
||||
&rethrow_on_failure
|
||||
);
|
||||
|
||||
run_until_completion(ex);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class Obj, class Callable>
|
||||
auto impl(Obj& obj, Callable&& fn)
|
||||
{
|
||||
using tup_type = typename decltype(fn(std::declval<diagnostics&>()))::value_type;
|
||||
if constexpr (std::tuple_size_v<tup_type> == 1)
|
||||
template <class R, class... Args>
|
||||
network_result<R> fn_impl(pmem_t<R, Args...> p, Args... args)
|
||||
{
|
||||
return impl_aux<void>(obj.get_executor(), fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
return impl_aux<std::tuple_element_t<1, tup_type>>(obj.get_executor(), fn);
|
||||
}
|
||||
}
|
||||
auto res = create_initial_netresult<R>();
|
||||
|
||||
using token_t = boost::asio::as_tuple_t<boost::asio::use_awaitable_t<>>;
|
||||
using stream_type = token_t::as_default_on_t<boost::mysql::tcp_ssl_connection>::stream_type;
|
||||
using conn_type = boost::mysql::connection<stream_type>;
|
||||
boost::asio::co_spawn(
|
||||
this->conn().get_executor(),
|
||||
[&]() -> boost::asio::awaitable<void> {
|
||||
// Create the task
|
||||
auto aw = (this->conn().*p)(std::forward<Args>(args)..., *res.diag, token_t());
|
||||
|
||||
#define BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(fn_name) \
|
||||
[](conn_type& conn, auto&&... args) { \
|
||||
return impl(conn, [&](diagnostics& diag) { \
|
||||
return conn.fn_name(std::forward<decltype(args)>(args)..., diag); \
|
||||
}); \
|
||||
// Verify that initiation didn't have side effects
|
||||
BOOST_TEST(res.diag->server_message() == "diagnostics not cleared properly");
|
||||
|
||||
// Run the task
|
||||
auto tup = co_await std::move(aw);
|
||||
to_network_result(tup, res);
|
||||
},
|
||||
// Regular errors are handled via error_code's. This will just
|
||||
// propagate unexpected ones.
|
||||
&rethrow_on_failure
|
||||
);
|
||||
|
||||
run_until_completion(this->conn().get_executor());
|
||||
return res;
|
||||
}
|
||||
|
||||
function_table<stream_type> create_table()
|
||||
{
|
||||
return {
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_connect),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_handshake),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_query),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_query),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_prepare_statement),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute_statement),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_statement_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_statement_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_close_statement),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_resultset_head),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_some_rows),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_ping),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_quit),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_close),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_execute),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_start_execution),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_resultset_head),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_some_rows),
|
||||
BOOST_MYSQL_ASYNC_COROCPP20_TABLE_ENTRY(async_read_some_rows),
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
template <>
|
||||
constexpr const char* get_stream_name<stream_type>()
|
||||
{
|
||||
return "tcp_ssl_default_tokens";
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr bool supports_ssl<stream_type>()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
BOOST_MYSQL_TEST_IMPLEMENT_ASYNC()
|
||||
static constexpr const char* name() noexcept { return "async_coroutinescpp20"; }
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
@ -167,8 +89,7 @@ constexpr bool supports_ssl<stream_type>()
|
||||
|
||||
void boost::mysql::test::add_async_coroutinescpp20(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
static er_network_variant_impl<stream_type> net_variant{create_table(), "async_coroutinescpp20"};
|
||||
output.push_back(&net_variant);
|
||||
add_variant<async_coroutinecpp20_connection<tcp_ssl_socket>>(output);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -41,167 +41,6 @@ void add_async_callback(std::vector<er_network_variant*>&);
|
||||
void add_async_coroutines(std::vector<er_network_variant*>&);
|
||||
void add_async_coroutinescpp20(std::vector<er_network_variant*>&);
|
||||
|
||||
// Function table
|
||||
template <class Stream>
|
||||
struct function_table
|
||||
{
|
||||
using conn_type = connection<Stream>;
|
||||
using stmt_tuple = bound_statement_tuple<std::tuple<field_view, field_view>>;
|
||||
using stmt_it = bound_statement_iterator_range<fv_list_it>;
|
||||
|
||||
using connect_sig = network_result<
|
||||
void>(conn_type&, const typename Stream::lowest_layer_type::endpoint_type&, const handshake_params&);
|
||||
using handshake_sig = network_result<void>(conn_type&, const handshake_params&);
|
||||
using query_legacy_sig = network_result<void>(conn_type&, string_view, results&);
|
||||
using start_query_legacy_sig = network_result<void>(conn_type&, string_view, execution_state&);
|
||||
using prepare_statement_sig = network_result<statement>(conn_type&, string_view);
|
||||
using execute_stmt_legacy_sig = network_result<
|
||||
void>(conn_type&, const statement&, const std::tuple<field_view, field_view>&, results&);
|
||||
using start_stmt_execution_legacy_tuple_sig = network_result<
|
||||
void>(conn_type&, const statement&, const std::tuple<field_view, field_view>&, execution_state&);
|
||||
using start_stmt_execution_legacy_it_sig =
|
||||
network_result<void>(conn_type&, const statement&, fv_list_it, fv_list_it, execution_state&);
|
||||
using execute_query_sig = network_result<void>(conn_type&, const string_view&, results&);
|
||||
using execute_stmt_tuple_sig = network_result<void>(conn_type&, const stmt_tuple&, results&);
|
||||
using execute_stmt_it_sig = network_result<void>(conn_type&, const stmt_it&, results&);
|
||||
using start_execution_query_sig = network_result<void>(conn_type&, const string_view&, execution_state&);
|
||||
using start_execution_stmt_tuple_sig =
|
||||
network_result<void>(conn_type&, const stmt_tuple&, execution_state&);
|
||||
using start_execution_stmt_it_sig = network_result<void>(conn_type&, const stmt_it&, execution_state&);
|
||||
|
||||
using close_stmt_sig = network_result<void>(conn_type&, const statement&);
|
||||
using read_resultset_head_sig = network_result<void>(conn_type&, execution_state&);
|
||||
using read_some_rows_sig = network_result<rows_view>(conn_type&, execution_state&);
|
||||
using ping_sig = network_result<void>(conn_type&);
|
||||
using quit_sig = network_result<void>(conn_type&);
|
||||
using close_sig = network_result<void>(conn_type&);
|
||||
|
||||
#ifdef BOOST_MYSQL_CXX14
|
||||
using execute_static_sig =
|
||||
network_result<void>(conn_type&, const string_view&, er_connection::static_results_t&);
|
||||
using start_execution_static_sig =
|
||||
network_result<void>(conn_type&, const string_view&, er_connection::static_state_t&);
|
||||
using read_resultset_head_static_sig = network_result<void>(conn_type&, er_connection::static_state_t&);
|
||||
using read_some_rows_static_1_sig =
|
||||
network_result<std::size_t>(conn_type&, er_connection::static_state_t&, boost::span<row_multifield>);
|
||||
using read_some_rows_static_2_sig =
|
||||
network_result<std::size_t>(conn_type&, er_connection::static_state_t&, boost::span<row_2fields>);
|
||||
#endif
|
||||
|
||||
std::function<connect_sig> connect;
|
||||
std::function<handshake_sig> handshake;
|
||||
std::function<query_legacy_sig> query_legacy;
|
||||
std::function<start_query_legacy_sig> start_query_legacy;
|
||||
std::function<prepare_statement_sig> prepare_statement;
|
||||
std::function<execute_stmt_legacy_sig> execute_stmt_legacy;
|
||||
std::function<start_stmt_execution_legacy_tuple_sig> start_stmt_execution_legacy_tuple;
|
||||
std::function<start_stmt_execution_legacy_it_sig> start_stmt_execution_legacy_it;
|
||||
std::function<execute_query_sig> execute_query;
|
||||
std::function<execute_stmt_tuple_sig> execute_stmt_tuple;
|
||||
std::function<execute_stmt_it_sig> execute_stmt_it;
|
||||
std::function<start_execution_query_sig> start_execution_query;
|
||||
std::function<start_execution_stmt_tuple_sig> start_execution_stmt_tuple;
|
||||
std::function<start_execution_stmt_it_sig> start_execution_stmt_it;
|
||||
std::function<close_stmt_sig> close_stmt;
|
||||
std::function<read_resultset_head_sig> read_resultset_head;
|
||||
std::function<read_some_rows_sig> read_some_rows;
|
||||
std::function<ping_sig> ping;
|
||||
std::function<quit_sig> quit;
|
||||
std::function<close_sig> close;
|
||||
|
||||
#ifdef BOOST_MYSQL_CXX14
|
||||
std::function<execute_static_sig> execute_static;
|
||||
std::function<start_execution_static_sig> start_execution_static;
|
||||
std::function<read_resultset_head_static_sig> read_resultset_head_static;
|
||||
std::function<read_some_rows_static_1_sig> read_some_rows_static_1;
|
||||
std::function<read_some_rows_static_2_sig> read_some_rows_static_2;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Note: Netmaker should be a struct with a
|
||||
// public template type called "type", accepting the signature
|
||||
// arguments as template parameters, and having a static call that
|
||||
// takes function pointers and returns a type-erased function
|
||||
// Generate the function table given a sync maker
|
||||
template <class Stream, class Netmaker>
|
||||
function_table<Stream> create_sync_table()
|
||||
{
|
||||
using conn_type = connection<Stream>;
|
||||
using table_t = function_table<Stream>;
|
||||
|
||||
// clang-format off
|
||||
return function_table<Stream>{
|
||||
Netmaker::template type<typename table_t::connect_sig>::call(&conn_type::connect),
|
||||
Netmaker::template type<typename table_t::handshake_sig>::call(&conn_type::handshake),
|
||||
Netmaker::template type<typename table_t::query_legacy_sig>::call(&conn_type::query),
|
||||
Netmaker::template type<typename table_t::start_query_legacy_sig>::call(&conn_type::start_query),
|
||||
Netmaker::template type<typename table_t::prepare_statement_sig>::call(&conn_type::prepare_statement),
|
||||
Netmaker::template type<typename table_t::execute_stmt_legacy_sig>::call(&conn_type::execute_statement),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_tuple_sig>::call(&conn_type::start_statement_execution),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_it_sig>::call(&conn_type::start_statement_execution),
|
||||
Netmaker::template type<typename table_t::execute_query_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_tuple_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_it_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::start_execution_query_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_tuple_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_it_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::close_stmt_sig>::call(&conn_type::close_statement),
|
||||
Netmaker::template type<typename table_t::read_resultset_head_sig>::call(&conn_type::read_resultset_head),
|
||||
Netmaker::template type<typename table_t::read_some_rows_sig>::call(&conn_type::read_some_rows),
|
||||
Netmaker::template type<typename table_t::ping_sig>::call(&conn_type::ping),
|
||||
Netmaker::template type<typename table_t::quit_sig>::call(&conn_type::quit),
|
||||
Netmaker::template type<typename table_t::close_sig>::call(&conn_type::close),
|
||||
#ifdef BOOST_MYSQL_CXX14
|
||||
Netmaker::template type<typename table_t::execute_static_sig>::call(&conn_type::execute),
|
||||
Netmaker::template type<typename table_t::start_execution_static_sig>::call(&conn_type::start_execution),
|
||||
Netmaker::template type<typename table_t::read_resultset_head_static_sig>::call(&conn_type::read_resultset_head),
|
||||
Netmaker::template type<typename table_t::read_some_rows_static_1_sig>::call(&conn_type::read_some_rows),
|
||||
Netmaker::template type<typename table_t::read_some_rows_static_2_sig>::call(&conn_type::read_some_rows),
|
||||
#endif
|
||||
};
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Generate the function table given an async maker
|
||||
template <class Stream, class Netmaker>
|
||||
function_table<Stream> create_async_table()
|
||||
{
|
||||
using conn_type = connection<Stream>;
|
||||
using table_t = function_table<Stream>;
|
||||
|
||||
// clang-format off
|
||||
return function_table<Stream>{
|
||||
Netmaker::template type<typename table_t::connect_sig>::call(&conn_type::async_connect),
|
||||
Netmaker::template type<typename table_t::handshake_sig>::call(&conn_type::async_handshake),
|
||||
Netmaker::template type<typename table_t::query_legacy_sig>::call(&conn_type::async_query),
|
||||
Netmaker::template type<typename table_t::start_query_legacy_sig>::call(&conn_type::async_start_query),
|
||||
Netmaker::template type<typename table_t::prepare_statement_sig>::call(&conn_type::async_prepare_statement),
|
||||
Netmaker::template type<typename table_t::execute_stmt_legacy_sig>::call(&conn_type::async_execute_statement),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_tuple_sig>::call(&conn_type::async_start_statement_execution),
|
||||
Netmaker::template type<typename table_t::start_stmt_execution_legacy_it_sig>::call(&conn_type::async_start_statement_execution),
|
||||
Netmaker::template type<typename table_t::execute_query_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_tuple_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::execute_stmt_it_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::start_execution_query_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_tuple_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::start_execution_stmt_it_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::close_stmt_sig>::call(&conn_type::async_close_statement),
|
||||
Netmaker::template type<typename table_t::read_resultset_head_sig>::call(&conn_type::async_read_resultset_head),
|
||||
Netmaker::template type<typename table_t::read_some_rows_sig>::call(&conn_type::async_read_some_rows),
|
||||
Netmaker::template type<typename table_t::ping_sig>::call(&conn_type::async_ping),
|
||||
Netmaker::template type<typename table_t::quit_sig>::call(&conn_type::async_quit),
|
||||
Netmaker::template type<typename table_t::close_sig>::call(&conn_type::async_close),
|
||||
#ifdef BOOST_MYSQL_CXX14
|
||||
Netmaker::template type<typename table_t::execute_static_sig>::call(&conn_type::async_execute),
|
||||
Netmaker::template type<typename table_t::start_execution_static_sig>::call(&conn_type::async_start_execution),
|
||||
Netmaker::template type<typename table_t::read_resultset_head_static_sig>::call(&conn_type::async_read_resultset_head),
|
||||
Netmaker::template type<typename table_t::read_some_rows_static_1_sig>::call(&conn_type::async_read_some_rows),
|
||||
Netmaker::template type<typename table_t::read_some_rows_static_2_sig>::call(&conn_type::async_read_some_rows),
|
||||
#endif
|
||||
};
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Helpers
|
||||
template <class Stream>
|
||||
connection<Stream> create_connection_impl(
|
||||
@ -236,27 +75,27 @@ connection<Stream> create_connection(
|
||||
);
|
||||
}
|
||||
|
||||
// Implementation for er_connection
|
||||
// Base for implementing er_connection
|
||||
template <class Stream>
|
||||
class er_connection_impl : public er_connection
|
||||
class connection_base : public er_connection
|
||||
{
|
||||
using conn_type = connection<Stream>;
|
||||
|
||||
conn_type conn_;
|
||||
er_network_variant& var_;
|
||||
const function_table<Stream>& table_;
|
||||
|
||||
public:
|
||||
er_connection_impl(
|
||||
using stream_type = Stream;
|
||||
using connection_type = connection<Stream>;
|
||||
using stmt_tuple = bound_statement_tuple<std::tuple<field_view, field_view>>;
|
||||
using stmt_it = bound_statement_iterator_range<fv_list_it>;
|
||||
|
||||
connection_base(
|
||||
boost::asio::any_io_executor executor,
|
||||
boost::asio::ssl::context& ssl_ctx,
|
||||
er_network_variant& var,
|
||||
const function_table<Stream>& table
|
||||
er_network_variant& var
|
||||
)
|
||||
: conn_(create_connection<Stream>(executor, ssl_ctx)), var_(var), table_(table)
|
||||
: conn_(create_connection<Stream>(executor, ssl_ctx)), var_(var)
|
||||
{
|
||||
}
|
||||
|
||||
connection_type& conn() noexcept { return conn_; }
|
||||
|
||||
bool uses_ssl() const override { return conn_.uses_ssl(); }
|
||||
bool is_open() const override { return conn_.stream().lowest_layer().is_open(); }
|
||||
void set_metadata_mode(metadata_mode v) override { conn_.set_meta_mode(v); }
|
||||
@ -273,160 +112,220 @@ public:
|
||||
}
|
||||
er_network_variant& variant() const override { return var_; }
|
||||
|
||||
network_result<void> connect(const handshake_params& params) override
|
||||
{
|
||||
return table_.connect(conn_, get_endpoint<Stream>(), params);
|
||||
}
|
||||
network_result<void> handshake(const handshake_params& params) override
|
||||
{
|
||||
return table_.handshake(conn_, params);
|
||||
}
|
||||
network_result<void> query(string_view query, results& result) override
|
||||
{
|
||||
return table_.query_legacy(conn_, query, result);
|
||||
}
|
||||
network_result<void> start_query(string_view query, execution_state& st) override
|
||||
{
|
||||
return table_.start_query_legacy(conn_, query, st);
|
||||
}
|
||||
network_result<statement> prepare_statement(string_view stmt_sql) override
|
||||
{
|
||||
return table_.prepare_statement(conn_, stmt_sql);
|
||||
}
|
||||
network_result<void> execute_statement(
|
||||
const statement& stmt,
|
||||
field_view param1,
|
||||
field_view param2,
|
||||
results& result
|
||||
) override
|
||||
{
|
||||
return table_.execute_stmt_legacy(conn_, stmt, std::make_tuple(param1, param2), result);
|
||||
}
|
||||
network_result<void> start_statement_execution(
|
||||
const statement& stmt,
|
||||
field_view param1,
|
||||
field_view param2,
|
||||
execution_state& st
|
||||
) override
|
||||
{
|
||||
return table_.start_stmt_execution_legacy_tuple(conn_, stmt, std::make_tuple(param1, param2), st);
|
||||
}
|
||||
network_result<void> start_statement_execution(
|
||||
const statement& stmt,
|
||||
fv_list_it params_first,
|
||||
fv_list_it params_last,
|
||||
execution_state& st
|
||||
) override
|
||||
{
|
||||
return table_.start_stmt_execution_legacy_it(conn_, stmt, params_first, params_last, st);
|
||||
}
|
||||
|
||||
network_result<void> execute(string_view query, results& result) override
|
||||
{
|
||||
return table_.execute_query(conn_, query, result);
|
||||
}
|
||||
network_result<void> execute(
|
||||
bound_statement_tuple<std::tuple<field_view, field_view>> req,
|
||||
results& result
|
||||
) override
|
||||
{
|
||||
return table_.execute_stmt_tuple(conn_, req, result);
|
||||
}
|
||||
network_result<void> execute(bound_statement_iterator_range<fv_list_it> req, results& result) override
|
||||
{
|
||||
return table_.execute_stmt_it(conn_, req, result);
|
||||
}
|
||||
network_result<void> start_execution(string_view query, execution_state& st) override
|
||||
{
|
||||
return table_.start_execution_query(conn_, query, st);
|
||||
}
|
||||
network_result<void> start_execution(
|
||||
bound_statement_tuple<std::tuple<field_view, field_view>> req,
|
||||
execution_state& st
|
||||
) override
|
||||
{
|
||||
return table_.start_execution_stmt_tuple(conn_, req, st);
|
||||
}
|
||||
network_result<void> start_execution(bound_statement_iterator_range<fv_list_it> req, execution_state& st)
|
||||
override
|
||||
{
|
||||
return table_.start_execution_stmt_it(conn_, req, st);
|
||||
}
|
||||
|
||||
network_result<void> close_statement(statement& stmt) override { return table_.close_stmt(conn_, stmt); }
|
||||
network_result<void> read_resultset_head(execution_state& st) override
|
||||
{
|
||||
return table_.read_resultset_head(conn_, st);
|
||||
}
|
||||
network_result<rows_view> read_some_rows(execution_state& st) override
|
||||
{
|
||||
return table_.read_some_rows(conn_, st);
|
||||
}
|
||||
network_result<void> ping() override { return table_.ping(conn_); }
|
||||
network_result<void> quit() override { return table_.quit(conn_); }
|
||||
network_result<void> close() override { return table_.close(conn_); }
|
||||
#ifdef BOOST_MYSQL_CXX14
|
||||
network_result<void> execute(string_view q, static_results_t& result) override
|
||||
{
|
||||
return table_.execute_static(conn_, q, result);
|
||||
}
|
||||
network_result<void> start_execution(string_view q, static_state_t& st) override
|
||||
{
|
||||
return table_.start_execution_static(conn_, q, st);
|
||||
}
|
||||
network_result<void> read_resultset_head(static_state_t& st) override
|
||||
{
|
||||
return table_.read_resultset_head_static(conn_, st);
|
||||
}
|
||||
network_result<std::size_t> read_some_rows(static_state_t& st, boost::span<row_multifield> storage)
|
||||
override
|
||||
{
|
||||
return table_.read_some_rows_static_1(conn_, st, storage);
|
||||
}
|
||||
network_result<std::size_t> read_some_rows(static_state_t& st, boost::span<row_2fields> storage) override
|
||||
{
|
||||
return table_.read_some_rows_static_2(conn_, st, storage);
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
connection_type conn_;
|
||||
er_network_variant& var_;
|
||||
};
|
||||
|
||||
template <class Stream>
|
||||
// Macros to help implementing er_connection
|
||||
#ifdef BOOST_MYSQL_CXX14
|
||||
#define BOOST_MYSQL_TEST_IMPLEMENT_GENERIC_CXX14(prefix) \
|
||||
network_result<void> execute(string_view q, er_connection::static_results_t& result) override \
|
||||
{ \
|
||||
return fn_impl<void, const string_view&, er_connection::static_results_t&>( \
|
||||
&conn_type::prefix##execute, \
|
||||
q, \
|
||||
result \
|
||||
); \
|
||||
} \
|
||||
network_result<void> start_execution(string_view q, er_connection::static_state_t& st) override \
|
||||
{ \
|
||||
return fn_impl<void, const string_view&, er_connection::static_state_t&>( \
|
||||
&conn_type::prefix##start_execution, \
|
||||
q, \
|
||||
st \
|
||||
); \
|
||||
} \
|
||||
network_result<void> read_resultset_head(er_connection::static_state_t& st) override \
|
||||
{ \
|
||||
return fn_impl<void, er_connection::static_state_t&>(&conn_type::prefix##read_resultset_head, st); \
|
||||
} \
|
||||
network_result<std::size_t> read_some_rows( \
|
||||
er_connection::static_state_t& st, \
|
||||
boost::span<row_multifield> storage \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<std::size_t, er_connection::static_state_t&, boost::span<row_multifield>>( \
|
||||
&conn_type::prefix##read_some_rows, \
|
||||
st, \
|
||||
storage \
|
||||
); \
|
||||
} \
|
||||
network_result<std::size_t> read_some_rows( \
|
||||
er_connection::static_state_t& st, \
|
||||
boost::span<row_2fields> storage \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<std::size_t, er_connection::static_state_t&, boost::span<row_2fields>>( \
|
||||
&conn_type::prefix##read_some_rows, \
|
||||
st, \
|
||||
storage \
|
||||
); \
|
||||
}
|
||||
#else
|
||||
#define BOOST_MYSQL_TEST_IMPLEMENT_GENERIC_CXX14(prefix)
|
||||
#endif
|
||||
|
||||
#define BOOST_MYSQL_TEST_IMPLEMENT_GENERIC(prefix) \
|
||||
using connection_base<Stream>::connection_base; \
|
||||
network_result<void> connect(const handshake_params& params) override \
|
||||
{ \
|
||||
return fn_impl< \
|
||||
void, \
|
||||
const typename Stream::lowest_layer_type::endpoint_type&, \
|
||||
const handshake_params&>(&conn_type::prefix##connect, get_endpoint<Stream>(), params); \
|
||||
} \
|
||||
network_result<void> handshake(const handshake_params& params) override \
|
||||
{ \
|
||||
return fn_impl<void, const handshake_params&>(&conn_type::prefix##handshake, params); \
|
||||
} \
|
||||
network_result<void> query(string_view query, results& result) override \
|
||||
{ \
|
||||
return fn_impl<void, string_view, results&>(&conn_type::prefix##query, query, result); \
|
||||
} \
|
||||
network_result<void> start_query(string_view query, execution_state& st) override \
|
||||
{ \
|
||||
return fn_impl<void, string_view, execution_state&>(&conn_type::prefix##start_query, query, st); \
|
||||
} \
|
||||
network_result<statement> prepare_statement(string_view stmt_sql) override \
|
||||
{ \
|
||||
return fn_impl<statement, string_view>(&conn_type::prefix##prepare_statement, stmt_sql); \
|
||||
} \
|
||||
network_result<void> \
|
||||
execute_statement(const statement& stmt, field_view param1, field_view param2, results& result) override \
|
||||
{ \
|
||||
return fn_impl<void, const statement&, const std::tuple<field_view, field_view>&, results&>( \
|
||||
&conn_type::prefix##execute_statement, \
|
||||
stmt, \
|
||||
std::make_tuple(param1, param2), \
|
||||
result \
|
||||
); \
|
||||
} \
|
||||
network_result<void> start_statement_execution( \
|
||||
const statement& stmt, \
|
||||
field_view param1, \
|
||||
field_view param2, \
|
||||
execution_state& st \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<void, const statement&, const std::tuple<field_view, field_view>&, execution_state&>( \
|
||||
&conn_type::prefix##start_statement_execution, \
|
||||
stmt, \
|
||||
std::make_tuple(param1, param2), \
|
||||
st \
|
||||
); \
|
||||
} \
|
||||
network_result<void> start_statement_execution( \
|
||||
const statement& stmt, \
|
||||
fv_list_it params_first, \
|
||||
fv_list_it params_last, \
|
||||
execution_state& st \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<void, const statement&, fv_list_it, fv_list_it, execution_state&>( \
|
||||
&conn_type::prefix##start_statement_execution, \
|
||||
stmt, \
|
||||
params_first, \
|
||||
params_last, \
|
||||
st \
|
||||
); \
|
||||
} \
|
||||
network_result<void> execute(string_view query, results& result) override \
|
||||
{ \
|
||||
return fn_impl<void, const string_view&, results&>(&conn_type::prefix##execute, query, result); \
|
||||
} \
|
||||
network_result<void> execute( \
|
||||
bound_statement_tuple<std::tuple<field_view, field_view>> req, \
|
||||
results& result \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<void, const typename base_type::stmt_tuple&, results&>( \
|
||||
&conn_type::prefix##execute, \
|
||||
req, \
|
||||
result \
|
||||
); \
|
||||
} \
|
||||
network_result<void> execute(bound_statement_iterator_range<fv_list_it> req, results& result) override \
|
||||
{ \
|
||||
return fn_impl<void, const typename base_type::stmt_it&, results&>( \
|
||||
&conn_type::prefix##execute, \
|
||||
req, \
|
||||
result \
|
||||
); \
|
||||
} \
|
||||
network_result<void> start_execution(string_view query, execution_state& st) override \
|
||||
{ \
|
||||
return fn_impl<void, const string_view&, execution_state&>( \
|
||||
&conn_type::prefix##start_execution, \
|
||||
query, \
|
||||
st \
|
||||
); \
|
||||
} \
|
||||
network_result<void> start_execution( \
|
||||
bound_statement_tuple<std::tuple<field_view, field_view>> req, \
|
||||
execution_state& st \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<void, const typename base_type::stmt_tuple&, execution_state&>( \
|
||||
&conn_type::prefix##start_execution, \
|
||||
req, \
|
||||
st \
|
||||
); \
|
||||
} \
|
||||
network_result<void> start_execution( \
|
||||
bound_statement_iterator_range<fv_list_it> req, \
|
||||
execution_state& st \
|
||||
) override \
|
||||
{ \
|
||||
return fn_impl<void, const typename base_type::stmt_it&, execution_state&>( \
|
||||
&conn_type::prefix##start_execution, \
|
||||
req, \
|
||||
st \
|
||||
); \
|
||||
} \
|
||||
network_result<void> close_statement(statement& stmt) override \
|
||||
{ \
|
||||
return fn_impl<void, const statement&>(&conn_type::prefix##close_statement, stmt); \
|
||||
} \
|
||||
network_result<void> read_resultset_head(execution_state& st) override \
|
||||
{ \
|
||||
return fn_impl<void, execution_state&>(&conn_type::prefix##read_resultset_head, st); \
|
||||
} \
|
||||
network_result<rows_view> read_some_rows(execution_state& st) override \
|
||||
{ \
|
||||
return fn_impl<rows_view, execution_state&>(&conn_type::prefix##read_some_rows, st); \
|
||||
} \
|
||||
network_result<void> ping() override { return fn_impl<void>(&conn_type::prefix##ping); } \
|
||||
network_result<void> reset_connection() override \
|
||||
{ \
|
||||
return fn_impl<void>(&conn_type::prefix##reset_connection); \
|
||||
} \
|
||||
network_result<void> quit() override { return fn_impl<void>(&conn_type::prefix##quit); } \
|
||||
network_result<void> close() override { return fn_impl<void>(&conn_type::prefix##close); } \
|
||||
BOOST_MYSQL_TEST_IMPLEMENT_GENERIC_CXX14(prefix)
|
||||
|
||||
// Use these
|
||||
#define BOOST_MYSQL_TEST_IMPLEMENT_SYNC() BOOST_MYSQL_TEST_IMPLEMENT_GENERIC()
|
||||
#define BOOST_MYSQL_TEST_IMPLEMENT_ASYNC() BOOST_MYSQL_TEST_IMPLEMENT_GENERIC(async_)
|
||||
|
||||
// Implementation for er_network_variant
|
||||
template <class ErConnection>
|
||||
class er_network_variant_impl : public er_network_variant
|
||||
{
|
||||
function_table<Stream> table_;
|
||||
const char* variant_name_;
|
||||
|
||||
using conn_type = er_connection_impl<Stream>;
|
||||
using stream_type = typename ErConnection::stream_type;
|
||||
|
||||
public:
|
||||
er_network_variant_impl(function_table<Stream>&& table, const char* name)
|
||||
: table_(std::move(table)), variant_name_(name)
|
||||
{
|
||||
}
|
||||
|
||||
bool supports_ssl() const override { return ::boost::mysql::test::supports_ssl<Stream>(); }
|
||||
bool is_unix_socket() const override { return ::boost::mysql::test::is_unix_socket<Stream>(); }
|
||||
const char* stream_name() const override { return ::boost::mysql::test::get_stream_name<Stream>(); }
|
||||
const char* variant_name() const override { return variant_name_; }
|
||||
bool supports_ssl() const override { return ::boost::mysql::test::supports_ssl<stream_type>(); }
|
||||
bool is_unix_socket() const override { return ::boost::mysql::test::is_unix_socket<stream_type>(); }
|
||||
const char* stream_name() const override { return ::boost::mysql::test::get_stream_name<stream_type>(); }
|
||||
const char* variant_name() const override { return ErConnection::name(); }
|
||||
er_connection_ptr create_connection(boost::asio::any_io_executor ex, boost::asio::ssl::context& ssl_ctx)
|
||||
override
|
||||
{
|
||||
return er_connection_ptr(new conn_type(ex, ssl_ctx, *this, table_));
|
||||
return er_connection_ptr(new ErConnection(std::move(ex), ssl_ctx, *this));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Stream, class Netmaker>
|
||||
er_network_variant_impl<Stream> create_sync_variant()
|
||||
{
|
||||
return er_network_variant_impl<Stream>(create_sync_table<Stream, Netmaker>(), Netmaker::name());
|
||||
}
|
||||
|
||||
template <class Stream, class Netmaker>
|
||||
er_network_variant_impl<Stream> create_async_variant()
|
||||
{
|
||||
return er_network_variant_impl<Stream>(create_async_table<Stream, Netmaker>(), Netmaker::name());
|
||||
}
|
||||
|
||||
// Helpers
|
||||
inline void rethrow_on_failure(std::exception_ptr ptr)
|
||||
{
|
||||
@ -436,6 +335,13 @@ inline void rethrow_on_failure(std::exception_ptr ptr)
|
||||
}
|
||||
}
|
||||
|
||||
template <class ErConnection>
|
||||
void add_variant(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
static er_network_variant_impl<ErConnection> obj;
|
||||
output.push_back(&obj);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
@ -10,45 +10,63 @@
|
||||
#include "test_integration/streams.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using boost::mysql::diagnostics;
|
||||
using boost::mysql::error_code;
|
||||
|
||||
namespace {
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
struct sync_errc_maker
|
||||
template <class Stream>
|
||||
class sync_errc_connection : public connection_base<Stream>
|
||||
{
|
||||
static constexpr const char* name() { return "sync_errc"; }
|
||||
using conn_type = connection<Stream>;
|
||||
using base_type = connection_base<Stream>;
|
||||
|
||||
template <class Signature>
|
||||
struct type;
|
||||
|
||||
template <class R, class Obj, class... Args>
|
||||
struct type<network_result<R>(Obj&, Args...)>
|
||||
// workaround for gcc5
|
||||
template <class R, class... Args>
|
||||
struct pmem
|
||||
{
|
||||
using impl = netfun_maker_sync_impl<R, Obj&, Args...>;
|
||||
using signature = std::function<network_result<R>(Obj&, Args...)>;
|
||||
using sync_sig = R (Obj::*)(Args..., error_code&, diagnostics&);
|
||||
|
||||
static signature call(sync_sig sync) { return impl::sync_errc(sync); }
|
||||
using type = R (conn_type::*)(Args..., error_code&, diagnostics&);
|
||||
};
|
||||
|
||||
template <class R, class... Args>
|
||||
network_result<R> fn_impl(typename pmem<R, Args...>::type p, Args... args)
|
||||
{
|
||||
auto res = create_initial_netresult<R>();
|
||||
invoke_and_assign(res, p, this->conn(), std::forward<Args>(args)..., res.err, *res.diag);
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
// MSVC complains about passing empty tokens, which is valid C++
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4003)
|
||||
#endif
|
||||
BOOST_MYSQL_TEST_IMPLEMENT_SYNC()
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
static constexpr const char* name() noexcept { return "sync_errc"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
template <class Stream>
|
||||
void add_sync_errc_variant(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
add_variant<sync_errc_connection<Stream>>(output);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
void boost::mysql::test::add_sync_errc(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
// Verify that all streams work
|
||||
static auto tcp = create_sync_variant<tcp_socket, sync_errc_maker>();
|
||||
static auto tcp_ssl = create_sync_variant<tcp_ssl_socket, sync_errc_maker>();
|
||||
add_sync_errc_variant<tcp_socket>(output);
|
||||
add_sync_errc_variant<tcp_ssl_socket>(output);
|
||||
#if BOOST_ASIO_HAS_LOCAL_SOCKETS
|
||||
static auto unix = create_sync_variant<unix_socket, sync_errc_maker>();
|
||||
static auto unix_ssl = create_sync_variant<unix_ssl_socket, sync_errc_maker>();
|
||||
#endif
|
||||
|
||||
output.push_back(&tcp);
|
||||
output.push_back(&tcp_ssl);
|
||||
#if BOOST_ASIO_HAS_LOCAL_SOCKETS
|
||||
output.push_back(&unix);
|
||||
output.push_back(&unix_ssl);
|
||||
add_sync_errc_variant<unix_socket>(output);
|
||||
add_sync_errc_variant<unix_ssl_socket>(output);
|
||||
#endif
|
||||
}
|
||||
|
@ -11,31 +11,58 @@
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
|
||||
namespace {
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
struct sync_exc_maker
|
||||
template <class Stream>
|
||||
class sync_exc_connection : public connection_base<Stream>
|
||||
{
|
||||
static constexpr const char* name() { return "sync_exc"; }
|
||||
using conn_type = connection<Stream>;
|
||||
using base_type = connection_base<Stream>;
|
||||
|
||||
template <class Signature>
|
||||
struct type;
|
||||
template <class R, class... Args>
|
||||
using pmem_t = R (conn_type::*)(Args...);
|
||||
|
||||
template <class R, class Obj, class... Args>
|
||||
struct type<network_result<R>(Obj&, Args...)>
|
||||
template <class R, class... Args>
|
||||
network_result<R> fn_impl(pmem_t<R, Args...> p, Args... args)
|
||||
{
|
||||
using impl = netfun_maker_sync_impl<R, Obj&, Args...>;
|
||||
using signature = std::function<network_result<R>(Obj&, Args...)>;
|
||||
using sync_sig = R (Obj::*)(Args...);
|
||||
network_result<R> res;
|
||||
try
|
||||
{
|
||||
invoke_and_assign(res, p, this->conn(), std::forward<Args>(args)...);
|
||||
}
|
||||
catch (const boost::mysql::error_with_diagnostics& err)
|
||||
{
|
||||
res.err = err.code();
|
||||
res.diag = err.get_diagnostics();
|
||||
}
|
||||
catch (const boost::system::system_error& err)
|
||||
{
|
||||
res.err = err.code();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static signature call(sync_sig sync) { return impl::sync_exc(sync); }
|
||||
};
|
||||
public:
|
||||
// MSVC complains about passing empty tokens, which is valid C++
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4003)
|
||||
#endif
|
||||
BOOST_MYSQL_TEST_IMPLEMENT_SYNC()
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
static constexpr const char* name() noexcept { return "sync_exc"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
void boost::mysql::test::add_sync_exc(std::vector<er_network_variant*>& output)
|
||||
{
|
||||
// Spotcheck
|
||||
static auto sync_exc = create_sync_variant<tcp_socket, sync_exc_maker>();
|
||||
output.push_back(&sync_exc);
|
||||
add_variant<sync_exc_connection<tcp_socket>>(output);
|
||||
}
|
||||
|
@ -439,6 +439,23 @@ BOOST_MYSQL_NETWORK_TEST(ping_error, network_fixture, all_network_samples())
|
||||
conn->ping().validate_any_error();
|
||||
}
|
||||
|
||||
// Reset connection: no server error spotcheck.
|
||||
BOOST_MYSQL_NETWORK_TEST(reset_connection_success, network_fixture, all_network_samples())
|
||||
{
|
||||
setup_and_connect(sample.net);
|
||||
|
||||
// Set some variable
|
||||
results result;
|
||||
conn->execute("SET @myvar = 42", result).validate_no_error();
|
||||
|
||||
// Reset connection
|
||||
conn->reset_connection().validate_no_error();
|
||||
|
||||
// The variable has been reset
|
||||
conn->execute("SELECT @myvar", result);
|
||||
BOOST_TEST(result.rows().at(0).at(0).is_null());
|
||||
}
|
||||
|
||||
// Quit connection: no server error spotcheck
|
||||
BOOST_MYSQL_NETWORK_TEST(quit_success, network_fixture, all_network_samples())
|
||||
{
|
||||
|
@ -44,6 +44,7 @@ add_executable(
|
||||
test/network_algorithms/execute.cpp
|
||||
test/network_algorithms/close_statement.cpp
|
||||
test/network_algorithms/ping.cpp
|
||||
test/network_algorithms/reset_connection.cpp
|
||||
test/network_algorithms/read_some_rows_static.cpp
|
||||
|
||||
test/detail/any_stream_impl.cpp
|
||||
@ -61,6 +62,7 @@ add_executable(
|
||||
|
||||
test/misc.cpp
|
||||
test/multifn.cpp
|
||||
test/default_completion_tokens.cpp
|
||||
test/execution_state.cpp
|
||||
test/static_execution_state.cpp
|
||||
test/results.cpp
|
||||
|
@ -52,6 +52,7 @@ run
|
||||
test/network_algorithms/execute.cpp
|
||||
test/network_algorithms/close_statement.cpp
|
||||
test/network_algorithms/ping.cpp
|
||||
test/network_algorithms/reset_connection.cpp
|
||||
test/network_algorithms/read_some_rows_static.cpp
|
||||
|
||||
test/detail/any_stream_impl.cpp
|
||||
@ -69,6 +70,7 @@ run
|
||||
|
||||
test/misc.cpp
|
||||
test/multifn.cpp
|
||||
test/default_completion_tokens.cpp
|
||||
test/execution_state.cpp
|
||||
test/static_execution_state.cpp
|
||||
test/results.cpp
|
||||
|
@ -5,10 +5,13 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_UNIT_NETFUN_MAKER_HPP
|
||||
#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_UNIT_NETFUN_MAKER_HPP
|
||||
#ifndef BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_NETFUN_MAKER_HPP
|
||||
#define BOOST_MYSQL_TEST_UNIT_INCLUDE_TEST_UNIT_NETFUN_MAKER_HPP
|
||||
|
||||
#include <boost/mysql/error_with_diagnostics.hpp>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
#include "test_common/netfun_helpers.hpp"
|
||||
#include "test_common/tracker_executor.hpp"
|
||||
@ -21,10 +24,53 @@ namespace test {
|
||||
// These rely on the stream dispatching completion handlers directly
|
||||
// via post(), which only happens with test_stream.
|
||||
template <class R, class IOObject, class... Args>
|
||||
struct netfun_maker_impl : netfun_maker_sync_impl<R, IOObject, Args...>
|
||||
struct netfun_maker_impl
|
||||
{
|
||||
using signature = std::function<network_result<R>(IOObject&, Args...)>;
|
||||
|
||||
template <class Pfn>
|
||||
static signature sync_errc(Pfn fn)
|
||||
{
|
||||
return [fn](IOObject& obj, Args... args) {
|
||||
auto res = create_initial_netresult<R>();
|
||||
invoke_and_assign(res, fn, obj, std::forward<Args>(args)..., res.err, *res.diag);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
template <class Pfn>
|
||||
static signature sync_exc(Pfn fn)
|
||||
{
|
||||
return [fn](IOObject& obj, Args... args) {
|
||||
network_result<R> res;
|
||||
try
|
||||
{
|
||||
invoke_and_assign(res, fn, obj, std::forward<Args>(args)...);
|
||||
}
|
||||
catch (const boost::mysql::error_with_diagnostics& err)
|
||||
{
|
||||
res.err = err.code();
|
||||
res.diag = err.get_diagnostics();
|
||||
}
|
||||
catch (const boost::system::system_error& err)
|
||||
{
|
||||
res.err = err.code();
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
// Used by channel functions
|
||||
template <class Pfn>
|
||||
static signature sync_errc_noerrinfo(Pfn fn)
|
||||
{
|
||||
return [fn](IOObject& obj, Args... args) {
|
||||
auto res = create_initial_netresult<R>(false);
|
||||
invoke_and_assign(res, fn, obj, std::forward<Args>(args)..., res.err);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
template <class Pfn>
|
||||
static signature async_errinfo(Pfn fn)
|
||||
{
|
||||
@ -65,17 +111,6 @@ struct netfun_maker_impl : netfun_maker_sync_impl<R, IOObject, Args...>
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
// Used by channel functions
|
||||
template <class Pfn>
|
||||
static signature sync_errc_noerrinfo(Pfn fn)
|
||||
{
|
||||
return [fn](IOObject& obj, Args... args) {
|
||||
auto res = create_initial_netresult<R>(false);
|
||||
invoke_and_assign(res, fn, obj, std::forward<Args>(args)..., res.err);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <class R, class Obj, class... Args>
|
@ -19,8 +19,8 @@
|
||||
#include "test_common/buffer_concat.hpp"
|
||||
#include "test_common/printing.hpp"
|
||||
#include "test_unit/create_frame.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::detail;
|
||||
using namespace boost::mysql::test;
|
||||
|
@ -20,8 +20,8 @@
|
||||
#include "test_common/assert_buffer_equals.hpp"
|
||||
#include "test_common/buffer_concat.hpp"
|
||||
#include "test_unit/create_frame.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::detail;
|
||||
using namespace boost::mysql::test;
|
||||
|
@ -19,8 +19,8 @@
|
||||
#include "test_common/printing.hpp"
|
||||
#include "test_unit/create_ok.hpp"
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql;
|
||||
using namespace boost::mysql::test;
|
||||
|
107
test/unit/test/default_completion_tokens.cpp
Normal file
107
test/unit/test/default_completion_tokens.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
//
|
||||
// Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/execution_state.hpp>
|
||||
#include <boost/mysql/field_view.hpp>
|
||||
#include <boost/mysql/handshake_params.hpp>
|
||||
#include <boost/mysql/static_execution_state.hpp>
|
||||
#include <boost/mysql/tcp_ssl.hpp>
|
||||
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <boost/asio/use_awaitable.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace test {
|
||||
|
||||
// Verify that default completion tokens compile.
|
||||
// This is just a spotcheck, this function is never called
|
||||
boost::asio::awaitable<void> test_default_completion_tokens()
|
||||
{
|
||||
using conn_type = boost::asio::use_awaitable_t<>::as_default_on_t<boost::mysql::tcp_ssl_connection>;
|
||||
|
||||
// Connection
|
||||
boost::asio::io_context ctx;
|
||||
boost::asio::ssl::context ssl_ctx(boost::asio::ssl::context::tls_client);
|
||||
conn_type conn{ctx, ssl_ctx};
|
||||
|
||||
// Helpers
|
||||
diagnostics diag;
|
||||
boost::asio::ip::tcp::endpoint ep{};
|
||||
handshake_params params{"user", "pass"};
|
||||
results result;
|
||||
static_execution_state<std::tuple<>> static_st;
|
||||
execution_state st;
|
||||
statement stmt;
|
||||
std::vector<field_view> stmt_params;
|
||||
|
||||
// Tests
|
||||
co_await conn.async_connect(ep, params);
|
||||
co_await conn.async_connect(ep, params, diag);
|
||||
|
||||
co_await conn.async_handshake(params);
|
||||
co_await conn.async_handshake(params, diag);
|
||||
|
||||
co_await conn.async_query("SELECT 1", result);
|
||||
co_await conn.async_query("SELECT 1", result, diag);
|
||||
|
||||
co_await conn.async_start_query("SELECT 1", st);
|
||||
co_await conn.async_start_query("SELECT 1", st, diag);
|
||||
|
||||
co_await conn.async_prepare_statement("SELECT 1");
|
||||
co_await conn.async_prepare_statement("SELECT 1", diag);
|
||||
|
||||
co_await conn.async_execute_statement(stmt, std::make_tuple(), result);
|
||||
co_await conn.async_execute_statement(stmt, std::make_tuple(), result, diag);
|
||||
|
||||
co_await conn.async_start_statement_execution(stmt, std::make_tuple(), st);
|
||||
co_await conn.async_start_statement_execution(stmt, std::make_tuple(), st, diag);
|
||||
|
||||
co_await conn.async_start_statement_execution(stmt, stmt_params.begin(), stmt_params.end(), st);
|
||||
co_await conn.async_start_statement_execution(stmt, stmt_params.begin(), stmt_params.end(), st, diag);
|
||||
|
||||
co_await conn.async_execute("SELECT 1", result);
|
||||
co_await conn.async_execute("SELECT 1", result, diag);
|
||||
|
||||
co_await conn.async_start_execution("SELECT 1", st);
|
||||
co_await conn.async_start_execution("SELECT 1", st, diag);
|
||||
|
||||
co_await conn.async_close_statement(stmt);
|
||||
co_await conn.async_close_statement(stmt, diag);
|
||||
|
||||
co_await conn.async_read_resultset_head(st);
|
||||
co_await conn.async_read_resultset_head(st, diag);
|
||||
|
||||
co_await conn.async_read_some_rows(st);
|
||||
co_await conn.async_read_some_rows(st, diag);
|
||||
|
||||
co_await conn.async_ping();
|
||||
co_await conn.async_ping(diag);
|
||||
|
||||
co_await conn.async_quit();
|
||||
co_await conn.async_quit(diag);
|
||||
|
||||
co_await conn.async_close();
|
||||
co_await conn.async_close(diag);
|
||||
|
||||
co_await conn.async_read_some_rows(static_st, boost::span<std::tuple<>>());
|
||||
co_await conn.async_read_some_rows(static_st, boost::span<std::tuple<>>(), diag);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace mysql
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
@ -23,8 +23,8 @@
|
||||
#include "test_unit/create_ok.hpp"
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/create_row_message.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql;
|
||||
using namespace boost::mysql::test;
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include "test_common/assert_buffer_equals.hpp"
|
||||
#include "test_unit/create_channel.hpp"
|
||||
#include "test_unit/create_statement.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
|
@ -29,9 +29,9 @@
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/create_row_message.hpp"
|
||||
#include "test_unit/mock_execution_processor.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/printing.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include "test_unit/create_frame.hpp"
|
||||
#include "test_unit/create_ok.hpp"
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/create_row_message.hpp"
|
||||
#include "test_unit/mock_execution_processor.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql;
|
||||
using namespace boost::mysql::test;
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/create_row_message.hpp"
|
||||
#include "test_unit/mock_execution_processor.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include "test_unit/create_ok.hpp"
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/create_row_message.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "test_unit/create_meta.hpp"
|
||||
#include "test_unit/create_ok.hpp"
|
||||
#include "test_unit/create_row_message.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
|
111
test/unit/test/network_algorithms/reset_connection.cpp
Normal file
111
test/unit/test/network_algorithms/reset_connection.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#include <boost/mysql/client_errc.hpp>
|
||||
#include <boost/mysql/common_server_errc.hpp>
|
||||
#include <boost/mysql/diagnostics.hpp>
|
||||
#include <boost/mysql/error_code.hpp>
|
||||
|
||||
#include <boost/mysql/impl/internal/channel/channel.hpp>
|
||||
#include <boost/mysql/impl/internal/network_algorithms/reset_connection.hpp>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "test_common/assert_buffer_equals.hpp"
|
||||
#include "test_unit/create_channel.hpp"
|
||||
#include "test_unit/create_err.hpp"
|
||||
#include "test_unit/create_frame.hpp"
|
||||
#include "test_unit/create_ok.hpp"
|
||||
#include "test_unit/create_ok_frame.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
|
||||
using namespace boost::mysql::test;
|
||||
using namespace boost::mysql;
|
||||
using boost::mysql::detail::channel;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(test_reset_connection)
|
||||
|
||||
using netfun_maker = netfun_maker_fn<void, channel&>;
|
||||
|
||||
struct
|
||||
{
|
||||
netfun_maker::signature reset_connection;
|
||||
const char* name;
|
||||
} all_fns[] = {
|
||||
{netfun_maker::sync_errc(&detail::reset_connection_impl), "sync" },
|
||||
{netfun_maker::async_errinfo(&detail::async_reset_connection_impl), "async"},
|
||||
};
|
||||
|
||||
struct fixture
|
||||
{
|
||||
channel chan{create_channel()};
|
||||
|
||||
test_stream& stream() noexcept { return get_stream(chan); }
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_CASE(success)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
fixture fix;
|
||||
fix.stream().add_bytes(create_ok_frame(1, ok_builder().build()));
|
||||
|
||||
// Call the function
|
||||
fns.reset_connection(fix.chan).validate_no_error();
|
||||
|
||||
// Verify the message we sent
|
||||
const std::uint8_t expected_message[] = {0x01, 0x00, 0x00, 0x00, 0x1f};
|
||||
BOOST_MYSQL_ASSERT_BUFFER_EQUALS(fix.stream().bytes_written(), expected_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_network)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
for (int i = 0; i <= 1; ++i)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name << " in network transfer " << i)
|
||||
{
|
||||
fixture fix;
|
||||
fix.stream().set_fail_count(fail_count(i, common_server_errc::er_aborting_connection));
|
||||
|
||||
// Call the function
|
||||
fns.reset_connection(fix.chan).validate_error_exact(common_server_errc::er_aborting_connection
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(error_response)
|
||||
{
|
||||
for (auto fns : all_fns)
|
||||
{
|
||||
BOOST_TEST_CONTEXT(fns.name)
|
||||
{
|
||||
fixture fix;
|
||||
fix.stream().add_bytes(err_builder()
|
||||
.seqnum(1)
|
||||
.code(common_server_errc::er_bad_db_error)
|
||||
.message("my_message")
|
||||
.build_frame());
|
||||
|
||||
// Call the function
|
||||
fns.reset_connection(fix.chan).validate_error_exact(
|
||||
common_server_errc::er_bad_db_error,
|
||||
"my_message"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
@ -27,9 +27,9 @@
|
||||
#include "test_unit/create_meta.hpp"
|
||||
#include "test_unit/create_statement.hpp"
|
||||
#include "test_unit/mock_execution_processor.hpp"
|
||||
#include "test_unit/netfun_maker.hpp"
|
||||
#include "test_unit/printing.hpp"
|
||||
#include "test_unit/test_stream.hpp"
|
||||
#include "test_unit/unit_netfun_maker.hpp"
|
||||
|
||||
using namespace boost::mysql;
|
||||
using namespace boost::mysql::test;
|
||||
|
@ -665,7 +665,18 @@ BOOST_AUTO_TEST_CASE(ping_serialization)
|
||||
do_serialize_toplevel_test(cmd, serialized);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(deserialize_ping_response_)
|
||||
//
|
||||
// reset_connection
|
||||
//
|
||||
BOOST_AUTO_TEST_CASE(reset_connection_serialization)
|
||||
{
|
||||
reset_connection_command cmd;
|
||||
const std::uint8_t serialized[] = {0x1f};
|
||||
do_serialize_toplevel_test(cmd, serialized);
|
||||
}
|
||||
|
||||
// OK response (ping & reset connection)
|
||||
BOOST_AUTO_TEST_CASE(deserialize_ok_response_)
|
||||
{
|
||||
struct
|
||||
{
|
||||
@ -690,7 +701,7 @@ BOOST_AUTO_TEST_CASE(deserialize_ping_response_)
|
||||
BOOST_TEST_CONTEXT(tc.name)
|
||||
{
|
||||
diagnostics diag;
|
||||
auto err = deserialize_ping_response(tc.message, db_flavor::mariadb, diag);
|
||||
auto err = deserialize_ok_response(tc.message, db_flavor::mariadb, diag);
|
||||
|
||||
BOOST_TEST(err == tc.expected_err);
|
||||
BOOST_TEST(diag.server_message() == tc.expected_msg);
|
||||
|
@ -65,7 +65,10 @@ def find_first_blank(lines):
|
||||
|
||||
def read_file(fpath):
|
||||
with open(fpath, 'rt') as f:
|
||||
return f.readlines()
|
||||
try:
|
||||
return f.readlines()
|
||||
except Exception as err:
|
||||
raise SystemError(f'Error processing file {fpath}') from err
|
||||
|
||||
def write_file(fpath, lines):
|
||||
with open(fpath, 'wt') as f:
|
||||
@ -88,6 +91,8 @@ def gen_header(linesym, opensym=None, closesym=None, shebang=None, include_guard
|
||||
return text_to_lines(HEADER_TEMPLATE.format(begin=begin, end=end, linesym=linesym))
|
||||
|
||||
class BaseProcessor(metaclass=ABCMeta):
|
||||
skip = False
|
||||
|
||||
@abstractmethod
|
||||
def process(self, lines: List[str], fpath: str) -> List[str]:
|
||||
return lines
|
||||
@ -176,6 +181,7 @@ class XmlProcessor(BaseProcessor):
|
||||
|
||||
class IgnoreProcessor(BaseProcessor):
|
||||
name = 'ignore'
|
||||
skip = True
|
||||
|
||||
def process(self, lines: List[str], _: str) -> List[str]:
|
||||
return lines
|
||||
@ -217,6 +223,8 @@ FILE_PROCESSORS : List[Tuple[str, BaseProcessor]] = [
|
||||
('.pem', IgnoreProcessor()),
|
||||
('.md', IgnoreProcessor()),
|
||||
('.csv', IgnoreProcessor()),
|
||||
('.tar.gz', IgnoreProcessor()),
|
||||
('.json', IgnoreProcessor()),
|
||||
]
|
||||
|
||||
def process_file(fpath: str):
|
||||
@ -224,10 +232,11 @@ def process_file(fpath: str):
|
||||
if fpath.endswith(ext):
|
||||
if VERBOSE:
|
||||
print('Processing file {} with processor {}'.format(fpath, processor.name))
|
||||
lines = read_file(fpath)
|
||||
output_lines = processor.process(lines, fpath)
|
||||
if output_lines != lines:
|
||||
write_file(fpath, output_lines)
|
||||
if not processor.skip:
|
||||
lines = read_file(fpath)
|
||||
output_lines = processor.process(lines, fpath)
|
||||
if output_lines != lines:
|
||||
write_file(fpath, output_lines)
|
||||
break
|
||||
else:
|
||||
raise ValueError('Could not find a suitable processor for file: ' + fpath)
|
||||
|
@ -53,7 +53,7 @@
|
||||
"msg": "0364656607617765736f6d650a746573745f7461626c650a746573745f7461626c650b6669656c645f666c6f61740b6669656c645f666c6f61740d3f000c0000000400001f000000"
|
||||
}
|
||||
],
|
||||
"fuzz_ping_response": [
|
||||
"fuzz_ok_response": [
|
||||
{
|
||||
"name": "success",
|
||||
"msg": "00010602000000"
|
||||
|
Loading…
x
Reference in New Issue
Block a user