2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-14 00:42:53 +00:00

Added coroutines to integration tests

Changed all prepared_statement functions to not use auto return type
declaration
Fixed wrong return value in prepared_statement::execute
This commit is contained in:
ruben
2020-03-28 16:06:36 +00:00
parent f57de875ef
commit 09f7bd9aed
14 changed files with 174 additions and 24 deletions

View File

@@ -15,6 +15,7 @@ Handshake
SSL
compression
Usability
Static asserts for completion tokens
Connection quit
Incomplete query reads: how does this affect further queries?
Metadata in rows: being able to index by name

View File

@@ -31,7 +31,7 @@ void main_impl(int argc, char** argv)
// TCP and MySQL level connect
boost::asio::io_context ctx;
boost::mysql::tcp_connection conn (ctx);
conn.next_level().connect(ep);
conn.next_layer().connect(ep);
conn.handshake(params);
// Issue the query

View File

@@ -39,7 +39,7 @@ void main_impl(int argc, char** argv)
// Declare the connection object and authenticate to the server
boost::mysql::tcp_connection conn (ctx);
conn.next_level().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
conn.next_layer().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
conn.handshake(params); // Authenticates to the MySQL server
/**

View File

@@ -64,7 +64,7 @@ public:
void connect()
{
connection.next_level().async_connect(ep, [this](error_code err) {
connection.next_layer().async_connect(ep, [this](error_code err) {
die_on_error(err);
connection.async_handshake(conn_params, [this](error_code err, const error_info& info) {
die_on_error(err, info);

View File

@@ -68,7 +68,7 @@ void main_impl(int argc, char** argv)
boost::mysql::error_code ec;
// TCP connect
conn.next_level().async_connect(ep, yield[ec]);
conn.next_layer().async_connect(ep, yield[ec]);
check_error(ec);
// MySQL handshake

View File

@@ -65,7 +65,7 @@ void main_impl(int argc, char** argv)
* - Authenticating to the MySQL server.
*/
boost::mysql::tcp_connection conn (ctx);
conn.next_level().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
conn.next_layer().connect(ep); // next_level() returns a boost::asio::ip::tcp::socket
conn.handshake(params); // Authenticates to the MySQL server
/**

View File

@@ -67,7 +67,7 @@ class connection
{
using channel_type = detail::channel<Stream>;
Stream next_level_;
Stream next_layer_;
channel_type channel_;
public:
/**
@@ -76,16 +76,16 @@ public:
*/
template <typename... Args>
connection(Args&&... args) :
next_level_(std::forward<Args>(args)...),
channel_(next_level_)
next_layer_(std::forward<Args>(args)...),
channel_(next_layer_)
{
}
/// Retrieves the underlying Stream object.
Stream& next_level() { return next_level_; }
Stream& next_layer() { return next_layer_; }
/// Retrieves the underlying Stream object.
const Stream& next_level() const { return next_level_; }
const Stream& next_layer() const { return next_layer_; }
/// Performs the MySQL-level handshake (synchronous with error code version).
void handshake(const connection_params& params, error_code& ec, error_info& info);

View File

