diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 503be6b89..ea28e6f91 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -411,6 +411,9 @@ add_test_executable(mxs280_select_outfile.cpp mxs280_select_outfile replication # Tries prepared stmt 'SELECT 1,1,1,1...." with different nu,ber of '1' add_test_executable(mxs314.cpp mxs314 galera LABELS MySQLProtocol LIGHT GALERA_BACKEND) +# Testing of the master replacement feature +add_test_executable(mxs359_master_switch.cpp mxs359_master_switch mxs359_master_switch LABELS REPL_BACKEND) + # Binary protocol prepared statement tests add_test_executable(binary_ps.cpp binary_ps replication LABELS readwritesplit LIGHT REPL_BACKEND) add_test_executable(binary_ps_cursor.cpp binary_ps_cursor replication LABELS readwritesplit LIGHT REPL_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs359_master_switch b/maxscale-system-test/cnf/maxscale.cnf.template.mxs359_master_switch new file mode 100644 index 000000000..988b829d9 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs359_master_switch @@ -0,0 +1,59 @@ +[maxscale] +threads=###threads### + +[MySQL-Monitor] +type=monitor +module=mysqlmon +###repl51### +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +monitor_interval=1000 + +[RW-Split-Router] +type=service +router=readwritesplit +servers=server1,server2,server3,server4 +user=maxskysql +passwd=skysql +allow_master_replacement=true + +[RW-Split-Listener] +type=listener +service=RW-Split-Router +protocol=MySQLClient +port=4006 + +[CLI] +type=service +router=cli + +[CLI-Listener] +type=listener +service=CLI +protocol=maxscaled +socket=default + +[server1] +type=server +address=###node_server_IP_1### +port=###node_server_port_1### +protocol=MySQLBackend + +[server2] +type=server +address=###node_server_IP_2### +port=###node_server_port_2### +protocol=MySQLBackend + +[server3] +type=server +address=###node_server_IP_3### +port=###node_server_port_3### +protocol=MySQLBackend + +[server4] +type=server +address=###node_server_IP_4### +port=###node_server_port_4### +protocol=MySQLBackend diff --git a/maxscale-system-test/mxs359_master_switch.cpp b/maxscale-system-test/mxs359_master_switch.cpp new file mode 100644 index 000000000..75de8d0dc --- /dev/null +++ b/maxscale-system-test/mxs359_master_switch.cpp @@ -0,0 +1,87 @@ +/** + * MXS-359: Switch master mid-session + * + * https://jira.mariadb.org/browse/MXS-359 + */ +#include "testconnections.h" + +TestConnections* global_test; + +void change_master(int next, int current) +{ + TestConnections& test = *global_test; + test.repl->connect(); + test.repl->change_master(current, next); + test.repl->close_connections(); +} + +struct Test +{ + const char* query; + bool should_work; + + Test(const char* q = NULL, bool works = true): + query(q), + should_work(works) + { + } +}; + +void do_test(Test pre, Test post) +{ + TestConnections& test = *global_test; + int rc; + test.maxscales->connect(); + + if (pre.query) + { + rc = execute_query_silent(test.maxscales->conn_rwsplit[0], pre.query); + test.assert((rc == 0) == pre.should_work, "Expected query '%s' to %s: %s", + pre.query, pre.should_work ? "succeed" : "fail", + mysql_error(test.maxscales->conn_rwsplit[0])); + } + + change_master(1, 0); + sleep(5); + + rc = execute_query_silent(test.maxscales->conn_rwsplit[0], post.query); + test.assert((rc == 0) == post.should_work, "Expected query '%s' to %s: %s", + post.query, post.should_work ? "succeed" : "fail", + mysql_error(test.maxscales->conn_rwsplit[0])); + + change_master(0, 1); + test.maxscales->disconnect(); + + sleep(5); +} + +int main(int argc, char** argv) +{ + TestConnections test(argc, argv); + global_test = &test; + + // Prepare a table for testing + test.maxscales->connect(); + test.try_query(test.maxscales->conn_rwsplit[0], "CREATE OR REPLACE TABLE test.t1(id INT)"); + test.repl->sync_slaves(); + test.maxscales->disconnect(); + + test.tprintf("Check that write after change works"); + do_test({}, {"INSERT INTO test.t1 VALUES (1)"}); + + test.tprintf("Check that write with open transaction fails"); + do_test({"START TRANSACTION"}, {"INSERT INTO test.t1 VALUES (1)", false}); + + test.tprintf("Check that read with open read-only transaction works"); + do_test({"START TRANSACTION READ ONLY"}, {"SELECT 1"}); + + test.tprintf("Check that write with autocommit=0 fails"); + do_test({"SET autocommit=0"}, {"INSERT INTO test.t1 VALUES (1)", false}); + + test.maxscales->connect(); + test.try_query(test.maxscales->conn_rwsplit[0], "DROP TABLE test.t1"); + test.repl->fix_replication(); + test.maxscales->disconnect(); + + return test.global_result; +}