MXS-2976 Reinforce mysqlmon_multimaster test
Compares server states as sets. Stops MaxScale during some cluster modifications to ensure consistency.
This commit is contained in:
@ -5,10 +5,9 @@ log_warning=1
|
|||||||
[MySQL-Monitor]
|
[MySQL-Monitor]
|
||||||
type=monitor
|
type=monitor
|
||||||
module=mysqlmon
|
module=mysqlmon
|
||||||
servers= server1, server2, server3, server4
|
servers=server1, server2, server3, server4
|
||||||
user=maxskysql
|
user=maxskysql
|
||||||
password= skysql
|
password=skysql
|
||||||
detect_stale_master=0
|
|
||||||
monitor_interval=1000
|
monitor_interval=1000
|
||||||
|
|
||||||
[RW-Split-Router]
|
[RW-Split-Router]
|
||||||
@ -20,40 +19,12 @@ password=skysql
|
|||||||
slave_selection_criteria=LEAST_ROUTER_CONNECTIONS
|
slave_selection_criteria=LEAST_ROUTER_CONNECTIONS
|
||||||
max_slave_replication_lag=1
|
max_slave_replication_lag=1
|
||||||
|
|
||||||
[Read-Connection-Router-Slave]
|
|
||||||
type=service
|
|
||||||
router=readconnroute
|
|
||||||
router_options= slave
|
|
||||||
servers=server1,server2
|
|
||||||
user=maxskysql
|
|
||||||
password=skysql
|
|
||||||
|
|
||||||
[Read-Connection-Router-Master]
|
|
||||||
type=service
|
|
||||||
router=readconnroute
|
|
||||||
router_options=master
|
|
||||||
servers=server1,server2
|
|
||||||
user=maxskysql
|
|
||||||
password=skysql
|
|
||||||
|
|
||||||
[RW-Split-Listener]
|
[RW-Split-Listener]
|
||||||
type=listener
|
type=listener
|
||||||
service=RW-Split-Router
|
service=RW-Split-Router
|
||||||
protocol=MySQLClient
|
protocol=MySQLClient
|
||||||
port=4006
|
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]
|
[CLI]
|
||||||
type=service
|
type=service
|
||||||
router=cli
|
router=cli
|
||||||
|
|||||||
@ -19,33 +19,47 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
#include "testconnections.h"
|
#include "testconnections.h"
|
||||||
#include "maxadmin_operations.h"
|
#include "maxadmin_operations.h"
|
||||||
#include "sql_t1.h"
|
#include "sql_t1.h"
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include <string>
|
#include <maxbase/string.hh>
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::set;
|
||||||
|
|
||||||
void check_status(TestConnections& test, const char* server, const char* status)
|
void check_status(TestConnections& test, const string& server, const set<string>& expected_status)
|
||||||
{
|
{
|
||||||
char cmd[256];
|
string cmd = "show server " + server;
|
||||||
char maxadmin_result[1024];
|
char buf[100];
|
||||||
|
|
||||||
sprintf(cmd, "show server %s", server);
|
test.maxscales->get_maxadmin_param(0, cmd.c_str(), "Status:", buf);
|
||||||
test.maxscales->get_maxadmin_param(0, cmd, (char*)"Status:", maxadmin_result);
|
string maxadmin_result = buf;
|
||||||
|
|
||||||
if (maxadmin_result == NULL)
|
if (maxadmin_result.empty())
|
||||||
{
|
{
|
||||||
test.add_result(1, "maxadmin execution error\n");
|
test.expect(false, "maxadmin execution error\n");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (strstr(maxadmin_result, status) == NULL)
|
|
||||||
{
|
{
|
||||||
test.add_result(1, "Test failed, server '%s' status is '%s', expected '%s'\n",
|
// First tokenize by comma, then trim. Cannot tokenize by whitespace due to
|
||||||
server, maxadmin_result, status);
|
// "Relay Master"-element.
|
||||||
|
auto tokens = mxb::strtok(maxadmin_result, ",");
|
||||||
|
auto trimmer = [](string& s) {
|
||||||
|
mxb::trim(s);
|
||||||
|
};
|
||||||
|
std::for_each(tokens.begin(), tokens.end(), trimmer);
|
||||||
|
set<string> tokenset(tokens.begin(), tokens.end());
|
||||||
|
|
||||||
|
if (tokenset != expected_status)
|
||||||
|
{
|
||||||
|
auto expected_joined = mxb::join(expected_status);
|
||||||
|
test.expect(false, "Wrong states for '%s'. Got '%s', expected '%s'.",
|
||||||
|
server.c_str(), maxadmin_result.c_str(), expected_joined.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +113,9 @@ json_t* find_array_elem_json(TestConnections& test, json_t* object,
|
|||||||
json_t* arr_elem = json_array_get(object, i);
|
json_t* arr_elem = json_array_get(object, i);
|
||||||
json_t* elem_val = json_object_get(arr_elem, key.c_str());
|
json_t* elem_val = json_object_get(arr_elem, key.c_str());
|
||||||
bool is_string = json_is_string(elem_val);
|
bool is_string = json_is_string(elem_val);
|
||||||
test.expect(is_string, "Key %s was not found in json data or the data is not string.\n", key.c_str());
|
test.expect(is_string,
|
||||||
|
"Key %s was not found in json data or the data is not string.\n",
|
||||||
|
key.c_str());
|
||||||
if (is_string)
|
if (is_string)
|
||||||
{
|
{
|
||||||
std::string elem_field = json_string_value(elem_val);
|
std::string elem_field = json_string_value(elem_val);
|
||||||
@ -164,7 +180,7 @@ void check_rlag(TestConnections& test, const char* server, int min_rlag, int max
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void change_master(TestConnections& test ,int slave, int master, const string& conn_name = "",
|
void change_master(TestConnections& test, int slave, int master, const string& conn_name = "",
|
||||||
int replication_delay = 0)
|
int replication_delay = 0)
|
||||||
{
|
{
|
||||||
const char query[] = "CHANGE MASTER '%s' TO master_host='%s', master_port=%d, "
|
const char query[] = "CHANGE MASTER '%s' TO master_host='%s', master_port=%d, "
|
||||||
@ -172,20 +188,25 @@ void change_master(TestConnections& test ,int slave, int master, const string& c
|
|||||||
"master_user='repl', master_password='repl', master_delay=%d; "
|
"master_user='repl', master_password='repl', master_delay=%d; "
|
||||||
"START SLAVE '%s';";
|
"START SLAVE '%s';";
|
||||||
test.try_query(test.repl->nodes[slave], query, conn_name.c_str(),
|
test.try_query(test.repl->nodes[slave], query, conn_name.c_str(),
|
||||||
test.repl->IP_private[master], test.repl->port[master],
|
test.repl->IP_private[master], test.repl->port[master],
|
||||||
replication_delay, conn_name.c_str());
|
replication_delay, conn_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
const char mm_master_states[] = "Master, Running";
|
string master = "Master";
|
||||||
const char mm_slave_states[] = "Relay Master, Slave, Running";
|
string running = "Running";
|
||||||
const char slave_states[] = "Slave, Running";
|
string slave = "Slave";
|
||||||
const char running_state[] = "Running";
|
|
||||||
|
set<string> mm_master_states = {master, running};
|
||||||
|
set<string> mm_slave_states = {"Relay Master", slave, running};
|
||||||
|
set<string> slave_states = {slave, running};
|
||||||
|
set<string> running_state = {running};
|
||||||
|
|
||||||
const char reset_query[] = "STOP SLAVE; RESET SLAVE ALL; RESET MASTER; SET GLOBAL read_only='OFF'";
|
const char reset_query[] = "STOP SLAVE; RESET SLAVE ALL; RESET MASTER; SET GLOBAL read_only='OFF'";
|
||||||
const char readonly_on_query[] = "SET GLOBAL read_only='ON'";
|
const char readonly_on_query[] = "SET GLOBAL read_only='ON'";
|
||||||
|
|
||||||
TestConnections::require_repl_version("10.2.3"); // Delayed replication needs this.
|
TestConnections::require_repl_version("10.2.3"); // Delayed replication needs this.
|
||||||
TestConnections test(argc, argv);
|
TestConnections test(argc, argv);
|
||||||
|
|
||||||
test.tprintf("Test 1 - Configure all servers into a multi-master ring with one slave");
|
test.tprintf("Test 1 - Configure all servers into a multi-master ring with one slave");
|
||||||
@ -237,15 +258,20 @@ int main(int argc, char* argv[])
|
|||||||
test.tprintf("Test 3 - Configure nodes 1 and 2 into a master-master pair, make node 0 "
|
test.tprintf("Test 3 - Configure nodes 1 and 2 into a master-master pair, make node 0 "
|
||||||
"a slave of node 1 and node 3 a slave of node 2");
|
"a slave of node 1 and node 3 a slave of node 2");
|
||||||
|
|
||||||
|
test.maxscales->stop_maxscale();
|
||||||
test.set_timeout(120);
|
test.set_timeout(120);
|
||||||
test.repl->execute_query_all_nodes(reset_query);
|
test.repl->execute_query_all_nodes(reset_query);
|
||||||
test.repl->connect();
|
test.repl->connect();
|
||||||
|
|
||||||
change_master(test, 0, 1);
|
change_master(test, 0, 1);
|
||||||
change_master(test, 1, 2);
|
change_master(test, 1, 2);
|
||||||
change_master(test, 2, 1, "", max_rlag);
|
change_master(test, 2, 1, "", max_rlag);
|
||||||
change_master(test, 3, 2);
|
change_master(test, 3, 2);
|
||||||
|
|
||||||
|
test.maxscales->start_maxscale();
|
||||||
|
sleep(2);
|
||||||
test.maxscales->wait_for_monitor(1);
|
test.maxscales->wait_for_monitor(1);
|
||||||
|
|
||||||
maxconn = test.maxscales->open_rwsplit_connection();
|
maxconn = test.maxscales->open_rwsplit_connection();
|
||||||
test.try_query(maxconn, "FLUSH TABLES;");
|
test.try_query(maxconn, "FLUSH TABLES;");
|
||||||
mysql_close(maxconn);
|
mysql_close(maxconn);
|
||||||
@ -278,14 +304,18 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
test.tprintf("Test 5 - Create two distinct groups");
|
test.tprintf("Test 5 - Create two distinct groups");
|
||||||
|
|
||||||
|
test.maxscales->stop_maxscale();
|
||||||
test.set_timeout(120);
|
test.set_timeout(120);
|
||||||
test.repl->execute_query_all_nodes(reset_query);
|
test.repl->execute_query_all_nodes(reset_query);
|
||||||
test.repl->connect();
|
test.repl->connect();
|
||||||
|
|
||||||
change_master(test, 0, 1);
|
change_master(test, 0, 1);
|
||||||
change_master(test, 1, 0);
|
change_master(test, 1, 0);
|
||||||
change_master(test, 2, 3);
|
change_master(test, 2, 3);
|
||||||
change_master(test, 3, 2);
|
change_master(test, 3, 2);
|
||||||
|
|
||||||
|
test.maxscales->start_maxscale();
|
||||||
|
sleep(2);
|
||||||
test.maxscales->wait_for_monitor(1);
|
test.maxscales->wait_for_monitor(1);
|
||||||
|
|
||||||
// Even though the servers are in two distinct groups, only one of them
|
// Even though the servers are in two distinct groups, only one of them
|
||||||
@ -330,7 +360,8 @@ int main(int argc, char* argv[])
|
|||||||
test.maxscales->wait_for_monitor(1);
|
test.maxscales->wait_for_monitor(1);
|
||||||
maxconn = test.maxscales->open_rwsplit_connection();
|
maxconn = test.maxscales->open_rwsplit_connection();
|
||||||
test.try_query(maxconn, "FLUSH TABLES;");
|
test.try_query(maxconn, "FLUSH TABLES;");
|
||||||
test.maxscales->wait_for_monitor(1);
|
test.maxscales->wait_for_monitor(2);
|
||||||
|
test.try_query(maxconn, "SHOW DATABASES;");
|
||||||
|
|
||||||
check_status(test, "server1", slave_states);
|
check_status(test, "server1", slave_states);
|
||||||
check_status(test, "server2", mm_slave_states);
|
check_status(test, "server2", mm_slave_states);
|
||||||
@ -346,7 +377,7 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
const char remove_delay[] = "STOP SLAVE '%s'; CHANGE MASTER '%s' TO master_delay=0; START SLAVE '%s';";
|
const char remove_delay[] = "STOP SLAVE '%s'; CHANGE MASTER '%s' TO master_delay=0; START SLAVE '%s';";
|
||||||
test.try_query(test.repl->nodes[0], remove_delay, "a", "a", "a");
|
test.try_query(test.repl->nodes[0], remove_delay, "a", "a", "a");
|
||||||
test.maxscales->wait_for_monitor(1);
|
test.maxscales->wait_for_monitor(2);
|
||||||
|
|
||||||
check_status(test, "server1", slave_states);
|
check_status(test, "server1", slave_states);
|
||||||
check_rlag(test, "server1", 0, 0);
|
check_rlag(test, "server1", 0, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user