Support for reset_connection

Refactored integration tests network functions

Close #141
This commit is contained in:
Ruben Perez 2023-07-14 16:27:31 +02:00
parent cc73a0592f
commit c60de9cee4
39 changed files with 1006 additions and 630 deletions

View File

@ -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:

View File

@ -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

View File

@ -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
//

View File

@ -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>

View File

@ -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_ */

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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());

View File

@ -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.

View File

@ -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;

View File

@ -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
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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);
}

View File

@ -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())
{

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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;

View 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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View 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()

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -53,7 +53,7 @@
"msg": "0364656607617765736f6d650a746573745f7461626c650a746573745f7461626c650b6669656c645f666c6f61740b6669656c645f666c6f61740d3f000c0000000400001f000000"
}
],
"fuzz_ping_response": [
"fuzz_ok_response": [
{
"name": "success",
"msg": "00010602000000"