MXS-2131: Add sanity check test
The sanity check replaces several old regression tests and provides a quick test for checking mainly the readwritesplit routing behavior. It also checks some of the connection counts and runs queries that once caused a crash. The set of tests that the sanity check obsoletes is: bug422 bug469 bug448 bug507 bug509 bug634 bug694 bug669 bug711 mxs127 mxs47 mxs682_cyrillic mxs957 mxs1786_statistics rwsplit_read_only_trx
This commit is contained in:
@ -61,6 +61,9 @@ add_test_executable(config_test.cpp config_test replication LABELS CONFIG)
|
||||
|
||||
add_subdirectory(cdc_datatypes)
|
||||
|
||||
# Routing sanity check
|
||||
add_test_executable(sanity_check.cpp sanity_check replication LABELS LIGHT REPL_BACKEND)
|
||||
|
||||
# Repeatedly connect to maxscale while the backends reject all connections, expect no crash
|
||||
add_test_executable(backend_auth_fail.cpp backend_auth_fail replication LABELS readconnroute REPL_BACKEND)
|
||||
|
||||
|
@ -323,10 +323,10 @@ public:
|
||||
return get_row(m_conn, q);
|
||||
}
|
||||
|
||||
std::string field(std::string q)
|
||||
std::string field(std::string q, int idx = 0)
|
||||
{
|
||||
Row r = get_row(m_conn, q);
|
||||
return r.empty() ? std::string() : r[0];
|
||||
return r.empty() ? std::string() : r[idx];
|
||||
}
|
||||
|
||||
const char* error() const
|
||||
|
131
maxscale-system-test/sanity_check.cpp
Normal file
131
maxscale-system-test/sanity_check.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Sanity check for basic functionality
|
||||
*
|
||||
* Combines several old regression tests into one quick test.
|
||||
*/
|
||||
|
||||
#include "testconnections.h"
|
||||
|
||||
|
||||
void test_rwsplit(TestConnections& test)
|
||||
{
|
||||
test.set_timeout(300);
|
||||
test.repl->connect();
|
||||
std::string master_id = test.repl->get_server_id_str(0);
|
||||
test.repl->disconnect();
|
||||
|
||||
auto c = test.maxscales->rwsplit();
|
||||
test.expect(c.connect(), "Connection to readwritesplit should succeed");
|
||||
|
||||
// Transactions to master
|
||||
c.query("START TRANSACTION");
|
||||
test.expect(c.field("SELECT @@server_id") == master_id,
|
||||
"START TRANSACTION should go to the master");
|
||||
c.query("COMMIT");
|
||||
|
||||
// Read-only transactions to slave
|
||||
c.query("START TRANSACTION READ ONLY");
|
||||
test.expect(c.field("SELECT @@server_id") != master_id,
|
||||
"START TRANSACTION READ ONLY should go to a slave");
|
||||
c.query("COMMIT");
|
||||
|
||||
// @@last_insert_id routed to master
|
||||
test.expect(c.field("SELECT @@server_id, @@last_insert_id") == master_id,
|
||||
"@@last_insert_id should go to the master");
|
||||
test.expect(c.field("SELECT last_insert_id(), @@server_id", 1) == master_id,
|
||||
"@@last_insert_id should go to the master");
|
||||
|
||||
// Replication related queries
|
||||
test.expect(!c.row("SHOW SLAVE STATUS").empty(),
|
||||
"SHOW SLAVE STATUS should go to a slave");
|
||||
|
||||
// User variable modification in SELECT
|
||||
test.expect(!c.query("SELECT @a:=@a+1 as a, user FROM mysql"),
|
||||
"Query with variable modification should fail");
|
||||
|
||||
// Repeated session commands
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
test.expect(c.query("set @test=" + std::to_string(i)), "SET should work: %s", c.error());
|
||||
}
|
||||
|
||||
// Large result sets
|
||||
for (int i = 1; i < 5000; i += 7)
|
||||
{
|
||||
c.query("SELECT REPEAT('a'," + std::to_string(i) + ")");
|
||||
}
|
||||
|
||||
// Non ASCII characters
|
||||
c.query("CREATE OR REPLACE TABLE test.t1 AS SELECT 'Кот'");
|
||||
c.query("BEGIN");
|
||||
c.check("SELECT * FROM test.t1", "Кот");
|
||||
c.query("COMMIT");
|
||||
c.query("DROP TABLE test.t1");
|
||||
|
||||
// Temporary tables
|
||||
for (auto a : {
|
||||
"USE test",
|
||||
"CREATE OR REPLACE TABLE t1(`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY)",
|
||||
"CREATE OR REPLACE TABLE t2(`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY)",
|
||||
"CREATE TEMPORARY TABLE temp1(`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY)",
|
||||
"INSERT INTO temp1 values (1), (2), (3)",
|
||||
"INSERT INTO t1 values (1), (2), (3)",
|
||||
"INSERT INTO t2 values (1), (2), (3)",
|
||||
"CREATE TEMPORARY TABLE temp2 SELECT DISTINCT p.id FROM temp1 p JOIN t1 t "
|
||||
" ON (t.id = p.id) LEFT JOIN t2 ON (t.id = t2.id) WHERE p.id IS NOT NULL "
|
||||
" AND @@server_id IS NOT NULL",
|
||||
"SELECT * FROM temp2",
|
||||
"DROP TABLE t1",
|
||||
"DROP TABLE t2"
|
||||
})
|
||||
{
|
||||
test.expect(c.query(a), "Temp table query failed");
|
||||
}
|
||||
|
||||
// Temporary and real table overlap
|
||||
c.query("CREATE OR REPLACE TABLE test.t1 AS SELECT 1 AS id");
|
||||
c.query("CREATE TEMPORARY TABLE test.t1 AS SELECT 2 AS id");
|
||||
c.check("SELECT id FROM test.t1", "2");
|
||||
c.query("DROP TABLE test.t1");
|
||||
c.query("DROP TABLE test.t1");
|
||||
|
||||
// COM_STATISTICS
|
||||
test.maxscales->connect();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
mysql_stat(test.maxscales->conn_rwsplit[0]);
|
||||
test.try_query(test.maxscales->conn_rwsplit[0], "SELECT 1");
|
||||
}
|
||||
test.maxscales->disconnect();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TestConnections test(argc, argv);
|
||||
|
||||
auto connections = [&]() {
|
||||
return test.maxctrl("api get servers/server1 data.attributes.statistics.connections").second;
|
||||
};
|
||||
|
||||
test.expect(connections()[0] == '0', "The master should have no connections");
|
||||
test.maxscales->connect();
|
||||
test.expect(connections()[0] == '2', "The master should have two connections");
|
||||
test.maxscales->disconnect();
|
||||
test.expect(connections()[0] == '0', "The master should have no connections");
|
||||
|
||||
test.maxscales->connect();
|
||||
for (auto a : {"show status", "show variables", "show global status"})
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
test.try_query(test.maxscales->conn_rwsplit[0], "%s", a);
|
||||
test.try_query(test.maxscales->conn_master[0], "%s", a);
|
||||
}
|
||||
}
|
||||
test.maxscales->disconnect();
|
||||
|
||||
// Readwritesplit sanity checks
|
||||
test_rwsplit(test);
|
||||
|
||||
return test.global_result;
|
||||
}
|
Reference in New Issue
Block a user