@@ -74,7 +74,11 @@ boost::mysql::resultset<Stream> boost::mysql::prepared_statement<Stream>::execut
template <typename StreamType>
template <typename ForwardIterator, typename CompletionToken>
auto boost::mysql::prepared_statement<StreamType>::async_execute(
BOOST_ASIO_INITFN_RESULT_TYPE(
CompletionToken,
typename boost::mysql::prepared_statement<StreamType>::execute_signature
)
boost::mysql::prepared_statement<StreamType>::async_execute(
ForwardIterator params_first,
ForwardIterator params_last,
CompletionToken&& token
@@ -89,7 +93,8 @@ auto boost::mysql::prepared_statement<StreamType>::async_execute(
using HandlerArg = async_handler_arg<resultset<StreamType>>;
using HandlerSignature = void(error_code, HandlerArg);
boost::asio::async_completion<CompletionToken, HandlerSignature> completion (token);
return boost::asio::post(
// TODO: is executor correctly preserved here?
boost::asio::post(
channel_->next_layer().get_executor(),
boost::beast::bind_front_handler(
std::move(completion.completion_handler),
@@ -97,6 +102,7 @@ auto boost::mysql::prepared_statement<StreamType>::async_execute(
HandlerArg(std::move(info))
)
);
return completion.result.get();
}
// Actually execute the statement
@@ -133,7 +139,11 @@ void boost::mysql::prepared_statement<StreamType>::close()
template <typename StreamType>
template <typename CompletionToken>
auto boost::mysql::prepared_statement<StreamType>::async_close(
BOOST_ASIO_INITFN_RESULT_TYPE(
CompletionToken,
typename boost::mysql::prepared_statement<StreamType>::close_signature
)
boost::mysql::prepared_statement<StreamType>::async_close(
CompletionToken&& token
)
{

View File

@@ -59,6 +59,12 @@ public:
prepared_statement(detail::channel<Stream>& chan, const detail::com_stmt_prepare_ok_packet& msg) noexcept:
channel_(&chan), stmt_msg_(msg) {}
/// Retrieves the stream object associated with the underlying connection.
Stream& next_layer() noexcept { assert(channel_); return channel_->next_layer(); }
/// Retrieves the stream object associated with the underlying connection.
const Stream& next_layer() const noexcept { assert(channel_); return channel_->next_layer(); }
/// Returns true if the statement is not a default-constructed object.
bool valid() const noexcept { return channel_ != nullptr; }
@@ -86,13 +92,17 @@ public:
return execute(std::begin(params), std::end(params));
}
/// The handler signature for execute.
using execute_signature = void(error_code, async_handler_arg<resultset<Stream>>);
/**
* \brief Executes a statement (collection, sync with exceptions code version).
* \details It is **not** necessary to keep the collection of parameters or the
* values they may point to alive.
*/
template <typename Collection, typename CompletionToken>
auto async_execute(const Collection& params, CompletionToken&& token) const
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, execute_signature)
async_execute(const Collection& params, CompletionToken&& token) const
{
return async_execute(std::begin(params), std::end(params), std::forward<CompletionToken>(token));
}
@@ -118,7 +128,8 @@ public:
* by the elements of the sequence need **not** be kept alive.
*/
template <typename ForwardIterator, typename CompletionToken>
auto async_execute(ForwardIterator params_first, ForwardIterator params_last, CompletionToken&& token) const;
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, execute_signature)
async_execute(ForwardIterator params_first, ForwardIterator params_last, CompletionToken&& token) const;
/**
* \brief Closes a prepared statement, deallocating it from the server (sync with error code version).
@@ -137,9 +148,13 @@ public:
/// Closes a prepared statement, deallocating it from the server (sync with exceptions version).
void close();
/// The handler signature for close.
using close_signature = void(error_code, error_info);
/// Closes a prepared statement, deallocating it from the server (async version).
template <typename CompletionToken>
auto async_close(CompletionToken&& token);
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, close_signature)
async_close(CompletionToken&& token);
};
/// A prepared statement associated to a TCP connection to the MySQL server.

View File

@@ -70,6 +70,12 @@ public:
resultset(channel_type& channel, detail::bytestring&& buffer, const detail::ok_packet& ok_pack):
channel_(&channel), buffer_(std::move(buffer)), ok_packet_(ok_pack), eof_received_(true) {};
/// Retrieves the stream object associated with the underlying connection.
StreamType& next_layer() noexcept { assert(channel_); return channel_->next_layer(); }
/// Retrieves the stream object associated with the underlying connection.
const StreamType& next_layer() const noexcept { assert(channel_); return channel_->next_layer(); }
/**
* \brief Fetches a single row (sync with error code version).
* \details The returned object will be nullptr if there are no more rows

View File

@@ -58,6 +58,8 @@ add_test(
)
# Integration testing
find_package(Boost REQUIRED COMPONENTS coroutine)
add_executable(
mysql_integrationtests
integration/metadata_validator.cpp
@@ -78,6 +80,7 @@ target_link_libraries(
gtest_main
gmock
mysql_asio
Boost::coroutine
)
target_include_directories(
mysql_integrationtests

View File

@@ -29,7 +29,7 @@ struct IntegTest : testing::Test
try
{
boost::asio::ip::tcp::endpoint endpoint (boost::asio::ip::address_v4::loopback(), 3306);
conn.next_level().connect(endpoint);
conn.next_layer().connect(endpoint);
}
catch (...) // prevent terminate without an active exception on connect error
{
@@ -42,7 +42,7 @@ struct IntegTest : testing::Test
~IntegTest()
{
error_code code;
conn.next_level().close(code);
conn.next_layer().close(code);
guard.reset();
runner.join();
}

View File

@@ -1,4 +1,5 @@
#include "network_functions.hpp"
#include <boost/asio/spawn.hpp>
#include <future>
using namespace boost::mysql::test;
@@ -12,6 +13,7 @@ using boost::mysql::errc;
using boost::mysql::value;
using boost::mysql::row;
using boost::mysql::owning_row;
using boost::asio::yield_context;
namespace
{
@@ -214,7 +216,7 @@ public:
}
};
class async : public network_functions
class async_callback : public network_functions
{
template <typename R, typename Callable>
static network_result<R> impl(Callable&& cb) {
@@ -238,7 +240,7 @@ class async : public network_functions
return prom.get_future().get();
}
public:
const char* name() const override { return "async"; }
const char* name() const override { return "async_callback"; }
network_result<no_result> handshake(
tcp_connection& conn,
const boost::mysql::connection_params& params
@@ -320,14 +322,125 @@ public:
}
};
class async_coroutine : public network_functions
{
template <typename IoObj, typename Callable>
static auto impl(IoObj& obj, Callable&& cb) {
using R = typename decltype(cb(std::declval<yield_context>()))::value_type;
auto executor = obj.next_layer().get_executor();
std::promise<network_result<R>> prom;
boost::asio::spawn(executor, [&](yield_context yield) {
error_code ec;
auto result = cb(yield[ec]);
prom.set_value(network_result<R>{ec, std::move(result.error()), std::move(result.get())});
});
return prom.get_future().get();
}
template <typename IoObj, typename Callable>
static network_result<no_result> impl_no_result(IoObj& obj, Callable&& cb) {
auto executor = obj.next_layer().get_executor();
std::promise<network_result<no_result>> prom;
boost::asio::spawn(executor, [&](yield_context yield) {
error_code ec;
error_info info = cb(yield[ec]);
prom.set_value(network_result<no_result>{ec, std::move(info), no_result()});
});
return prom.get_future().get();
}
public:
const char* name() const override { return "async_coroutine"; }
network_result<no_result> handshake(
tcp_connection& conn,
const boost::mysql::connection_params& params
) override
{
return impl_no_result(conn, [&](yield_context yield) {
return conn.async_handshake(params, yield);
});
}
network_result<tcp_resultset> query(
tcp_connection& conn,
std::string_view query
) override
{
return impl(conn, [&](yield_context yield) {
return conn.async_query(query, yield);
});
}
network_result<tcp_prepared_statement> prepare_statement(
tcp_connection& conn,
std::string_view statement
) override
{
return impl(conn, [&](yield_context yield) {
return conn.async_prepare_statement(statement, yield);
});
}
network_result<tcp_resultset> execute_statement(
tcp_prepared_statement& stmt,
value_list_it params_first,
value_list_it params_last
) override
{
return impl(stmt, [&](yield_context yield) {
return stmt.async_execute(params_first, params_last, yield);
});
}
network_result<tcp_resultset> execute_statement(
tcp_prepared_statement& stmt,
const std::vector<value>& values
) override
{
return impl(stmt, [&](yield_context yield) {
return stmt.async_execute(values, yield);
});
}
network_result<no_result> close_statement(
tcp_prepared_statement& stmt
) override
{
return impl_no_result(stmt, [&](yield_context yield) {
return stmt.async_close(yield);
});
}
network_result<const row*> fetch_one(
tcp_resultset& r
) override
{
return impl(r, [&](yield_context yield) {
return r.async_fetch_one(yield);
});
}
network_result<std::vector<owning_row>> fetch_many(
tcp_resultset& r,
std::size_t count
) override
{
return impl(r, [&](yield_context yield) {
return r.async_fetch_many(count, yield);
});
}
network_result<std::vector<owning_row>> fetch_all(
tcp_resultset& r
) override
{
return impl(r, [&](yield_context yield) {
return r.async_fetch_all(yield);
});
}
};
// Global objects to be exposed
sync_errc sync_errc_obj;
sync_exc sync_exc_obj;
async async_obj;
async_callback async_callback_obj;
async_coroutine async_coroutine_obj;
}
// Visible stuff
boost::mysql::test::network_functions* boost::mysql::test::sync_errc_network_functions = &sync_errc_obj;
boost::mysql::test::network_functions* boost::mysql::test::sync_exc_network_functions = &sync_exc_obj;
boost::mysql::test::network_functions* boost::mysql::test::async_network_functions = &async_obj;
boost::mysql::test::network_functions* boost::mysql::test::async_callback_network_functions = &async_callback_obj;
boost::mysql::test::network_functions* boost::mysql::test::async_coroutine_network_functions = &async_coroutine_obj;

View File

@@ -66,12 +66,14 @@ public:
extern network_functions* sync_errc_network_functions;
extern network_functions* sync_exc_network_functions;
extern network_functions* async_network_functions;
extern network_functions* async_callback_network_functions;
extern network_functions* async_coroutine_network_functions;
inline network_functions* all_network_functions [] = {
sync_errc_network_functions,
sync_exc_network_functions,
async_network_functions
async_callback_network_functions,
async_coroutine_network_functions
};
#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \