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

Integ tests now run with and without ssl

This commit is contained in:
ruben
2020-04-05 12:49:37 +01:00
parent c486dbbf96
commit b18cbd2aa6
12 changed files with 106 additions and 56 deletions

View File

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

View File

@@ -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 <boost/asio/buffer.hpp>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -12,6 +13,7 @@
#include <sstream>
#include <type_traits>
#include <ostream>
#include <cassert>
namespace boost {
namespace mysql {
@@ -140,6 +142,16 @@ inline std::vector<std::uint8_t> 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 <typename T, typename=std::enable_if_t<std::is_base_of_v<named_param, T>>>

View File

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

View File

@@ -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<database_types_testcase>
struct DatabaseTypesTest : IntegTestAfterHandshake,
WithParamInterface<database_types_testcase>
{
DatabaseTypesTest(): IntegTestAfterHandshake(boost::mysql::ssl_mode::disable) {}
};
TEST_P(DatabaseTypesTest, Query_MetadataAndValueCorrect)

View File

@@ -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<value> 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<value> 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<value> 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<value> 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<value>()); // execute
auto result = GetParam().net->execute_statement(stmt, std::vector<value>()); // execute
result.validate_no_error();
EXPECT_TRUE(result.value.valid());
}
@@ -71,7 +73,7 @@ TEST_P(ExecuteStatementTest, Container_OkWithParams)
{
std::vector<value> 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<value> 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());
}

View File

@@ -22,18 +22,23 @@ using boost::mysql::error_code;
namespace
{
struct HandshakeTest : public NetworkTest<IntegTest>
struct HandshakeTest : public IntegTest,
public testing::WithParamInterface<network_testcase>
{
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();

View File

@@ -3,6 +3,7 @@
#include <gtest/gtest.h>
#include "boost/mysql/connection.hpp"
#include "boost/mysql/detail/auxiliar/stringize.hpp"
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <future>
@@ -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 <typename BaseType = IntegTestAfterHandshake>
struct NetworkTest : public BaseType,
public testing::WithParamInterface<network_functions*>
struct network_testcase
{
network_functions* net;
ssl_mode ssl;
std::string name() const
{
return detail::stringize(net->name(), '_', to_string(ssl));
}
};
inline std::vector<network_testcase> make_all_network_testcases()
{
std::vector<network_testcase> 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<network_testcase>
{
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_ */

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<ResultsetTestParam>
public testing::WithParamInterface<resultset_testcase>
{
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<ResultsetTestParam> make_resultset_test_params()
std::vector<resultset_testcase> make_all_resultset_testcases()
{
std::vector<ResultsetTestParam> res;
std::vector<resultset_testcase> 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<ResultsetTestParam> make_resultset_test_params()
INSTANTIATE_TEST_SUITE_P(Default, ResultsetTest, testing::ValuesIn(
make_resultset_test_params()
make_all_resultset_testcases()
), test_name_generator);
}