diff --git a/test/tap/groups/groups.json b/test/tap/groups/groups.json index b95ebb3f8..83365a35b 100644 --- a/test/tap/groups/groups.json +++ b/test/tap/groups/groups.json @@ -139,6 +139,7 @@ "test_cluster_sync-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], "test_com_binlog_dump_enables_fast_forward-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], "fast_forward_grace_close_libmysql-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], + "fast_forward_switch_replication_deprecate_eof_libmysql-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], "test_com_register_slave_enables_fast_forward-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], "test_com_reset_connection_com_change_user-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], "test_connection_annotation-t" : [ "default-g3","mysql-auto_increment_delay_multiplex=0-g3","mysql-multiplexing=false-g3","mysql-query_digests=0-g3","mysql-query_digests_keep_comment=1-g3" ], diff --git a/test/tap/tests/Makefile b/test/tap/tests/Makefile index 136d7db01..801013cf3 100644 --- a/test/tap/tests/Makefile +++ b/test/tap/tests/Makefile @@ -122,6 +122,7 @@ tests: tests-cpp \ prepare_statement_err3024_libmysql-t \ prepare_statement_err3024_async-t \ fast_forward_grace_close_libmysql-t \ + fast_forward_switch_replication_deprecate_eof_libmysql-t \ reg_test_mariadb_stmt_store_result_libmysql-t \ reg_test_mariadb_stmt_store_result_async-t tests: @@ -257,6 +258,9 @@ test_ssl_fast_forward-3_libmariadb-t: test_ssl_fast_forward-3.cpp $(TAP_LDIR)/li test_ssl_fast_forward-3_libmysql-t: test_ssl_fast_forward-3.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 $@ +fast_forward_switch_replication_deprecate_eof_libmysql-t: fast_forward_switch_replication_deprecate_eof.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 $@ diff --git a/test/tap/tests/fast_forward_switch_replication_deprecate_eof.cpp b/test/tap/tests/fast_forward_switch_replication_deprecate_eof.cpp new file mode 100644 index 000000000..002c65fba --- /dev/null +++ b/test/tap/tests/fast_forward_switch_replication_deprecate_eof.cpp @@ -0,0 +1,179 @@ +#include +/* + * Fast Forward Switch Replication Deprecate EOF Test + * + * This test validates the fast forward replication feature with different + * deprecate EOF variable combinations. The test ensures that ProxySQL + * handles replication switching correctly under all combinations of + * mysql-enable_client_deprecate_eof and mysql-enable_server_deprecate_eof. + * + * Test Strategy: + * - Generate a large binlog on the backend. + * - Run replication in a loop with different deprecate EOF combinations. + * - Test all 4 combinations: true/true, true/false, false/true, false/false. + * - Verify that replication works correctly in all scenarios. + * - Fetch binary log at full speed without throttling. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mysql.h" +#include "mysqld_error.h" + +#include "tap.h" +#include "command_line.h" +#include "utils.h" + +#ifndef BINLOG_DUMP_NON_BLOCK +#define BINLOG_DUMP_NON_BLOCK 1 +#endif // BINLOG_DUMP_NON_BLOCK + +using std::string; + +struct DeprecateEOFConfig { + bool client_deprecate_eof; + bool server_deprecate_eof; + std::string description; +}; + +int main() { + // Define the 4 combinations of deprecate EOF settings + std::vector configs = { + {true, true, "client=true, server=true"}, + {true, false, "client=true, server=false"}, + {false, true, "client=false, server=true"}, + {false, false, "client=false, server=false"} + }; + + plan(20); // 4 base tests + 16 tests (4 configs × 4 tests each) + + CommandLine cl; + if (cl.getEnv()) { + diag("Failed to get the required environmental variables."); + return -1; + } + + // 1. Generate a large binlog file + MYSQL* backend_conn = mysql_init(NULL); + if (!mysql_real_connect(backend_conn, cl.host, cl.mysql_username, cl.mysql_password, "information_schema", cl.port, NULL, 0)) { + diag("Backend connection failed: %s", mysql_error(backend_conn)); + return -1; + } + ok(1, "Connected to backend server"); + MYSQL_QUERY(backend_conn, "CREATE DATABASE IF NOT EXISTS test"); + MYSQL_QUERY(backend_conn, "USE test"); + MYSQL_QUERY(backend_conn, "CREATE TABLE IF NOT EXISTS dummy_log_table (id INT PRIMARY KEY AUTO_INCREMENT, data LONGTEXT)"); + MYSQL_QUERY(backend_conn, "INSERT INTO dummy_log_table (data) VALUES (REPEAT('a', 1024*50))"); + MYSQL_QUERY(backend_conn, "INSERT INTO dummy_log_table (data) VALUES (REPEAT('a', 1024*50))"); + MYSQL_QUERY(backend_conn, "INSERT INTO dummy_log_table (data) VALUES (REPEAT('a', 1024*50))"); + int rc = mysql_query(backend_conn, "FLUSH LOGS"); + ok(rc == 0, "Generated data and flushed logs on backend"); + + // 2. Get binary log file name + string binlog_file; + if (mysql_query(backend_conn, "SHOW BINARY LOGS") == 0) { + MYSQL_RES *res = mysql_store_result(backend_conn); + if (res) { + MYSQL_ROW row = mysql_fetch_row(res); + if (row && row[0]) { + binlog_file = row[0]; + } + mysql_free_result(res); + } + } + mysql_close(backend_conn); + ok(!binlog_file.empty(), "Retrieved binary log file name: %s", binlog_file.c_str()); + + // 3. Connect to ProxySQL admin + MYSQL* proxysql_admin = mysql_init(NULL); + if (!mysql_real_connect(proxysql_admin, cl.host, cl.admin_username, cl.admin_password, NULL, cl.admin_port, NULL, 0)) { + diag("Admin connection failed: %s", mysql_error(proxysql_admin)); + return -1; + } + ok(1, "Connected to ProxySQL admin"); + + // 4. Test each deprecate EOF configuration + for (size_t i = 0; i < configs.size(); i++) { + const auto& config = configs[i]; + + // Set the deprecate EOF variables + std::string client_value = config.client_deprecate_eof ? "true" : "false"; + std::string server_value = config.server_deprecate_eof ? "true" : "false"; + + rc = mysql_query(proxysql_admin, + ("UPDATE global_variables SET variable_value='" + client_value + "' WHERE variable_name='mysql-enable_client_deprecate_eof'").c_str()); + ok(rc == 0, ("Set mysql-enable_client_deprecate_eof=" + client_value).c_str()); + + rc = mysql_query(proxysql_admin, + ("UPDATE global_variables SET variable_value='" + server_value + "' WHERE variable_name='mysql-enable_server_deprecate_eof'").c_str()); + ok(rc == 0, ("Set mysql-enable_server_deprecate_eof=" + server_value).c_str()); + + rc = mysql_query(proxysql_admin, "LOAD MYSQL VARIABLES TO RUNTIME"); + ok(rc == 0, "Loaded MYSQL variables to runtime"); + + // Connect for binlog reading + MYSQL* binlog_conn = mysql_init(NULL); + if (!mysql_real_connect(binlog_conn, cl.host, cl.mysql_username, cl.mysql_password, NULL, cl.port, NULL, 0)) { + diag("Binlog connection failed for config %s: %s", config.description.c_str(), mysql_error(binlog_conn)); + mysql_close(proxysql_admin); + return -1; + } + + MYSQL_QUERY(binlog_conn, "SET /* create_new_connection=1 */ @source_binlog_checksum='NONE'"); + MYSQL_RPL rpl {}; + rpl.file_name = const_cast(binlog_file.c_str()); + rpl.start_position = 4; + rpl.server_id = 12345; + rpl.flags = BINLOG_DUMP_NON_BLOCK; + rc = mysql_binlog_open(binlog_conn, &rpl); + if (rc != 0) { + diag("mysql_binlog_open failed for config %s: %s", config.description.c_str(), mysql_error(binlog_conn)); + mysql_close(binlog_conn); + mysql_close(proxysql_admin); + return -1; + } + diag("mysql_binlog_open succeeded for config: %s", config.description.c_str()); + + // Read binlog at full speed + long bytes_read = 0; + bool reached_EOF = false; + long total_chunks = 0; + + while (true) { + rc = mysql_binlog_fetch(binlog_conn, &rpl); + if (rc != 0) break; + bytes_read += rpl.size; + total_chunks++; + + if (rpl.size == 0) { + // when size is 0, we reached EOF + reached_EOF = true; + break; + } + } + + ok(reached_EOF == true, "Config %s: Reached EOF: %s, Total Chunks: %ld, Bytes: %ld", + config.description.c_str(), (reached_EOF == true ? "TRUE" : "FALSE"), total_chunks, bytes_read); + + diag("Config %s: binlog fetch ended with rc=%d, error=%s", config.description.c_str(), + rc, (rc == 0 ? "None" : mysql_error(binlog_conn))); + mysql_binlog_close(binlog_conn, &rpl); + mysql_close(binlog_conn); + + // Result summary + diag("Config %s: completed - chunks=%ld, bytes=%ld", config.description.c_str(), total_chunks, bytes_read); + } + + mysql_close(proxysql_admin); + + return exit_status(); +}