From b18cbd2aa6ce5cc4504949adef83b6123b8dfdcb Mon Sep 17 00:00:00 2001 From: ruben Date: Sun, 5 Apr 2020 12:49:37 +0100 Subject: [PATCH] Integ tests now run with and without ssl --- TODO.txt | 4 +- test/common/test_common.hpp | 12 ++++++ test/integration/close_statement.cpp | 4 +- test/integration/database_types.cpp | 4 +- test/integration/execute_statement.cpp | 20 +++++---- test/integration/handshake.cpp | 21 ++++++---- test/integration/integration_test_common.hpp | 41 ++++++++++++++++--- test/integration/network_functions.hpp | 5 --- test/integration/prepare_statement.cpp | 8 ++-- .../prepared_statement_lifecycle.cpp | 12 +++--- test/integration/query.cpp | 4 +- test/integration/resultset.cpp | 27 ++++++------ 12 files changed, 106 insertions(+), 56 deletions(-) diff --git a/TODO.txt b/TODO.txt index 840bc1f8..2a3fc70c 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,6 +1,4 @@ SSL - Add an integ test in handshake to verify encrypted connections - Add a new integ test that proves using every feature over a non-encrypted connection Update README Make ssl context in channel lazy Multiresultset @@ -25,6 +23,8 @@ Usability connection::run_sql that hides the resultset concept Consider if header-only is a good idea Technical debt + Review convention in test names + Review named_param Copy operations for handshake Review handshake auth_plugin_data - seems like buffer overrun is possible (auth data string_lenenc?) Take fetch_many() algorithm out into network_algorithms (e.g. read_many_rows) diff --git a/test/common/test_common.hpp b/test/common/test_common.hpp index 58d49910..d2470efd 100644 --- a/test/common/test_common.hpp +++ b/test/common/test_common.hpp @@ -4,6 +4,7 @@ #include "boost/mysql/value.hpp" #include "boost/mysql/row.hpp" #include "boost/mysql/error.hpp" +#include "boost/mysql/connection_params.hpp" #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include namespace boost { namespace mysql { @@ -140,6 +142,16 @@ inline std::vector concat_copy( return std::move(lhs); } +inline const char* to_string(ssl_mode m) +{ + switch (m) + { + case ssl_mode::disable: return "nossl"; + case ssl_mode::require: return "ssl"; + default: assert(false); return ""; + } +} + struct named_param {}; template >> diff --git a/test/integration/close_statement.cpp b/test/integration/close_statement.cpp index c64b73f0..db2abcfc 100644 --- a/test/integration/close_statement.cpp +++ b/test/integration/close_statement.cpp @@ -12,13 +12,13 @@ using namespace boost::mysql::test; namespace { -struct CloseStatementTest : NetworkTest<> +struct CloseStatementTest : NetworkTest { }; TEST_P(CloseStatementTest, ExistingOrClosedStatement) { - auto* net = GetParam(); + auto* net = GetParam().net; // Prepare a statement auto stmt = net->prepare_statement(conn, "SELECT * FROM empty_table"); diff --git a/test/integration/database_types.cpp b/test/integration/database_types.cpp index c56d863a..6ee60e60 100644 --- a/test/integration/database_types.cpp +++ b/test/integration/database_types.cpp @@ -55,8 +55,10 @@ std::ostream& operator<<(std::ostream& os, const database_types_testcase& v) return os << v.table << "." << v.field << "." << v.row_id; } -struct DatabaseTypesTest : IntegTestAfterHandshake, WithParamInterface +struct DatabaseTypesTest : IntegTestAfterHandshake, + WithParamInterface { + DatabaseTypesTest(): IntegTestAfterHandshake(boost::mysql::ssl_mode::disable) {} }; TEST_P(DatabaseTypesTest, Query_MetadataAndValueCorrect) diff --git a/test/integration/execute_statement.cpp b/test/integration/execute_statement.cpp index 8a0b74b4..a29a133f 100644 --- a/test/integration/execute_statement.cpp +++ b/test/integration/execute_statement.cpp @@ -19,14 +19,16 @@ using boost::mysql::tcp_prepared_statement; namespace { -struct ExecuteStatementTest : public NetworkTest<> {}; +struct ExecuteStatementTest : public NetworkTest +{ +}; // Iterator version TEST_P(ExecuteStatementTest, Iterator_OkNoParams) { std::forward_list params; auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); - auto result = GetParam()->execute_statement(stmt, params.begin(), params.end()); // execute + auto result = GetParam().net->execute_statement(stmt, params.begin(), params.end()); // execute result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } @@ -35,7 +37,7 @@ 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()->execute_statement(stmt, params.begin(), params.end()); + auto result = GetParam().net->execute_statement(stmt, params.begin(), params.end()); result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } @@ -44,7 +46,7 @@ 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()->execute_statement(stmt, params.begin(), params.end()); + auto result = GetParam().net->execute_statement(stmt, params.begin(), params.end()); result.validate_error(errc::wrong_num_params, {"param", "2", "1", "statement", "execute"}); EXPECT_FALSE(result.value.valid()); } @@ -53,7 +55,7 @@ TEST_P(ExecuteStatementTest, Iterator_ServerError) { std::forward_list params { value("f0"), value("bad_date") }; auto stmt = conn.prepare_statement("INSERT INTO inserts_table (field_varchar, field_date) VALUES (?, ?)"); - auto result = GetParam()->execute_statement(stmt, params.begin(), params.end()); + auto result = GetParam().net->execute_statement(stmt, params.begin(), params.end()); result.validate_error(errc::truncated_wrong_value, {"field_date", "bad_date", "incorrect date value"}); EXPECT_FALSE(result.value.valid()); } @@ -62,7 +64,7 @@ TEST_P(ExecuteStatementTest, Iterator_ServerError) TEST_P(ExecuteStatementTest, Container_OkNoParams) { auto stmt = conn.prepare_statement("SELECT * FROM empty_table"); - auto result = GetParam()->execute_statement(stmt, std::vector()); // execute + auto result = GetParam().net->execute_statement(stmt, std::vector()); // execute result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } @@ -71,7 +73,7 @@ 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()->execute_statement(stmt, params); + auto result = GetParam().net->execute_statement(stmt, params); result.validate_no_error(); EXPECT_TRUE(result.value.valid()); } @@ -80,7 +82,7 @@ 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()->execute_statement(stmt, params); + auto result = GetParam().net->execute_statement(stmt, params); result.validate_error(errc::wrong_num_params, {"param", "2", "1", "statement", "execute"}); EXPECT_FALSE(result.value.valid()); } @@ -88,7 +90,7 @@ TEST_P(ExecuteStatementTest, Container_MismatchedNumParams) TEST_P(ExecuteStatementTest, Container_ServerError) { auto stmt = conn.prepare_statement("INSERT INTO inserts_table (field_varchar, field_date) VALUES (?, ?)"); - auto result = GetParam()->execute_statement(stmt, makevalues("f0", "bad_date")); + auto result = GetParam().net->execute_statement(stmt, makevalues("f0", "bad_date")); result.validate_error(errc::truncated_wrong_value, {"field_date", "bad_date", "incorrect date value"}); EXPECT_FALSE(result.value.valid()); } diff --git a/test/integration/handshake.cpp b/test/integration/handshake.cpp index 2e220eea..1863fa9b 100644 --- a/test/integration/handshake.cpp +++ b/test/integration/handshake.cpp @@ -22,18 +22,23 @@ using boost::mysql::error_code; namespace { -struct HandshakeTest : public NetworkTest +struct HandshakeTest : public IntegTest, + public testing::WithParamInterface { - auto do_handshake() { return GetParam()->handshake(conn, connection_params); } + auto do_handshake() + { + connection_params.set_ssl(boost::mysql::ssl_options(GetParam().ssl)); + return GetParam().net->handshake(conn, connection_params); + } }; -TEST_P(HandshakeTest, FastAuthSuccessfulLogin) +TEST_P(HandshakeTest, SuccessfulLogin) { auto result = do_handshake(); result.validate_no_error(); } -TEST_P(HandshakeTest, FastAuthSuccessfulLoginEmptyPassword) +TEST_P(HandshakeTest, SuccessfulLoginEmptyPassword) { connection_params.set_username("empty_password_user"); connection_params.set_password(""); @@ -41,14 +46,14 @@ TEST_P(HandshakeTest, FastAuthSuccessfulLoginEmptyPassword) result.validate_no_error(); } -TEST_P(HandshakeTest, FastAuthSuccessfulLoginNoDatabase) +TEST_P(HandshakeTest, SuccessfulLoginNoDatabase) { connection_params.set_database(""); auto result = do_handshake(); result.validate_no_error(); } -TEST_P(HandshakeTest, FastAuthBadUser) +TEST_P(HandshakeTest, BadUser) { connection_params.set_username("non_existing_user"); auto result = do_handshake(); @@ -57,14 +62,14 @@ TEST_P(HandshakeTest, FastAuthBadUser) // EXPECT_EQ(errc, make_error_code(mysql::errc::access_denied_error)); } -TEST_P(HandshakeTest, FastAuthBadPassword) +TEST_P(HandshakeTest, BadPassword) { connection_params.set_password("bad_password"); auto result = do_handshake(); result.validate_error(errc::access_denied_error, {"access denied", "integ_user"}); } -TEST_P(HandshakeTest, FastAuthBadDatabase) +TEST_P(HandshakeTest, BadDatabase) { connection_params.set_database("bad_database"); auto result = do_handshake(); diff --git a/test/integration/integration_test_common.hpp b/test/integration/integration_test_common.hpp index 38514667..efe4e8c3 100644 --- a/test/integration/integration_test_common.hpp +++ b/test/integration/integration_test_common.hpp @@ -3,6 +3,7 @@ #include #include "boost/mysql/connection.hpp" +#include "boost/mysql/detail/auxiliar/stringize.hpp" #include #include #include @@ -47,8 +48,9 @@ struct IntegTest : testing::Test runner.join(); } - void handshake() + void handshake(ssl_mode m = ssl_mode::require) { + connection_params.set_ssl(ssl_options(m)); conn.handshake(connection_params); } @@ -91,17 +93,46 @@ struct IntegTest : testing::Test struct IntegTestAfterHandshake : IntegTest { - IntegTestAfterHandshake() { handshake(); } + IntegTestAfterHandshake(ssl_mode m = ssl_mode::require) { handshake(m); } }; -template -struct NetworkTest : public BaseType, - public testing::WithParamInterface +struct network_testcase { + network_functions* net; + ssl_mode ssl; + + std::string name() const + { + return detail::stringize(net->name(), '_', to_string(ssl)); + } +}; + +inline std::vector make_all_network_testcases() +{ + std::vector res; + for (auto* net: all_network_functions) + { + for (auto ssl: {ssl_mode::require, ssl_mode::disable}) + { + res.push_back(network_testcase{net, ssl}); + } + } + return res; +} + +struct NetworkTest : public IntegTestAfterHandshake, + public testing::WithParamInterface +{ + NetworkTest(): IntegTestAfterHandshake(GetParam().ssl) {} }; } // test } // mysql } // boost +#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \ + INSTANTIATE_TEST_SUITE_P(Default, TestSuiteName, testing::ValuesIn( \ + make_all_network_testcases() \ + ), [](const auto& param_info) { return param_info.param.name(); }) + #endif /* TEST_INTEGRATION_INTEGRATION_TEST_COMMON_HPP_ */ diff --git a/test/integration/network_functions.hpp b/test/integration/network_functions.hpp index 67f4c69d..819dd770 100644 --- a/test/integration/network_functions.hpp +++ b/test/integration/network_functions.hpp @@ -97,11 +97,6 @@ inline network_functions* all_network_functions [] = { async_future_noerrinfo_network_functions }; -#define MYSQL_NETWORK_TEST_SUITE(TestSuiteName) \ - INSTANTIATE_TEST_SUITE_P(Default, TestSuiteName, testing::ValuesIn( \ - all_network_functions \ - ), [](const auto& param_info) { return param_info.param->name(); }) - } // test } // mysql diff --git a/test/integration/prepare_statement.cpp b/test/integration/prepare_statement.cpp index af9d9a6b..8a8db28b 100644 --- a/test/integration/prepare_statement.cpp +++ b/test/integration/prepare_statement.cpp @@ -17,13 +17,13 @@ using boost::mysql::tcp_connection; namespace { -struct PrepareStatementTest : public NetworkTest<> +struct PrepareStatementTest : public NetworkTest { }; TEST_P(PrepareStatementTest, OkNoParams) { - auto stmt = GetParam()->prepare_statement(conn, "SELECT * FROM empty_table"); + auto stmt = GetParam().net->prepare_statement(conn, "SELECT * FROM empty_table"); stmt.validate_no_error(); ASSERT_TRUE(stmt.value.valid()); EXPECT_GT(stmt.value.id(), 0u); @@ -32,7 +32,7 @@ TEST_P(PrepareStatementTest, OkNoParams) TEST_P(PrepareStatementTest, OkWithParams) { - auto stmt = GetParam()->prepare_statement(conn, "SELECT * FROM empty_table WHERE id IN (?, ?)"); + auto stmt = GetParam().net->prepare_statement(conn, "SELECT * FROM empty_table WHERE id IN (?, ?)"); stmt.validate_no_error(); ASSERT_TRUE(stmt.value.valid()); EXPECT_GT(stmt.value.id(), 0u); @@ -41,7 +41,7 @@ TEST_P(PrepareStatementTest, OkWithParams) TEST_P(PrepareStatementTest, Error) { - auto stmt = GetParam()->prepare_statement(conn, "SELECT * FROM bad_table WHERE id IN (?, ?)"); + auto stmt = GetParam().net->prepare_statement(conn, "SELECT * FROM bad_table WHERE id IN (?, ?)"); stmt.validate_error(errc::no_such_table, {"table", "doesn't exist", "bad_table"}); EXPECT_FALSE(stmt.value.valid()); } diff --git a/test/integration/prepared_statement_lifecycle.cpp b/test/integration/prepared_statement_lifecycle.cpp index b93a5b2a..9f0f7bdc 100644 --- a/test/integration/prepared_statement_lifecycle.cpp +++ b/test/integration/prepared_statement_lifecycle.cpp @@ -14,7 +14,7 @@ using boost::mysql::value; namespace { -struct PreparedStatementLifecycleTest : NetworkTest<> +struct PreparedStatementLifecycleTest : NetworkTest { std::int64_t get_table_size(const std::string& table) { @@ -31,7 +31,7 @@ struct PreparedStatementLifecycleTest : NetworkTest<> TEST_P(PreparedStatementLifecycleTest, SelectWithParametersMultipleExecutions) { - auto* net = GetParam(); + auto* net = GetParam().net; // Prepare a statement auto stmt = net->prepare_statement( @@ -74,7 +74,7 @@ TEST_P(PreparedStatementLifecycleTest, SelectWithParametersMultipleExecutions) TEST_P(PreparedStatementLifecycleTest, InsertWithParametersMultipleExecutions) { - auto* net = GetParam(); + auto* net = GetParam().net; // Get the number of rows before insertion auto rows_before = get_table_size("inserts_table"); @@ -111,7 +111,7 @@ TEST_P(PreparedStatementLifecycleTest, InsertWithParametersMultipleExecutions) TEST_P(PreparedStatementLifecycleTest, UpdateWithParametersMultipleExecutions) { - auto* net = GetParam(); + auto* net = GetParam().net; // Prepare a statement auto stmt = net->prepare_statement( @@ -147,7 +147,7 @@ TEST_P(PreparedStatementLifecycleTest, UpdateWithParametersMultipleExecutions) TEST_P(PreparedStatementLifecycleTest, MultipleStatements) { - auto* net = GetParam(); + auto* net = GetParam().net; // Prepare an update auto stmt_update = net->prepare_statement( @@ -203,7 +203,7 @@ TEST_P(PreparedStatementLifecycleTest, MultipleStatements) TEST_P(PreparedStatementLifecycleTest, InsertWithNullValues) { - auto* net = GetParam(); + auto* net = GetParam().net; // Statement to perform the updates auto stmt = net->prepare_statement( diff --git a/test/integration/query.cpp b/test/integration/query.cpp index c2841f47..93c3f5ea 100644 --- a/test/integration/query.cpp +++ b/test/integration/query.cpp @@ -23,9 +23,9 @@ using boost::mysql::errc; namespace { -struct QueryTest : public NetworkTest<> +struct QueryTest : public NetworkTest { - auto do_query(std::string_view sql) { return GetParam()->query(conn, sql); } + auto do_query(std::string_view sql) { return GetParam().net->query(conn, sql); } }; TEST_P(QueryTest, InsertQueryOk) diff --git a/test/integration/resultset.cpp b/test/integration/resultset.cpp index d2894174..80f14cda 100644 --- a/test/integration/resultset.cpp +++ b/test/integration/resultset.cpp @@ -16,6 +16,7 @@ using boost::mysql::error_code; using boost::mysql::error_info; using boost::mysql::tcp_resultset; using boost::mysql::tcp_connection; +using boost::mysql::ssl_mode; namespace net = boost::asio; namespace @@ -29,23 +30,25 @@ public: virtual tcp_resultset generate(tcp_connection&, std::string_view) = 0; }; -struct ResultsetTestParam : named_param +struct resultset_testcase : named_param, network_testcase { resultset_generator* gen; - network_functions* net; - ResultsetTestParam(resultset_generator* gen, network_functions* net): - gen(gen), net(net) {} + resultset_testcase(network_testcase base, resultset_generator* gen): + network_testcase(base), gen(gen) {} }; -std::ostream& operator<<(std::ostream& os, const ResultsetTestParam& v) +std::ostream& operator<<(std::ostream& os, const resultset_testcase& v) { - return os << v.gen->name() << '.' << v.net->name(); + return os << v.gen->name() << '.' + << v.net->name() << '.' + << to_string(v.ssl); } struct ResultsetTest : public IntegTestAfterHandshake, - public testing::WithParamInterface + public testing::WithParamInterface { + ResultsetTest(): IntegTestAfterHandshake(GetParam().ssl) {} auto do_generate(std::string_view query) { return GetParam().gen->generate(conn, query); } auto do_fetch_one(tcp_resultset& r) { return GetParam().net->fetch_one(r); } auto do_fetch_many(tcp_resultset& r, std::size_t count) { return GetParam().net->fetch_many(r, count); } @@ -273,14 +276,14 @@ resultset_generator* all_resultset_generators [] = { &binary_obj }; -std::vector make_resultset_test_params() +std::vector make_all_resultset_testcases() { - std::vector res; + std::vector res; for (auto* gen: all_resultset_generators) { - for (auto* net: all_network_functions) + for (auto base: make_all_network_testcases()) { - res.push_back(ResultsetTestParam{gen, net}); + res.push_back(resultset_testcase(base, gen)); } } return res; @@ -288,7 +291,7 @@ std::vector make_resultset_test_params() INSTANTIATE_TEST_SUITE_P(Default, ResultsetTest, testing::ValuesIn( - make_resultset_test_params() + make_all_resultset_testcases() ), test_name_generator); }