diff --git a/maxscale-system-test/.gitignore b/maxscale-system-test/.gitignore index 8c5e8fb1c..b33e105e0 100644 --- a/maxscale-system-test/.gitignore +++ b/maxscale-system-test/.gitignore @@ -123,6 +123,7 @@ mysqlmon_failover_rejoin_old_slave mysqlmon_failover_rolling_master mysqlmon_failover_rolling_restart_slaves mysqlmon_switchover_bad_master +mysqlmon_switchover mxs1045 mxs1071_maxrows mxs1110_16mb diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 7781b99e5..85908b8ae 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -263,6 +263,9 @@ add_test_executable(mysqlmon_failover_manual2.cpp mysqlmon_failover_manual2_4 my add_test_executable(mysqlmon_failover_manual2.cpp mysqlmon_failover_manual2_3 mysqlmon_failover_manual2_3 LABELS mysqlmon REPL_BACKEND) add_test_executable(mysqlmon_failover_manual2.cpp mysqlmon_failover_manual2_2 mysqlmon_failover_manual2_2 LABELS mysqlmon REPL_BACKEND) +# MySQL Monitor switchover +add_test_executable(mysqlmon_switchover.cpp mysqlmon_switchover mysqlmon_switchover LABELS mysqlmon REPL_BACKEND) + # MySQL Monitor switchover with bad master add_test_executable(mysqlmon_switchover_bad_master.cpp mysqlmon_switchover_bad_master mysqlmon_switchover_bad_master LABELS mysqlmon REPL_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_switchover b/maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_switchover new file mode 100644 index 000000000..e5dcff078 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mysqlmon_switchover @@ -0,0 +1,92 @@ +[maxscale] +threads=###threads### + +[MySQL-Monitor] +type=monitor +module=mysqlmon +servers= server1, server2, server3, server4 +user=maxskysql +passwd= skysql +monitor_interval=1000 +allow_cluster_recovery=true +detect_standalone_master=true +auto_failover=false +auto_rejoin=true +replication_user=repl +replication_password=repl +backend_connect_timeout=1 + +[RW-Split-Router] +type=service +router= readwritesplit +servers=server1, server2, server3, server4 +user=maxskysql +passwd=skysql + +[Read-Connection-Router-Slave] +type=service +router=readconnroute +router_options= slave +servers=server1, server2, server3, server4 +user=maxskysql +passwd=skysql + +[Read-Connection-Router-Master] +type=service +router=readconnroute +router_options=master +servers=server1, server2, server3, server4 +user=maxskysql +passwd=skysql + +[RW-Split-Listener] +type=listener +service=RW-Split-Router +protocol=MySQLClient +port=4006 + +[Read-Connection-Listener-Slave] +type=listener +service=Read-Connection-Router-Slave +protocol=MySQLClient +port=4009 + +[Read-Connection-Listener-Master] +type=listener +service=Read-Connection-Router-Master +protocol=MySQLClient +port=4008 + +[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/mysqlmon_switchover.cpp b/maxscale-system-test/mysqlmon_switchover.cpp new file mode 100644 index 000000000..acc1acfee --- /dev/null +++ b/maxscale-system-test/mysqlmon_switchover.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2020-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include +#include +#include +#include +#include "testconnections.h" + +using std::cerr; +using std::cout; +using std::endl; +using std::flush; +using std::string; +using std::stringstream; + +namespace +{ + +void sleep(int s) +{ + cout << "Sleeping " << s << " times 1 second" << flush; + do + { + ::sleep(1); + cout << "." << flush; + --s; + } + while (s > 0); + + cout << endl; +} + +} + +namespace +{ + +void create_table(TestConnections& test) +{ + MYSQL* pConn = test.maxscales->conn_rwsplit[0]; + + test.try_query(pConn, "DROP TABLE IF EXISTS test.t1"); + test.try_query(pConn, "CREATE TABLE test.t1(id INT)"); +} + +static int i_start = 0; +static int n_rows = 20; +static int i_end = 0; + +void insert_data(TestConnections& test) +{ + MYSQL* pConn = test.maxscales->conn_rwsplit[0]; + + test.try_query(pConn, "BEGIN"); + + i_end = i_start + n_rows; + + for (int i = i_start; i < i_end; ++i) + { + stringstream ss; + ss << "INSERT INTO test.t1 VALUES (" << i << ")"; + test.try_query(pConn, ss.str().c_str()); + } + + test.try_query(pConn, "COMMIT"); + + i_start = i_end; +} + +void expect(TestConnections& test, const char* zServer, const StringSet& expected) +{ + StringSet found = test.get_server_status(zServer); + + std::ostream_iterator oi(cout, ", "); + + cout << zServer + << ", expected states: "; + std::copy(expected.begin(), expected.end(), oi); + cout << endl; + + cout << zServer + << ", found states : "; + std::copy(found.begin(), found.end(), oi); + cout << endl; + + if (found != expected) + { + test.assert(false, "Found states are not the same as the expected ones."); + ++test.global_result; + } + + cout << endl; +} + +void expect(TestConnections& test, const char* zServer, const char* zState) +{ + StringSet s; + s.insert(zState); + + expect(test, zServer, s); +} + +void expect(TestConnections& test, const char* zServer, const char* zState1, const char* zState2) +{ + StringSet s; + s.insert(zState1); + s.insert(zState2); + + expect(test, zServer, s); +} + +void run(TestConnections& test) +{ + sleep(5); + + int N = test.repl->N; + cout << "Nodes: " << N << endl; + + expect(test, "server1", "Master", "Running"); + expect(test, "server2", "Slave", "Running"); + expect(test, "server3", "Slave", "Running"); + expect(test, "server4", "Slave", "Running"); + + cout << "\nConnecting to MaxScale." << endl; + test.maxscales->connect_maxscale(0); + + cout << "\nCreating table." << endl; + create_table(test); + + cout << "\nInserting data." << endl; + insert_data(test); + + cout << "\nSyncing slaves." << endl; + test.repl->sync_slaves(); + + cout << "\nTrying to do manual switchover to server2" << endl; + const char* zCommand = "call command mysqlmon switchover MySQL-Monitor server2 server1"; + test.maxscales->execute_maxadmin_command_print(0, (char*)zCommand); + + sleep(5); + + expect(test, "server1", "Slave", "Running"); + expect(test, "server2", "Master", "Running"); + expect(test, "server3", "Slave", "Running"); + expect(test, "server4", "Slave", "Running"); +} + +} + +int main(int argc, char* argv[]) +{ + std::ios::sync_with_stdio(true); + + Mariadb_nodes::require_gtid(true); + TestConnections test(argc, argv); + + run(test); + + return test.global_result; +} +