From 3424158b7c7338add100493d47cedfb33f239016 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Wed, 26 Jun 2019 09:46:05 +0300 Subject: [PATCH] MXS-2572 Add basic smartrouter test Very simple, creates 10 threads that concurrently starts making simple INSERTs and SELECTs. The purpose is to test that the basic router to router mechanism of smartrouter works. --- maxscale-system-test/CMakeLists.txt | 3 + .../cnf/maxscale.cnf.template.sr_basics | 87 +++++++++++ maxscale-system-test/mariadb_func.h | 5 + maxscale-system-test/sr_basics.cpp | 147 ++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 maxscale-system-test/cnf/maxscale.cnf.template.sr_basics create mode 100644 maxscale-system-test/sr_basics.cpp diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index ac3c9ab54..bca607f34 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -991,6 +991,9 @@ add_test_executable(mxs2563_concurrent_slave_failure.cpp mxs2563_concurrent_slav # MXS-2521: COM_STMT_EXECUTE maybe return empty result add_test_executable(mxs2521_double_exec.cpp mxs2521_double_exec mxs2521_double_exec LABELS REPL_BACKEND readwritesplit) +# MXS-2572: Add smartrouter tests. +add_test_executable(sr_basics.cpp sr_basics sr_basics LABELS REPL_BACKEND) + ############################################ # BEGIN: binlogrouter and avrorouter tests # ############################################ diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.sr_basics b/maxscale-system-test/cnf/maxscale.cnf.template.sr_basics new file mode 100644 index 000000000..e9386d857 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.sr_basics @@ -0,0 +1,87 @@ +[maxscale] +threads=###threads### +log_warning=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 + +[The-Monitor] +type=monitor +module=mysqlmon +servers=server1, server2, server3, server4 +user=maxskysql +password=skysql +monitor_interval=1000 + +[RWS1] +type=service +router=readwritesplit +servers=server1, server2, server3, server4 +user=maxskysql +password=skysql +slave_selection_criteria=LEAST_ROUTER_CONNECTIONS + +[RWS1-Listener] +type=listener +service=RWS1 +protocol=mariadbclient +socket=/tmp/rws1.sock + +[RWS1-As-Server] +type=server +protocol=mariadbbackend +socket=/tmp/rws1.sock + +[RWS2] +type=service +router=readwritesplit +servers=server1, server2, server3, server4 +user=maxskysql +password=skysql +slave_selection_criteria=LEAST_ROUTER_CONNECTIONS + +[RWS2-Listener] +type=listener +service=RWS2 +protocol=MySQLClient +socket=/tmp/rws2.sock + +[RWS2-As-Server] +type=server +protocol=mariadbbackend +socket=/tmp/rws2.sock + +[SQ] +type=service +router=smartrouter +servers=RWS1-As-Server, RWS2-As-Server +master=RWS1-As-Server +user=maxskysql +password=skysql + +[SQ-Listener] +type=listener +service=SQ +protocol=mariadbclient +port=4006 diff --git a/maxscale-system-test/mariadb_func.h b/maxscale-system-test/mariadb_func.h index 86fb5fc69..46300bf6d 100644 --- a/maxscale-system-test/mariadb_func.h +++ b/maxscale-system-test/mariadb_func.h @@ -321,6 +321,11 @@ public: return get_row(m_conn, q); } + Result rows(const std::string& q) const + { + return get_result(m_conn, q); + } + std::string field(std::string q, int idx = 0) { Row r = get_row(m_conn, q); diff --git a/maxscale-system-test/sr_basics.cpp b/maxscale-system-test/sr_basics.cpp new file mode 100644 index 000000000..380a1ee39 --- /dev/null +++ b/maxscale-system-test/sr_basics.cpp @@ -0,0 +1,147 @@ +/* + * 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: 2023-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 namespace std; + +namespace +{ + +void init(TestConnections& test, Connection& c) +{ + test.expect(c.query("DROP TABLE IF EXISTS sq"), "Could not drop table."); + test.expect(c.query("CREATE TABLE sq (id INT, value INT)"), "Could not create table."); + sleep(2); +} + +void finish(TestConnections& test, Connection& c) +{ + test.expect(c.query("DROP TABLE IF EXISTS sq"), "Could not drop table."); +} + +const size_t N_THREADS = 10; +const size_t N_INSERTS = 100; +const size_t N_SELECTS = 10; + +void thread_stress(TestConnections* pTest, int id) +{ + string greeting("Hello from thread "); + greeting += std::to_string(id); + greeting += "\n"; + + cout << greeting << flush; + + Connection c = pTest->maxscales->rwsplit(); + + c.connect(); + + string preamble("INSERT INTO sq VALUES ("); + preamble += std::to_string(id); + preamble += ", "; + + for (size_t i = 0; i < N_INSERTS; ++i) + { + string query = preamble + std::to_string(i) + ")"; + + c.query(query); + + for (size_t i = 0; i < N_SELECTS; ++i) + { + c.query("SELECT * FROM sq"); + } + } + + string goodbye("Goodbye from thread "); + goodbye += std::to_string(id); + goodbye += "\n"; + + cout << goodbye << flush; +} + +void test_stress(TestConnections& test) +{ + vector threads; + + for (size_t i = 0; i < N_THREADS; ++i) + { + thread t(thread_stress, &test, i); + + threads.emplace_back(std::move(t)); + } + + for (size_t i = 0; i < threads.size(); ++i) + { + threads[i].join(); + } + + Connection c = test.maxscales->rwsplit(); + c.connect(); + + Result rows = c.rows("SELECT * FROM sq"); + test.expect(rows.size() == N_THREADS * N_INSERTS, + "Expected %lu inserts in total, but found %lu.", N_THREADS * N_INSERTS, rows.size()); + + map> found_results; + + for (const auto& row : rows) + { + mxb_assert(row.size() == 2); + + string tid { row[0] }; + string f { row[1] }; + + found_results[tid].push_back(f); + } + + test.expect(found_results.size() == N_THREADS, + "Expected results from %lu threads, but found %lu.", N_THREADS, found_results.size()); + + for (const auto& kv : found_results) + { + const string& tid { kv.first }; + const vector& fields { kv.second }; + + test.expect(fields.size() == N_INSERTS, + "Expected %lu inserts for thread %s, but found only %lu.", + N_INSERTS, tid.c_str(), fields.size()); + } +} + +void run_tests(TestConnections& test) +{ + test_stress(test); +} + +} + +int main(int argc, char* argv[]) +{ + TestConnections test(argc, argv); + + Connection c = test.maxscales->rwsplit(); + + test.expect(c.connect(), "Could not connect to MaxScale."); + + init(test, c); + + run_tests(test); + + finish(test, c); + + return test.global_result; +}