From 16347315fe0f6360769eded3c4165bdce13aaa74 Mon Sep 17 00:00:00 2001 From: ruben Date: Fri, 14 Feb 2020 17:37:21 +0000 Subject: [PATCH] Now network tests use an interface Made network tests simpler and much more flexible --- test/CMakeLists.txt | 1 + test/integration/execute_statement.cpp | 76 ++------- test/integration/integration_test_common.hpp | 122 +------------- test/integration/network_functions.cpp | 158 +++++++++++++++++++ test/integration/network_functions.hpp | 79 ++++++++++ test/integration/prepare_statement.cpp | 28 +--- 6 files changed, 262 insertions(+), 202 deletions(-) create mode 100644 test/integration/network_functions.cpp create mode 100644 test/integration/network_functions.hpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index aa425318..e35ae46f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,6 +56,7 @@ add_test( add_executable( mysql_integrationtests integration/metadata_validator.cpp + integration/network_functions.cpp integration/handshake.cpp integration/query.cpp integration/prepare_statement.cpp diff --git a/test/integration/execute_statement.cpp b/test/integration/execute_statement.cpp index 81d5a402..7eb996c7 100644 --- a/test/integration/execute_statement.cpp +++ b/test/integration/execute_statement.cpp @@ -19,112 +19,68 @@ using mysql::tcp_prepared_statement; namespace { +struct ExecuteStatementTest : public NetworkTest<> {}; + // Iterator version -using listit = std::forward_list::const_iterator; -struct ExecuteStatementIteratorTraits -{ - static tcp_resultset sync_errc(const tcp_prepared_statement& stmt, listit first, listit last, - error_code& errc, error_info& info) - { - return stmt.execute(first, last, errc, info); - } - - static tcp_resultset sync_exc(const tcp_prepared_statement& stmt, listit first, listit last) - { - return stmt.execute(first, last); - } - - template - static auto async(const tcp_prepared_statement& stmt, listit first, listit last, CompletionToken&& token) - { - return stmt.async_execute(first, last, std::forward(token)); - } -}; - -struct ExecuteStatementIteratorTest : public NetworkTest {}; - -TEST_P(ExecuteStatementIteratorTest, OkNoParams) +TEST_P(ExecuteStatementTest, Iterator_OkNoParams) { std::forward_list params; auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); - auto result = GetParam().fun(stmt, params.begin(), params.end()); // execute + auto result = GetParam()->execute_statement(stmt, params.begin(), params.end()); // execute result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } -TEST_P(ExecuteStatementIteratorTest, OkWithParams) +TEST_P(ExecuteStatementTest, Iterator_OkWithParams) { std::forward_list params { value("item"), value(42) }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = GetParam().fun(stmt, params.begin(), params.end()); + auto result = GetParam()->execute_statement(stmt, params.begin(), params.end()); result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } -TEST_P(ExecuteStatementIteratorTest, MismatchedNumParams) +TEST_P(ExecuteStatementTest, Iterator_MismatchedNumParams) { std::forward_list params { value("item") }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = GetParam().fun(stmt, params.begin(), params.end()); + auto result = GetParam()->execute_statement(stmt, params.begin(), params.end()); result.validate_error(Error::wrong_num_params, {"param", "2", "1", "statement", "execute"}); EXPECT_FALSE(result.value.valid()); } // TODO: is there any way of making server return an error here? -MYSQL_NETWORK_TEST_SUITE(ExecuteStatementIteratorTest); - // Container version -struct ExecuteStatementContainerTraits -{ - static tcp_resultset sync_errc(const tcp_prepared_statement& stmt, const std::vector& v, - error_code& errc, error_info& info) - { - return stmt.execute(v, errc, info); - } - - static tcp_resultset sync_exc(const tcp_prepared_statement& stmt, const std::vector& v) - { - return stmt.execute(v); - } - - template - static auto async(const tcp_prepared_statement& stmt, const std::vector& v, CompletionToken&& token) - { - return stmt.async_execute(v, std::forward(token)); - } -}; - -struct ExecuteStatementContainerTest : public NetworkTest {}; - -TEST_P(ExecuteStatementContainerTest, OkNoParams) +TEST_P(ExecuteStatementTest, Container_OkNoParams) { auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); - auto result = GetParam().fun(stmt, std::vector()); // execute + auto result = GetParam()->execute_statement(stmt, std::vector()); // execute result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } -TEST_P(ExecuteStatementContainerTest, OkWithParams) +TEST_P(ExecuteStatementTest, Container_OkWithParams) { std::vector params { value("item"), value(42) }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = GetParam().fun(stmt, params); + auto result = GetParam()->execute_statement(stmt, params); result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } -TEST_P(ExecuteStatementContainerTest, MismatchedNumParams) +TEST_P(ExecuteStatementTest, Container_MismatchedNumParams) { std::vector params { value("item") }; auto stmt = conn.prepare_statement("SELECT * FROM empty_table WHERE id IN (?, ?)"); - auto result = GetParam().fun(stmt, params); + auto result = GetParam()->execute_statement(stmt, params); result.validate_error(Error::wrong_num_params, {"param", "2", "1", "statement", "execute"}); EXPECT_FALSE(result.value.valid()); } -MYSQL_NETWORK_TEST_SUITE(ExecuteStatementContainerTest); +MYSQL_NETWORK_TEST_SUITE(ExecuteStatementTest); +// Other containers struct ExecuteStatementOtherContainersTest : IntegTestAfterHandshake {}; TEST_F(ExecuteStatementOtherContainersTest, NoParams_CanUseNoStatementParamsVariable) diff --git a/test/integration/integration_test_common.hpp b/test/integration/integration_test_common.hpp index 92aac754..29d22cc8 100644 --- a/test/integration/integration_test_common.hpp +++ b/test/integration/integration_test_common.hpp @@ -10,6 +10,7 @@ #include #include "test_common.hpp" #include "metadata_validator.hpp" +#include "network_functions.hpp" namespace mysql { @@ -187,128 +188,13 @@ struct IntegTestAfterHandshake : IntegTest IntegTestAfterHandshake() { handshake(); } }; -template -struct NetworkResult +template +struct NetworkTest : public BaseType, + public testing::WithParamInterface { - error_code errc; - error_info info; - T value; - - void validate_no_error() const - { - ASSERT_EQ(errc, error_code()); - EXPECT_EQ(info, error_info()); - } - - void validate_error( - error_code expected_errc, - const std::vector& expected_msg - ) const - { - EXPECT_EQ(errc, expected_errc); - validate_string_contains(info.message(), expected_msg); - } - - void validate_error( - Error expected_errc, - const std::vector& expected_msg - ) const - { - validate_error(detail::make_error_code(expected_errc), expected_msg); - } -}; - -template -struct NetworkFunction : named_param -{ - std::string name; - std::function(Args...)> fun; - - template - NetworkFunction(std::string name, Callable&& cb): - name(std::move(name)), fun(std::forward(cb)) {} -}; - -template -class get_network_function_type -{ - template - static NetworkFunction helper(R(*)(Args...)); -public: - using type = decltype(helper(&TraitsType::sync_exc)); -}; - -template -using traits_network_function = typename get_network_function_type::type; - -template -struct printer -{ - static_assert(std::is_same_v); -}; - -template -auto make_network_functions_impl(R(*)(Args...)) -{ - using NetResultType = NetworkResult; - using NetFunType = NetworkFunction; - auto sync_errc = [](Args... args) { - NetResultType res; - res.errc = detail::make_error_code(Error::no); - res.info.set_message("Error info not cleared correctly"); - res.value = TraitsType::sync_errc(std::forward(args)..., res.errc, res.info); - return res; - }; - auto sync_exc = [](Args... args) { - NetResultType res; - try - { - res.value = TraitsType::sync_exc(std::forward(args)...); - } - catch (const boost::system::system_error& err) - { - res.errc = err.code(); - res.info.set_message(err.what()); - } - return res; - }; - auto async = [](Args... args) { - std::promise prom; - TraitsType::async(std::forward(args)..., [&prom](error_code errc, error_info info, auto retval) { - prom.set_value(NetResultType{errc, std::move(info), std::move(retval)}); - }); - return prom.get_future().get(); - }; - return std::vector{ - NetFunType("sync_errc", sync_errc), - NetFunType("sync_exc", sync_exc), - NetFunType("async", async) - }; -} - -template -std::vector> -make_network_functions() -{ - return make_network_functions_impl(&TraitsType::sync_exc); -} - -template -struct NetworkTest : - public BaseTest, - public testing::WithParamInterface> -{ - using traits_type = TraitsType; }; } } -#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \ - INSTANTIATE_TEST_SUITE_P(Default, TestSuiteName, testing::ValuesIn( \ - make_network_functions() \ - ), test_name_generator) - - - #endif /* TEST_INTEGRATION_INTEGRATION_TEST_COMMON_HPP_ */ diff --git a/test/integration/network_functions.cpp b/test/integration/network_functions.cpp new file mode 100644 index 00000000..9457289f --- /dev/null +++ b/test/integration/network_functions.cpp @@ -0,0 +1,158 @@ +#include "network_functions.hpp" +#include + +using namespace mysql::test; +using mysql::tcp_prepared_statement; +using mysql::tcp_resultset; +using mysql::tcp_connection; +using mysql::error_info; +using mysql::error_code; +using mysql::detail::make_error_code; +using mysql::Error; + +namespace +{ + +template +auto sync_errc_impl(Callable&& cb) { + using R = decltype(cb(std::declval(), std::declval())); + network_result res; + res.err = make_error_code(Error::no); + res.info.set_message("Error info not cleared correctly"); + res.value = cb(res.err, res.info); + return res; +} + +class sync_errc : public network_functions +{ +public: + network_result prepare_statement( + tcp_connection& conn, + std::string_view statement + ) override + { + return sync_errc_impl([&conn, statement](error_code& err, error_info& info) { + return conn.prepare_statement(statement, err, info); + }); + } + network_result execute_statement( + tcp_prepared_statement& stmt, + value_list_it params_first, + value_list_it params_last + ) override + { + return sync_errc_impl([=, &stmt](error_code& err, error_info& info) { + return stmt.execute(params_first, params_last, err, info); + }); + } + network_result execute_statement( + tcp_prepared_statement& stmt, + const std::vector& values + ) override + { + return sync_errc_impl([&stmt, &values](error_code& err, error_info& info) { + return stmt.execute(values, err, info); + }); + } +}; +sync_errc sync_errc_obj; + +template +auto sync_exc_impl(Callable&& cb) { + using R = decltype(cb()); + network_result res; + try + { + res.value = cb(); + } + catch (const boost::system::system_error& err) + { + res.err = err.code(); + res.info.set_message(err.what()); + } + return res; +} + +class sync_exc : public network_functions +{ +public: + network_result prepare_statement( + tcp_connection& conn, + std::string_view statement + ) override + { + return sync_exc_impl([&conn, statement] { + return conn.prepare_statement(statement); + }); + } + network_result execute_statement( + tcp_prepared_statement& stmt, + value_list_it params_first, + value_list_it params_last + ) override + { + return sync_exc_impl([&]{ + return stmt.execute(params_first, params_last); + }); + } + network_result execute_statement( + tcp_prepared_statement& stmt, + const std::vector& values + ) override + { + return sync_exc_impl([&stmt, &values] { + return stmt.execute(values); + }); + } +}; +sync_exc sync_exc_obj; + +template +network_result async_impl(Callable&& cb) { + std::promise> prom; + cb([&prom](error_code errc, error_info info, auto retval) { + prom.set_value(network_result{errc, std::move(info), std::move(retval)}); + }); + return prom.get_future().get(); +} + +class async : public network_functions +{ +public: + network_result prepare_statement( + tcp_connection& conn, + std::string_view statement + ) override + { + return async_impl([&conn, statement](auto&& token) { + return conn.async_prepare_statement(statement, std::forward(token)); + }); + } + network_result execute_statement( + tcp_prepared_statement& stmt, + value_list_it params_first, + value_list_it params_last + ) override + { + return async_impl([&](auto&& token) { + return stmt.async_execute(params_first, params_last, std::forward(token)); + }); + } + network_result execute_statement( + tcp_prepared_statement& stmt, + const std::vector& values + ) override + { + return async_impl([&](auto&& token) { + return stmt.async_execute(values, std::forward(token)); + }); + } +}; +async async_obj; + +} + +// Visible stuff +mysql::test::network_functions* mysql::test::sync_errc_network_functions = &sync_errc_obj; +mysql::test::network_functions* mysql::test::sync_exc_network_functions = &sync_exc_obj; +mysql::test::network_functions* mysql::test::async_network_functions = &async_obj; diff --git a/test/integration/network_functions.hpp b/test/integration/network_functions.hpp new file mode 100644 index 00000000..32155c19 --- /dev/null +++ b/test/integration/network_functions.hpp @@ -0,0 +1,79 @@ +#ifndef TEST_INTEGRATION_NETWORK_FUNCTIONS_HPP_ +#define TEST_INTEGRATION_NETWORK_FUNCTIONS_HPP_ + +#include "mysql/connection.hpp" +#include "test_common.hpp" +#include +#include + +namespace mysql +{ +namespace test +{ + +template +struct network_result +{ + error_code err; + error_info info; + T value; + + void validate_no_error() const + { + ASSERT_EQ(err, error_code()); + EXPECT_EQ(info, error_info()); + } + + void validate_error( + error_code expected_errc, + const std::vector& expected_msg + ) const + { + EXPECT_EQ(err, expected_errc); + validate_string_contains(info.message(), expected_msg); + } + + void validate_error( + Error expected_errc, + const std::vector& expected_msg + ) const + { + validate_error(detail::make_error_code(expected_errc), expected_msg); + } +}; + +using value_list_it = std::forward_list::const_iterator; + +class network_functions +{ +public: + virtual ~network_functions() = default; + virtual network_result prepare_statement( + tcp_connection&, std::string_view statement) = 0; + virtual network_result execute_statement( + tcp_prepared_statement&, value_list_it params_first, value_list_it params_last) = 0; + virtual network_result execute_statement( + tcp_prepared_statement&, const std::vector&) = 0; +}; + +extern network_functions* sync_errc_network_functions; +extern network_functions* sync_exc_network_functions; +extern network_functions* async_network_functions; + +inline network_functions* all_network_functions [] = { + sync_errc_network_functions, + sync_exc_network_functions, + async_network_functions +}; + +#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \ + INSTANTIATE_TEST_SUITE_P(Default, TestSuiteName, testing::ValuesIn( \ + all_network_functions \ + ), test_name_generator) + +} +} + + + +#endif /* TEST_INTEGRATION_NETWORK_FUNCTIONS_HPP_ */ diff --git a/test/integration/prepare_statement.cpp b/test/integration/prepare_statement.cpp index ff0d9372..b13f291d 100644 --- a/test/integration/prepare_statement.cpp +++ b/test/integration/prepare_statement.cpp @@ -17,34 +17,14 @@ using mysql::tcp_connection; namespace { -struct PrepareStatementTraits -{ - static tcp_prepared_statement sync_errc(tcp_connection& conn, std::string_view statement, - error_code& err, error_info& info) - { - return conn.prepare_statement(statement, err, info); - } - - static tcp_prepared_statement sync_exc(tcp_connection& conn, std::string_view statement) - { - return conn.prepare_statement(statement); - } - - template - static auto async(tcp_connection& conn, std::string_view statement, CompletionToken&& token) - { - return conn.async_prepare_statement(statement, std::forward(token)); - } -}; - -struct PrepareStatementTest : public NetworkTest +struct PrepareStatementTest : public NetworkTest<> { }; // sync errc TEST_P(PrepareStatementTest, OkNoParams) { - auto stmt = GetParam().fun(conn, "SELECT * FROM empty_table"); + auto stmt = GetParam()->prepare_statement(conn, "SELECT * FROM empty_table"); stmt.validate_no_error(); ASSERT_TRUE(stmt.value.valid()); EXPECT_GT(stmt.value.id(), 0); @@ -53,7 +33,7 @@ TEST_P(PrepareStatementTest, OkNoParams) TEST_P(PrepareStatementTest, OkWithParams) { - auto stmt = GetParam().fun(conn, "SELECT * FROM empty_table WHERE id IN (?, ?)"); + auto stmt = GetParam()->prepare_statement(conn, "SELECT * FROM empty_table WHERE id IN (?, ?)"); stmt.validate_no_error(); ASSERT_TRUE(stmt.value.valid()); EXPECT_GT(stmt.value.id(), 0); @@ -62,7 +42,7 @@ TEST_P(PrepareStatementTest, OkWithParams) TEST_P(PrepareStatementTest, Error) { - auto stmt = GetParam().fun(conn, "SELECT * FROM bad_table WHERE id IN (?, ?)"); + auto stmt = GetParam()->prepare_statement(conn, "SELECT * FROM bad_table WHERE id IN (?, ?)"); stmt.validate_error(Error::no_such_table, {"table", "doesn't exist", "bad_table"}); EXPECT_FALSE(stmt.value.valid()); }