diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index ffa43abb8..6bd13f0cf 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -926,6 +926,9 @@ add_test_executable(mxs2300_history_pruning.cpp mxs2300_history_pruning mxs2300_ # MXS-2326: Routing hints aren't cloned in gwbuf_clone add_test_executable(mxs2326_hint_clone.cpp mxs2326_hint_clone mxs2326_hint_clone LABELS readwritesplit REPL_BACKEND) +# MXS-2313: `rank` functional test +add_test_executable(mxs2313_rank.cpp mxs2313_rank mxs2313_rank LABELS readwritesplit REPL_BACKEND) + ############################################ # BEGIN: binlogrouter and avrorouter tests # ############################################ diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs2313_rank b/maxscale-system-test/cnf/maxscale.cnf.template.mxs2313_rank new file mode 100755 index 000000000..ebc2a6d56 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs2313_rank @@ -0,0 +1,64 @@ +[maxscale] +threads=###threads### +log_info=1 + +[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 + +[MySQL-Monitor] +type=monitor +module=mysqlmon +servers=server1,server2,server3,server4 +user=maxskysql +password=skysql +monitor_interval=1000 + +[RW-Split-Router] +type=service +router=readwritesplit +servers=server1,server2,server3,server4 +user=maxskysql +password=skysql +master_failure_mode=fail_on_write +master_reconnection=true + +[Read-Connection-Router] +type=service +router=readconnroute +router_options=running +servers=server1,server2,server3,server4 +user=maxskysql +password=skysql + +[RW-Split-Listener] +type=listener +service=RW-Split-Router +protocol=MySQLClient +port=4006 + +[Read-Connection-Listener] +type=listener +service=Read-Connection-Router +protocol=MySQLClient +port=4009 diff --git a/maxscale-system-test/mariadb_nodes.cpp b/maxscale-system-test/mariadb_nodes.cpp index 6ae51dec7..9034a3d3f 100644 --- a/maxscale-system-test/mariadb_nodes.cpp +++ b/maxscale-system-test/mariadb_nodes.cpp @@ -939,6 +939,18 @@ std::string Mariadb_nodes::get_server_id_str(int index) return ss.str(); } +std::vector Mariadb_nodes::get_all_server_ids_str() +{ + std::vector rval; + + for (int i = 0; i < N; i++) + { + rval.push_back(get_server_id_str(i)); + } + + return rval; +} + std::vector Mariadb_nodes::get_all_server_ids() { std::vector rval; diff --git a/maxscale-system-test/mariadb_nodes.h b/maxscale-system-test/mariadb_nodes.h index 7cd19a03f..48232730a 100644 --- a/maxscale-system-test/mariadb_nodes.h +++ b/maxscale-system-test/mariadb_nodes.h @@ -322,6 +322,7 @@ public: * @return List of server IDs */ std::vector get_all_server_ids(); + std::vector get_all_server_ids_str(); /** * @brief Execute 'mysqladmin flush-hosts' on all nodes diff --git a/maxscale-system-test/mxs2313_rank.cpp b/maxscale-system-test/mxs2313_rank.cpp new file mode 100644 index 000000000..c76e98278 --- /dev/null +++ b/maxscale-system-test/mxs2313_rank.cpp @@ -0,0 +1,104 @@ +/** + * MXS-2313: `rank` functional tests + * https://jira.mariadb.org/browse/MXS-2313 + */ + +#include "testconnections.h" +#include + +std::function block_wait; +std::function unblock_wait; + +void test_rwsplit(TestConnections& test, std::vector ids) +{ + std::cout << "Slaves with descending rank and a low ranking master" << std::endl; + + test.check_maxctrl("alter server server1 rank 9999"); + test.check_maxctrl("alter server server2 rank 2"); + test.check_maxctrl("alter server server3 rank 3"); + test.check_maxctrl("alter server server4 rank 4"); + + Connection c = test.maxscales->rwsplit(); + c.connect(); + test.expect(c.field("SELECT @@server_id") == ids[1], "First slave should reply"); + + block_wait(1); + test.expect(c.field("SELECT @@server_id") == ids[2], "Second slave should reply"); + + block_wait(2); + test.expect(c.field("SELECT @@server_id") == ids[3], "Third slave should reply"); + + block_wait(3); + test.expect(c.field("SELECT @@server_id") == ids[0], "Master should reply"); + + block_wait(0); + test.expect(!c.query("SELECT @@server_id"), "Query should fail"); + + unblock_wait(0); + c.disconnect(); + c.connect(); + test.expect(c.field("SELECT @@server_id") == ids[0], "Master should reply"); + + unblock_wait(3); + test.expect(c.field("SELECT @@server_id") == ids[3], "Third slave should reply"); + + unblock_wait(2); + test.expect(c.field("SELECT @@server_id") == ids[2], "Second slave should reply"); + + unblock_wait(1); + test.expect(c.field("SELECT @@server_id") == ids[1], "First slave should reply"); + + std::cout << "Grouping servers into a three-node cluster with one low-ranking server" << std::endl; + + test.check_maxctrl("alter server server1 rank 1"); + test.check_maxctrl("alter server server2 rank 1"); + test.check_maxctrl("alter server server3 rank 1"); + test.check_maxctrl("alter server server4 rank 9999"); + + block_wait(0); + auto id = c.field("SELECT @@server_id"); + test.expect(!id.empty() && id != ids[3], "Third slave should not reply"); + + block_wait(1); + id = c.field("SELECT @@server_id"); + test.expect(!id.empty() && id != ids[3], "Third slave should not reply"); + + block_wait(2); + test.expect(c.field("SELECT @@server_id") == ids[3], "Third slave should reply"); + + for (int i = 0; i < 3; i++) + { + unblock_wait(i); + auto id = c.field("SELECT @@server_id"); + test.expect(!id.empty() && id != ids[3], "Third slave should not reply"); + } + + test.check_maxctrl("alter server server1 rank 1"); + test.check_maxctrl("alter server server2 rank 2"); + test.check_maxctrl("alter server server3 rank 3"); + test.check_maxctrl("alter server server4 rank 4"); +} + +int main(int argc, char* argv[]) +{ + TestConnections test(argc, argv); + + block_wait = [&](int node) { + std::cout << "Block server" << (node + 1) << std::endl; + test.repl->block_node(node); + test.maxscales->wait_for_monitor(2); + }; + unblock_wait = [&](int node) { + std::cout << "Unblock server" << (node + 1) << std::endl; + test.repl->unblock_node(node); + test.maxscales->wait_for_monitor(2); + }; + + test.repl->connect(); + auto ids = test.repl->get_all_server_ids_str(); + test.repl->disconnect(); + + test_rwsplit(test, ids); + + return test.global_result; +}