MXS-1507: Add basic functional test

Added functional tests that cover the basic cases.
This commit is contained in:
Markus Mäkelä
2018-04-23 17:27:35 +03:00
parent cb5917b346
commit cffed86962
3 changed files with 252 additions and 0 deletions

View File

@ -613,6 +613,10 @@ add_test_executable(mxs1506_delayed_retry.cpp mxs1506_delayed_retry mxs1506_dela
# https://jira.mariadb.org/browse/MXS-1506
add_test_executable(mxs1506_no_master.cpp mxs1506_no_master mxs1506_delayed_retry LABELS readwritesplit REPL_BACKEND)
# MXS-1507: Transaction replay
# https://jira.mariadb.org/browse/MXS-1507
add_test_executable(mxs1507_trx_replay.cpp mxs1507_trx_replay mxs1507_trx_replay LABELS readwritesplit REPL_BACKEND)
# MXS-1509: Show correct server state for multisource replication
# https://jira.mariadb.org/browse/MXS-1509
add_test_executable(mxs1509.cpp mxs1509 mxs1509 LABELS mysqlmon REPL_BACKEND)

View File

@ -0,0 +1,60 @@
[maxscale]
threads=###threads###
log_info=1
[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
transaction_replay=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

View File

@ -0,0 +1,188 @@
/**
* MXS-1507: Transaction replay tests
*
* https://jira.mariadb.org/browse/MXS-1507
*/
#include "testconnections.h"
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char** argv)
{
TestConnections test(argc, argv);
auto query = [&](string q)
{
return execute_query_silent(test.maxscales->conn_rwsplit[0], q.c_str()) == 0;
};
auto ok = [&](string q)
{
test.assert(query(q), "Query '%s' should work: %s", q.c_str(), mysql_error(test.maxscales->conn_rwsplit[0]));
};
auto err = [&](string q)
{
test.assert(!query(q), "Query should not work: %s", q.c_str());
};
auto check = [&](string q)
{
Row row = get_row(test.maxscales->conn_rwsplit[0], q.c_str());
test.assert(!row.empty() && row[0] == "1", "Query should return 1: %s", q.c_str());
};
struct TrxTest
{
string description;
vector<function<void ()>> pre;
vector<function<void ()>> post;
vector<function<void ()>> check;
}
tests[] =
{
{
"Basic transaction",
{
bind(ok, "BEGIN"),
bind(ok, "SELECT 1"),
},
{
bind(ok, "SELECT 2"),
bind(ok, "COMMIT"),
},
},
{
"Transaction with a write",
{
bind(ok, "BEGIN"),
bind(ok, "INSERT INTO test.t1 VALUES (1)"),
},
{
bind(ok, "INSERT INTO test.t1 VALUES (2)"),
bind(ok, "COMMIT"),
},
{
bind(check, "SELECT COUNT(*) = 2 FROM test.t1 WHERE id IN (1, 2)"),
}
},
{
"Read-only transaction",
{
bind(ok, "START TRANSACTION READ ONLY"),
bind(ok, "SELECT 1"),
},
{
bind(ok, "SELECT 2"),
bind(ok, "COMMIT"),
},
},
{
"Trx started, no queries",
{
bind(ok, "BEGIN"),
},
{
bind(ok, "SELECT 1"),
bind(ok, "COMMIT"),
},
},
{
"Trx waiting on commit",
{
bind(ok, "BEGIN"),
bind(ok, "SELECT 1"),
},
{
bind(ok, "COMMIT"),
},
},
{
"Trx with NOW()",
{
bind(ok, "BEGIN"),
bind(ok, "SELECT NOW(), SLEEP(1)"),
},
{
bind(err, "SELECT 1"),
},
},
{
"Commit trx with NOW()",
{
bind(ok, "BEGIN"),
bind(ok, "SELECT NOW(), SLEEP(1)"),
},
{
bind(err, "COMMIT"),
},
},
{
"NOW() used after replay",
{
bind(ok, "BEGIN"),
bind(ok, "SELECT 1"),
},
{
bind(ok, "SELECT NOW()"),
bind(ok, "COMMIT"),
},
},
};
// Create a table for testing
test.maxscales->connect();
test.try_query(test.maxscales->conn_rwsplit[0], "CREATE OR REPLACE TABLE test.t1(id INT)");
test.maxscales->disconnect();
int i = 1;
for (auto& a : tests)
{
cout << i++ << ": " << a.description << endl;
test.maxscales->connect();
for (auto& f : a.pre)
{
f();
}
// Block and unblock the master
test.repl->block_node(0);
sleep(8);
test.repl->unblock_node(0);
sleep(8);
for (auto& f : a.post)
{
f();
}
test.maxscales->disconnect();
test.repl->connect();
test.repl->sync_slaves();
test.repl->disconnect();
test.maxscales->connect();
for (auto& f : a.check)
{
f();
}
test.maxscales->disconnect();
// Clear the table at the end of the test
test.maxscales->connect();
test.try_query(test.maxscales->conn_rwsplit[0], "TRUNCATE TABLE test.t1");
test.maxscales->disconnect();
}
test.maxscales->connect();
test.try_query(test.maxscales->conn_rwsplit[0], "DROP TABLE test.t1");
test.maxscales->disconnect();
return test.global_result;
}