Add new TAP test 'mysql_reconnect'

Tests reconnect with and without SSL for 'libmariadb' and 'libmysql'.
pull/4537/head
Javier Jaramago Fernández 2 years ago
parent ef3360f102
commit b4eab27686

@ -1033,6 +1033,27 @@ cleanup:
return res;
}
vector<vector<bool>> get_all_bin_vec(size_t tg_size) {
vector<vector<bool>> all_bin_strs {};
vector<bool> bin_vec(tg_size, 0);
for (size_t i = 0; i < tg_size; i++) {
if (i == 0) {
bin_vec[i] = 0;
for (const vector<bool> p : get_permutations(bin_vec)) {
all_bin_strs.push_back(p);
}
}
bin_vec[i] = 1;
for (const vector<bool> p : get_permutations(bin_vec)) {
all_bin_strs.push_back(p);
}
}
return all_bin_strs;
}
string to_string(const conn_cnf_t& cnf) {
return string {
string { "{" }

@ -424,6 +424,13 @@ std::vector<std::vector<T>> get_permutations(const std::vector<T>& elem_set) {
return result;
}
/**
* @brief Generates permutations of binary vectors of the specified size.
* @param tg_size The target size of the binary vectors.
* @return The generated permutations.
*/
std::vector<std::vector<bool>> get_all_bin_vec(size_t tg_size);
/**
* @brief Struct holding options on how to performs connections for 'EOF' tests.
*/

@ -191,6 +191,8 @@ tests: tests-cpp \
setparser_test \
reg_test_3504-change_user_libmariadb_helper \
reg_test_3504-change_user_libmysql_helper \
mysql_reconnect_libmariadb-t \
mysql_reconnect_libmysql-t \
setparser_test2 setparser_test2-t \
setparser_test3 setparser_test3-t \
set_testing-240.csv \
@ -289,6 +291,12 @@ reg_test_3504-change_user_libmariadb_helper: reg_test_3504-change_user_helper.cp
reg_test_3504-change_user_libmysql_helper: reg_test_3504-change_user_helper.cpp $(TAP_LDIR)/libtap.so
$(CXX) -DLIBMYSQL_HELPER -DDISABLE_WARNING_COUNT_LOGGING $< -I$(TEST_MYSQL_IDIR) -I$(TEST_MYSQL_EDIR) -L$(TEST_MYSQL_LDIR) -Wl,-Bstatic -lmysqlclient -ltap_mysql57 $(CUSTOMARGS) -o $@
mysql_reconnect_libmariadb-t: mysql_reconnect.cpp $(TAP_LDIR)/libtap.so
$(CXX) -DDISABLE_WARNING_COUNT_LOGGING $< $(IDIRS) $(LDIRS) $(OPT) $(MYLIBS) $(STATIC_LIBS) -o $@
mysql_reconnect_libmysql-t: mysql_reconnect.cpp $(TAP_LDIR)/libtap_mysql8.a
$(CXX) -DLIBMYSQL_HELPER8 -DDISABLE_WARNING_COUNT_LOGGING $< -I$(TEST_MYSQL8_IDIR) -I$(TEST_MYSQL8_EDIR) -L$(TEST_MYSQL8_LDIR) -lmysqlclient -ltap_mysql8 -lresolv $(CUSTOMARGS) -o $@
test_clickhouse_server_libmysql-t: test_clickhouse_server-t.cpp $(TAP_LDIR)/libtap.so
$(CXX) -DLIBMYSQL_HELPER -DDISABLE_WARNING_COUNT_LOGGING $< -I$(TEST_MYSQL_IDIR) -I$(TEST_MYSQL_EDIR) -L$(TEST_MYSQL_LDIR) -lmysqlclient -ltap_mysql57 $(CUSTOMARGS) -o $@

@ -0,0 +1,200 @@
/**
* @file mysql_reconnect.cpp
* @brief Check that reconnect works against ProxySQL with/without SSL enabled.
* @details The test requires to be compiled against libmariadb and libmysql. This allows to perform a
* regression test against libmysql regarding reconnect and SSL session tickets.
*/
#include <cstring>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <vector>
#include <thread>
#ifdef LIBMYSQL_HELPER8
#include <mysql/mysql.h>
#else
#include "mysql.h"
#endif
#include "utils.h"
#include "tap.h"
#include "command_line.h"
using std::string;
using std::vector;
struct _conn_cnf_t {
bool ssl;
bool eof;
};
int test_reconnect(const CommandLine& cl, const _conn_cnf_t& cnf) {
MYSQL* proxy = mysql_init(NULL);
bool reconnect = 1;
int cflags = 0;
if (cnf.ssl) {
#ifdef LIBMYSQL_HELPER8
enum mysql_ssl_mode ssl_mode = SSL_MODE_REQUIRED;
mysql_options(proxy, MYSQL_OPT_SSL_MODE, &ssl_mode);
#else
mysql_ssl_set(proxy, NULL, NULL, NULL, NULL, NULL);
cflags |= CLIENT_SSL;
#endif
}
if (cnf.eof) {
proxy->options.client_flag |= CLIENT_DEPRECATE_EOF;
}
mysql_options(proxy, MYSQL_OPT_RECONNECT, &reconnect);
cflags |= CLIENT_REMEMBER_OPTIONS;
const string TG_BACKEND { get_env_str("TG_BACKEND", "PROXYSQL") };
const char* user = cl.username;
const char* pass = cl.password;
const char* host = cl.host;
int port = cl.port;
if (TG_BACKEND == "MYSQL") {
port = cl.mysql_port;
}
diag(
"Creating initial conn against ProxySQL host:'%s', port:'%d', user:'%s', pass:'%s'",
cl.host, cl.port, cl.username, cl.password
);
if (!mysql_real_connect(proxy, host, user, pass, NULL, port, NULL, cflags)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(proxy));
return EXIT_FAILURE;
}
#ifdef LIBMYSQL_HELPER8
void* ssl_session_data = nullptr;
if (cnf.ssl) {
ssl_session_data = mysql_get_ssl_session_data(proxy, 0, nullptr);
if (ssl_session_data) {
mysql_options(proxy, MYSQL_OPT_SSL_SESSION_DATA, ssl_session_data);
}
}
#endif
const char* admin_user = cl.admin_username;
const char* admin_pass = cl.admin_password;
const char* admin_host = cl.admin_host;
int admin_port = cl.admin_port;
if (TG_BACKEND == "MYSQL") {
admin_user = cl.mysql_username;
admin_pass = cl.mysql_password;
admin_port = cl.mysql_port;
}
MYSQL* admin = mysql_init(NULL);
diag(
"Creating Admin conn against ProxySQL host:'%s', port:'%d', user:'%s', pass:'%s'",
admin_host, admin_port, admin_user, admin_pass
);
if (!mysql_real_connect(admin, admin_host, admin_user, admin_pass, NULL, admin_port, NULL, 0)) {
fprintf(stderr, "File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin));
return EXIT_FAILURE;
}
pid_t pid = getpid();
const string s_pid { std::to_string(pid) };
std::thread query_thread([proxy, s_pid] () {
const string query { "/* client_pid=" + s_pid + " */ SELECT SLEEP(20)" };
int rc = mysql_query(proxy, query.c_str());
ok(rc != 0, "Query should exit with error rc:%d, err:'%s'", rc, mysql_error(proxy));
rc = mysql_query(proxy, "DO 1");
if (rc) {
diag("Simple query failed after reconnect query:'%s', err:'%s'", "DO 1", mysql_error(proxy));
}
ok(rc == 0, "Second query should succeed (reconnect) rc:%d, err:'%s'", rc, mysql_error(proxy));
});
const string cond_query {
TG_BACKEND == "PROXYSQL" ?
"SELECT IIF("
"(SELECT COUNT(*) FROM stats_mysql_processlist WHERE"
" info LIKE '%client_pid=" + s_pid + "%')=1, 'TRUE', 'FALSE')" :
"SELECT IF("
"(SELECT COUNT(*) FROM information_schema.processlist WHERE"
" info LIKE '%client_pid=" + s_pid + "%' AND state='User sleep')=1, 'TRUE', 'FALSE')"
};
int wres = wait_for_cond(admin, cond_query.c_str(), 60);
const string ext_query {
TG_BACKEND == "PROXYSQL" ?
"SELECT SessionID FROM stats_mysql_processlist WHERE info LIKE '%client_pid=" + s_pid + "%'" :
"SELECT ID FROM information_schema.processlist WHERE info LIKE '%client_pid=" + s_pid + "%'"
" AND state='User sleep'"
};
ext_val_t<int64_t> ext_sess_id = mysql_query_ext_val(admin, ext_query, int64_t(0));
if (ext_sess_id.err != EXIT_SUCCESS) {
const string err { get_ext_val_err(admin, ext_sess_id) };
diag("Failed getting 'SessionID' query:`%s`, err:`%s`", ext_query.c_str(), err.c_str());
goto cleanup;
}
{
const string kill_sess_query { "KILL CONNECTION " + std::to_string(ext_sess_id.val) };
mysql_query(admin, kill_sess_query.c_str());
}
cleanup:
{
query_thread.join();
mysql_close(admin);
#ifdef LIBMYSQL_HELPER8
if (ssl_session_data) {
mysql_free_ssl_session_data(proxy, ssl_session_data);
}
#endif
mysql_close(proxy);
}
return EXIT_SUCCESS;
}
int main(int argc, char** argv) {
CommandLine cl;
if (cl.getEnv()) {
diag("Failed to get the required environmental variables.");
return EXIT_FAILURE;
}
const auto& bin_vecs { get_all_bin_vec(2) };
plan(bin_vecs.size() * 2);
for (const vector<bool> vec : bin_vecs) {
_conn_cnf_t conf { vec[0], vec[1] };
diag("Testing reconnect with config ssl:%d, eof:%d", conf.ssl, conf.eof);
int rc = test_reconnect(cl, conf);
if (rc) {
diag("Reconnect failed, aborting further testing... rc:%d, ssl:%d, eof:%d", rc, conf.ssl, conf.eof);
break;
}
}
return exit_status();
}

@ -28,27 +28,6 @@
using std::string;
using std::vector;
vector<vector<bool>> get_all_bin_vec(size_t tg_size) {
vector<vector<bool>> all_bin_strs {};
vector<bool> bin_vec(tg_size, 0);
for (size_t i = 0; i < tg_size; i++) {
if (i == 0) {
bin_vec[i] = 0;
for (const vector<bool> p : get_permutations(bin_vec)) {
all_bin_strs.push_back(p);
}
}
bin_vec[i] = 1;
for (const vector<bool> p : get_permutations(bin_vec)) {
all_bin_strs.push_back(p);
}
}
return all_bin_strs;
}
vector<conn_cnf_t> gen_all_configs(const string& ff_user) {
vector<vector<bool>> all_bin_vec { get_all_bin_vec(5) };
std::sort(all_bin_vec.begin(), all_bin_vec.end());

Loading…
Cancel
Save