add tests

This commit is contained in:
Timofey Turenko 2017-05-17 18:16:06 +03:00 committed by Markus Mäkelä
parent dbfd631fed
commit 8c6ca38a8a
594 changed files with 48376 additions and 0 deletions

9
.gitignore vendored
View File

@ -32,6 +32,7 @@ depend.mk
.#*
._*
# Vi swap files
.*.swp
/build/
@ -51,3 +52,11 @@ CMakeFiles/*
*/*/*/*/CMakeFiles/*
Makefile
/.DS_Store
# Netbeans Project files
nbproject/
/build/
# RBCommons
.reviewboardrc

View File

@ -0,0 +1,702 @@
# Building test package:
#
# apt-get install libssl-dev libmariadbclient-dev php5 perl \
# coreutils realpath libjansson-dev openjdk-7-jdk
# pip install JayDeBeApi
# Backend labes:
# REPL_BACKEND
# GALERA_BACKEND
# EXTERN_BACKEND
# BREAKS_REPL
# BREAKS_GALERA
project(maxscale_system_test)
cmake_minimum_required(VERSION 2.8)
include_directories("/usr/include/mysql/")
set(CTEST_BUILD_NAME "${BUILDNAME}")
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of
build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug
Release RelWithDebInfo MinSizeRel.")
set(CMAKE_CXX_FLAGS "-std=c++11 -ggdb")
set(CMAKE_CXX_FLAGS_DEBUG "-std=c++11 -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "-std=c++11 -ggdb")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-std=c++11 -ggdb")
enable_testing()
# utilities.cmake contains all helper functions and extra tools
include(utilities.cmake)
# Is this needed?
configure_file(${CMAKE_SOURCE_DIR}/cnf/maxscale.cnf.template.setup_binlog.in ${CMAKE_BINARY_DIR}/cnf/maxscale.cnf.template.setup_binlog @ONLY)
# Enable Java
find_package(Java)
if(EXISTS ${Java_JAVA_EXECUTABLE} ${JAVA_JAVAC_EXECUTABLE} ${JAVA_JAR_EXECUTABLE})
include(UseJava)
if(Java_FOUND)
add_subdirectory(maxscale/java/)
endif()
else()
message(WARNING "Java not found, Java based tests are not run.")
endif()
# The core library
add_library(testcore SHARED testconnections.cpp mariadb_nodes.cpp
mariadb_func.cpp get_com_select_insert.cpp maxadmin_operations.cpp big_transaction.cpp
sql_t1.cpp test_binlog_fnc.cpp get_my_ip.cpp big_load.cpp get_com_select_insert.cpp
different_size.cpp fw_copy_rules maxinfo_func.cpp config_operations.cpp rds_vpc.cpp execute_cmd.cpp
blob_test.cpp cdc_connector.cpp)
target_link_libraries(testcore ${MYSQL_CLIENT} z crypt nsl m pthread ssl crypto dl rt jansson)
install(TARGETS testcore DESTINATION system-test)
add_dependencies(testcore connector-c)
# Tool used to check backend state
add_test_executable_notest(check_backend.cpp check_backend check_backend LABELS CONFIG)
# Configuration tests
add_template(bug359 bug359)
add_template(bug495 bug495)
add_template(bug526 bug526)
add_template(bug479 bug479)
add_template(bug493 bug493)
add_template(bug643_1 bug643_1)
add_template(mxs652_bad_ssl bad_ssl)
add_template(mxs710_bad_socket mxs710_bad_socket)
add_template(mxs710_bad_socket mxs711_two_ports)
add_template(mxs720_line_with_no_equal mxs720_line_with_no_equal)
add_template(mxs720_wierd_line mxs720_wierd_line)
add_template(mxs710_bad_socket mxs799)
add_test_executable(config_test.cpp config_test replication LABELS CONFIG)
add_subdirectory(cdc_datatypes)
# 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)
# Regression case for the bug "MaxScale ignores host in user authentication"
add_test_executable(bug143.cpp bug143 replication LABELS MySQLAuth REPL_BACKEND)
# Regression case for the bug "Executing '\s' doesn't always produce complete result set"
add_test_executable(bug422.cpp bug422 replication LABELS readwritesplit readconnroute maxscale REPL_BACKEND)
# Regression case for the bug "Wildcard in host column of mysql.user table don't work properly"
add_test_executable(bug448.cpp bug448 replication LABELS MySQLAuth LIGHT REPL_BACKEND)
# Regression case for the bug "rwsplit counts every connection twice in master - counnection counts leak"
add_test_executable(bug469.cpp bug469 replication LABELS readwritesplit LIGHT REPL_BACKEND)
# Regression case for the bug "Routing Hints route to server sometimes doesn't work"
add_test_executable(bug471.cpp bug471 bug471 LABELS readwritesplit hintfilter REPL_BACKEND)
# Regression case for the bugs "malformed hints cause crash"
add_test_executable(bug473.cpp bug473 hints LABELS readwritesplit hintfilter REPL_BACKEND)
# Regression case for the bug "The end comment tag in hints isn't properly detected"
add_test_executable(bug475.cpp bug475 hints LABELS readwritesplit hintfilter REPL_BACKEND)
# Regression case for the bug "SHOW VARIABLES randomly failing with "Lost connection to MySQL server"
add_test_executable(bug488.cpp bug488 galera LABELS readwritesplit readconnroute maxscale GALERA_BACKEND)
# Regression case for the bug "rw-split router does not send last_insert_id() to master"
add_test_executable(bug507.cpp bug507 replication LABELS readwritesplit LIGHT REPL_BACKEND)
# Regression case for the bug "Referring to a nonexisting server in servers=... doesn't even raise a warning"
add_test_executable(bug509.cpp bug509 galera LABELS readwritesplit GALERA_BACKEND)
# Checks "SELECT * INTO OUTFILE" and "LOAD DATA LOCAL INFILE"
add_test_executable(bug519.cpp bug519 replication LABELS readwritesplit HEAVY REPL_BACKEND)
# Regression case for the bug "'Current no. of conns' not going down"
add_test_executable(bug529.cpp bug529 replication LABELS readwritesplit readconnroute maxscale REPL_BACKEND)
# Regression case for the bugs "get_dcb fails if slaves are not available" and "Maxscale fails to start without anything in the logs if there is no slave available"
add_test_executable(bug547.cpp bug547 replication LABELS readwritesplit REPL_BACKEND)
# Regression case for the bug "crash if max_slave_connections=10% and 4 or less backends are configured"
add_test_executable(bug681.cpp bug681 galera.bug681 LABELS readwritesplit GALERA_BACKEND)
# Regression case for the bug "crash with tee filter"
add_test_executable(bug643.cpp bug643 bug643 LABELS tee REPL_BACKEND)
# Regression case for the bug ""Different error messages from MariaDB and Maxscale"
add_test_script(bug561.sh bug561.sh replication LABELS MySQLAuth REPL_BACKEND)
# Regression case for the bug "Wrong error message for Access denied error"
add_test_script(bug562.sh bug562.sh replication LABELS MySQLAuth REPL_BACKEND)
# Regression case for the bug "Wrong charset settings"
add_test_script(bug564.sh bug564.sh replication LABELS MySQLProtocol REPL_BACKEND)
# Regression case for the bug "Clients CLIENT_FOUND_ROWS setting is ignored by maxscale"
add_test_executable(bug565.cpp bug565 replication LABELS MySQLProtocol REPL_BACKEND)
# Regression case for the bug "Crash if files from /dev/shm/ removed"
add_test_script(bug567.sh bug567.sh bug567 LABELS maxscale REPL_BACKEND)
# Regression case for the bug "Using regex filter hangs MaxScale"
add_test_executable(bug571.cpp bug571 bug571 LABELS regexfilter REPL_BACKEND)
# Attempt to use GRANT with wrong IP, expect no crash or hangs
add_test_executable(bug572.cpp bug572 replication LABELS readwritesplit REPL_BACKEND)
# Regression cases for the bug "Hint filter don't work if listed before regex filter in configuration file"
# (different filter sequence and configuration, but the same test, see .cnf for details)
add_test_script(bug585 bug587 bug585 LABELS regexfilter REPL_BACKEND)
add_test_executable(bug587.cpp bug587 bug587 LABELS regexfilter hintfilter REPL_BACKEND)
add_test_script(bug587_1 bug587 bug587_1 LABELS regexfilter hintfilter REPL_BACKEND)
# Tries to connect Maxscale when all slaves stopped
add_test_executable(bug592.cpp bug592 replication LABELS MySQLAuth readwritesplit REPL_BACKEND)
# Tries to do change user in the loop, checks that autorization is still ok
add_test_executable(bug601.cpp bug601 bug601 LABELS MySQLAuth MySQLProtocol REPL_BACKEND)
# Simple test with enable_root_user=true
add_test_executable(bug620.cpp bug620 bug620 LABELS MySQLAuth MySQLProtocol REPL_BACKEND)
# Regression case for the bug "Crash when user define with old password style (before 4.1 protocol)"
add_test_executable(bug626.cpp bug626 replication LABELS MySQLAuth MySQLProtocol REPL_BACKEND)
# Regression case for the bug 634 "SHOW SLAVE STATUS in RW SPLITTER is send to master"
add_test_executable(bug634.cpp bug634 replication LABELS readwritesplit REPL_BACKEND)
# Regression cases for several TEE filter hangs
add_test_executable(bug645.cpp bug645 bug645 LABELS tee REPL_BACKEND)
add_test_executable(bug645_1.cpp bug645_1 bug645_1 LABELS tee REPL_BACKEND)
add_test_executable(bug649.cpp bug649 bug645 LABELS tee)
add_test_executable(bug650.cpp bug650 bug650 LABELS tee REPL_BACKEND)
# Heavy test for TEE filter
add_test_script(bug648 sql_queries bug648 LABELS tee UNSTABLE HEAVY REPL_BACKEND)
# Crash when host name for some user in mysql.user is very long
add_test_executable(bug653.cpp bug653 replication LABELS MySQLAuth MySQLProtocol REPL_BACKEND)
# Crash with malformed Maxadmin command
add_test_executable(bug654.cpp bug654 replication LABELS maxscale REPL_BACKEND)
# Regression case for the bug "Tee filter: closing child session causes MaxScale to fail"
add_test_executable(bug657.cpp bug657 bug657 LABELS tee REPL_BACKEND)
# Block backends (master or all slaves) and tries to connect Maxscale
add_test_executable(bug658.cpp bug658 replication LABELS readwritesplit readconnroute maxscale REPL_BACKEND)
# Block all backends
add_test_executable(bug662.cpp bug662 replication LABELS readwritesplit readconnroute maxscale REPL_BACKEND)
# Bad TEE filter configuration
add_test_executable(bug664.cpp bug664 bug664 LABELS MySQLAuth MySQLProtocol)
# TEE fileter: execute long sequence of queries ans session commands in the loop
add_test_executable(bug670.cpp bug670 bug670 LABELS tee REPL_BACKEND)
# Regression case for the bug "MaxScale crashes if "Users table data" is empty and "show dbusers" is executed in maxadmin"
add_test_executable(bug673.cpp bug673 bug673 LABELS MySQLAuth REPL_BACKEND)
# Crash in case of backend node in Galera cluster stopping and then reconnect to Maxscale
add_test_executable(bug676.cpp bug676 galera LABELS galeramon GALERA_BACKEND)
# Rgression test for th bug "RWSplit: 'SELECT @a:=@a+1 as a, test.b FROM test' breaks client session"
add_test_executable(bug694.cpp bug694 bug694 LABELS readwritesplit REPL_BACKEND)
# Compare @@hostname from "select @@wsrep_node_name, @@hostname" and from "select @@hostname, @@wsrep_node_name"
add_test_executable(bug699.cpp bug699 galera LABELS readwritesplit LIGHT GALERA_BACKEND)
# Wrong processing of 'SET GLOBAL sql_mode="ANSI"'
add_test_executable(bug705.cpp bug705 bug705 LABELS MySQLAuth REPL_BACKEND)
# Try SHOW GLOBAL STATUS via Maxscale
add_test_executable(bug711.cpp bug711 bug711 LABELS readwritesplit REPL_BACKEND)
# Prepared statement from PHP application
add_test_executable(bug729.cpp bug729 replication LABELS readwritesplit LIGHT REPL_BACKEND)
# Regression case for the bug "Regex filter and shorter than original replacement queries MaxScale" (crash)
add_test_executable(bug730.cpp bug730 bug730 LABELS regexfilter REPL_BACKEND)
# Test MariaDB 10.2 bulk inserts
add_test_executable(bulk_insert.cpp bulk_insert bulk_insert LABELS MySQLProtocol REPL_BACKEND 10.2)
# Tests for the CCRFilter module
add_test_executable(ccrfilter.cpp ccrfilter ccrfilter LABELS ccrfilter LIGHT REPL_BACKEND)
# Tries to reconfigure replication setup to use another node as a Master
add_test_executable(change_master_during_session.cpp change_master_during_session replication LABELS readwritesplit mysqlmon REPL_BACKEND)
# Executes change_user command in the loop
add_test_executable(change_user.cpp change_user replication LABELS MySQLAuth MySQLProtocol LIGHT REPL_BACKEND)
# Tries to connect to non existing DB, expects no crash
add_test_executable(connect_to_nonexisting_db.cpp connect_to_nonexisting_db replication LABELS MySQLAuth MySQLProtoco LIGHT REPL_BACKEND)
# check if max_connections parameter works
add_test_executable(connection_limit.cpp connection_limit connection_limit LABELS maxscale LIGHT REPL_BACKEND)
# Tries to open to many connections, expect no crash
add_test_executable(crash_out_of_files.cpp crash_out_of_files load LABELS maxscale HEAVY REPL_BACKEND)
# Tries to open to many connections, expect no crash, with Galera backend
add_test_executable(crash_out_of_files_galera.cpp crash_out_of_files_galera galera LABELS maxscale HEAVY GALERA_BACKEND)
# Tries INSERTs with size close to 0x0ffffff * N
add_test_executable(different_size_rwsplit.cpp different_size_rwsplit replication LABELS readwritesplit HEAVY REPL_BACKEND)
# Tries to use 'maxkeys', 'maxpasswrd'
add_test_executable(encrypted_passwords.cpp encrypted_passwords replication LABELS maxscale LIGHT REPL_BACKEND)
# MySQL Monitor Failover Test
add_test_executable(failover_mysqlmon.cpp failover_mysqlmon failover_mysqlmon LABELS mysqlmon REPL_BACKEND)
# Test monitor state change events when manually clearing server bits
add_test_executable(false_monitor_state_change.cpp false_monitor_state_change replication LABELS mysqlmon REPL_BACKEND)
# A set of tests for Firewall filter
add_test_executable(fwf.cpp fwf fwf LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf2.cpp fwf2 fwf LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_duplicate_rules.cpp fwf_duplicate_rules fwf LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_prepared_stmt.cpp fwf_prepared_stmt fwf LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_actions.cpp fwf_actions fwf_action LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_logging.cpp fwf_logging fwf_logging LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_reload.cpp fwf_reload fwf LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_syntax.cpp fwf_syntax fwf_syntax LABELS dbfwfilter REPL_BACKEND)
add_test_executable(fwf_com_ping.cpp fwf_com_ping fwf_com_ping LABELS dbfwfilter REPL_BACKEND)
# Galera node priority test
add_test_executable(galera_priority.cpp galera_priority galera_priority LABELS galeramon LIGHT GALERA_BACKEND)
# Block and unblock Master and check that Maxscale survived
add_test_executable(kill_master.cpp kill_master replication LABELS readwritesplit LIGHT REPL_BACKEND)
# Test insertstream filter
add_test_script(insertstream insertstream.sh insertstream LABELS insertstream REPL_BACKEND)
# Check load balancing
add_test_executable(load_balancing.cpp load_balancing load LABELS readwritesplit LIGHT REPL_BACKEND)
# Check load balancing with Galera backend
add_test_executable(load_balancing_galera.cpp load_balancing_galera load_galera LABELS readwritesplit GALERA_BACKEND)
# Check load balancing parameters with Galera backend and 1 persistent connection
add_test_script(load_balancing_galera_pers1 load_balancing_galera load_galera_pers1 LABELS readwritesplit HEAVY GALERA_BACKEND)
# Check load balancing parameters with Galera backend and 10 persistent connections
add_test_script(load_balancing_galera_pers10 load_balancing_galera load_galera_pers10 LABELS readwritesplit HEAVY GALERA_BACKEND)
# Check load balancing parameters with 1 persistent connection
add_test_script(load_balancing_pers1 load_balancing load_pers1 LABELS readwritesplit HEAVY REPL_BACKEND)
# Check load balancing parameters with 10 persistent connections
add_test_script(load_balancing_pers10 load_balancing load_pers10 LABELS readwritesplit HEAVY REPL_BACKEND)
# Test with extremely big blob inserting
add_test_executable(longblob.cpp longblob longblob LABELS readwritesplit readconnroute UNSTABLE HEAVY REPL_BACKEND)
# Test with extremely big blob inserting/selecting with > 16 mb data blocks
add_test_executable(mxs1110_16mb.cpp mxs1110_16mb longblob_filters LABELS readwritesplit readconnroute HEAVY REPL_BACKEND)
# INSERT extremelly big number of rows
add_test_executable(lots_of_rows.cpp lots_of_rows galera LABELS readwritesplit HEAVY GALERA_BACKEND)
# A set of MariaDB server tests executed against Maxscale RWSplit
add_test_script(mariadb_tests_hartmut mariadb_tests_hartmut.sh replication LABELS readwritesplit REPL_BACKEND)
# A set of MariaDB server tests executed against Maxscale RWSplit (Galera backend)
add_test_script(mariadb_tests_hartmut_galera mariadb_tests_hartmut.sh galera LABELS readwritesplit GALERA_BACKEND)
# Creates a number of connections > max_connections setting
add_test_executable(max_connections.cpp max_connections replication LABELS MySQLAuth MySQLProtocol UNSTABLE HEAVY REPL_BACKEND)
# Test of Maxinfo interface (http)
#add_test_executable(maxinfo.cpp maxinfocpp maxinfo LABELS maxinfo UNSTABLE HEAVY REPL_BACKEND)
# Test of Maxinfo interface (http), python impelemntation
add_test_script(maxinfo.py maxinfo.py maxinfo LABELS maxinfo LIGHT REPL_BACKEND)
# Checks tha Maxscale processis running as 'maxscale' user
add_test_executable(maxscale_process_user.cpp maxscale_process_user replication LABELS maxscale LIGHT REPL_BACKEND)
# Test of multi master monitor
add_test_executable(mm.cpp mm mm LABELS mmmon BREAKS_REPL)
# MySQL Monitor with Multi-master configurations
add_test_executable(mm_mysqlmon.cpp mm_mysqlmon mm_mysqlmon LABELS mysqlmon REPL_BACKEND BREAKS_REPL)
# MySQL Monitor crash safety
add_test_executable(mysqlmon_backup.cpp mysqlmon_backup mysqlmon_backup LABELS mysqlmon REPL_BACKEND)
# Regression case for the bug "Two monitors loaded at the same time result into not working installation"
add_test_executable(mxs118.cpp mxs118 mxs118 LABELS maxscale LIGHT REPL_BACKEND)
# Regression case for the bug "disable_sescmd_history causes MaxScale to crash under load"
add_test_executable(mxs127.cpp mxs127 mxs127 LABELS readwritesplit LIGHT REPL_BACKEND)
# Prepearing and execution statements in the loop
add_test_executable(mxs244_prepared_stmt_loop.cpp mxs244_prepared_stmt_loop galera LABELS readwritesplit readconnroute LIGHT GALERA_BACKEND)
# Regression case for the bug "SELECT INTO OUTFILE query succeeds even if backed fails"
add_test_executable(mxs280_select_outfile.cpp mxs280_select_outfile replication LABELS readwritesplit REPL_BACKEND)
# Tries prepared stmt 'SELECT 1,1,1,1...." with different nu,ber of '1'
add_test_executable(mxs314.cpp mxs314 galera LABELS MySQLProtocol LIGHT GALERA_BACKEND)
# Creates and closes a lot of connections, checks that 'maxadmin list servers' shows 0 connections at the end
add_test_executable(mxs321.cpp mxs321 replication LABELS maxscale REPL_BACKEND)
# Crash with Galera and backend restart when persistant cfonnections are in use
add_test_script(mxs361 pers_02 mxs361 mxs361 LABELS maxscale GALERA_BACKEND)
# Load huge file with 'LOAD DATA LOCAL INFILE'
add_test_executable(mxs365.cpp mxs365 replication LABELS readwritesplit REPL_BACKEND)
# Connect to Maxscale with user with only 'SELECT' priveledge
add_test_executable(mxs37_table_privilege.cpp mxs37_table_privilege replication LABELS MySQLAuth LIGHT REPL_BACKEND)
# Connect to Maxscale with user with only 'SELECT' priveledge (Galera backend)
add_test_script(mxs37_table_privilege_galera mxs37_table_privilege galera LABELS MySQLAuth GALERA_BACKEND)
# Connect repeatedly to Schema router and execute simple query, check if auth is ok
add_test_executable(mxs431.cpp mxs431 sharding LABELS schemarouter REPL_BACKEND BREAKS_REPL)
# execute SELECT REPEAT('a',i), where 'i' is changing from 1 to 50000 (bug "Session freeze when small tail packet")
add_test_executable(mxs47.cpp mxs47 replication LABELS MySQLProtocol LIGHT REPL_BACKEND)
# Regression case for the bug "USE <db> hangs when Tee filter uses matching"
add_test_executable(mxs501_tee_usedb.cpp mxs501_tee_usedb mxs501 LABELS tee REPL_BACKEND)
# Open connection, execute 'change user', close connection in the loop
add_test_executable(mxs548_short_session_change_user.cpp mxs548_short_session_change_user mxs548 LABELS MySQLProtocol REPL_BACKEND)
# Playing with blocking and unblocking Master under load
add_test_executable(mxs559_block_master.cpp mxs559_block_master mxs559 LABELS readwritesplit REPL_BACKEND)
# Playing with blocking and unblocking nodes under INSERT load
add_test_executable(mxs564_big_dump.cpp mxs564_big_dump galera_mxs564 LABELS readwritesplit readconnroute GALERA_BACKEND)
# Executes simple queries from python script in the loop
add_test_script(mxs585.py mxs585.py replication LABELS readwritesplit readconnroute UNSTABLE HEAVY REPL_BACKEND)
# Simple transactions in the loop from python script with client SSL on
add_test_script(mxs598.py mxs598.py ssl LABELS MySQLProtocol UNSTABLE HEAVY REPL_BACKEND)
# Regression case for the bug "MaxScale fails to start silently if config file is not readable"
add_test_executable(mxs621_unreadable_cnf.cpp mxs621_unreadable_cnf replication LABELS maxscale REPL_BACKEND)
# playing with 'restart service' and restart Maxscale under load
add_test_executable(mxs657_restart.cpp mxs657_restart replication LABELS maxscale HEAVY REPL_BACKEND)
add_test_executable(mxs657_restart_service.cpp mxs657_restart_service replication LABELS maxscale REPL_BACKEND)
# put cyrillic letters to the table and check from backend
add_test_executable(mxs682_cyrillic.cpp mxs682_cyrillic replication LABELS maxscale LIGHT REPL_BACKEND)
# put cyrillic letters to the table and check from backend (Galera backend)
add_test_script(mxs682_cyrillic_galera mxs682_cyrillic galera LABELS maxscale GALERA_BACKEND)
# Connect using different default database using user with database and table level grants
add_test_executable(mxs716.cpp mxs716 replication LABELS MySQLAuth LIGHT REPL_BACKEND)
# MaxScale configuration check functionality test (maxscale -c)
add_test_executable(mxs722.cpp mxs722 mxs722 LABELS maxscale LIGHT REPL_BACKEND)
# Test of 'maxadmin' user Unix accounts enable/disable
add_test_executable(mxs729_maxadmin.cpp mxs729_maxadmin replication LABELS MaxAdminAuth LIGHT REPL_BACKEND)
# Simple connect test in bash, checks that defined in cmd line DB is selected
add_test_script(mxs791.sh mxs791.sh replication LABELS UNSTABLE HEAVY REPL_BACKEND)
# Simple connect test in bash, checks that defined in cmd line DB is selected (Galera backend)
add_test_script(mxs791_galera.sh mxs791_galera.sh galera LABELS UNSTABLE HEAVY GALERA_BACKEND)
# Checks "Current no. of conns" maxadmin output after long blob inserting
add_test_executable(mxs812_1.cpp mxs812_1 longblob LABELS readwritesplit REPL_BACKEND)
# Checks "Current no. of conns" maxadmin output after long blob inserting
add_test_executable(mxs812_2.cpp mxs812_2 longblob LABELS readwritesplit REPL_BACKEND)
# Execute prepared statements while master is blocked, checks "Current no. of conns" after the test
add_test_executable(mxs822_maxpasswd.cpp mxs822_maxpasswd maxpasswd LABELS maxscale REPL_BACKEND)
# Do only SELECTS during time > wait_timeout and then do INSERT
# This test will fail because the functionality hasn't been implemented
add_test_executable(mxs827_write_timeout.cpp mxs827_write_timeout mxs827_write_timeout LABELS readwritesplit REPL_BACKEND)
# Block and unblock first and second slaves and check that they are recovered
add_test_executable(mxs874_slave_recovery.cpp mxs874_slave_recovery mxs874 LABELS readwritesplit REPL_BACKEND)
# A set of dynamic configuration tests
# Server removal test
add_test_executable(mxs922_bad_server.cpp mxs922_bad_server mxs922 LABELS maxscale REPL_BACKEND)
# Server creation test
add_test_executable(mxs922_server.cpp mxs922_server mxs922_base LABELS maxscale REPL_BACKEND)
# Monitor creation test
add_test_executable(mxs922_monitor.cpp mxs922_monitor mxs922_base LABELS maxscale REPL_BACKEND)
# Double creation of listeners, expect no crash
add_test_executable(mxs922_double_listener.cpp mxs922_double_listener mxs922_base LABELS maxscale REPL_BACKEND)
# Test persisting of configuration changes
add_test_executable(mxs922_restart.cpp mxs922_restart mxs922 LABELS maxscale REPL_BACKEND)
# Server scaling test
add_test_executable(mxs922_scaling.cpp mxs922_scaling mxs922_base LABELS maxscale REPL_BACKEND)
# Dynamic listener SSL test
add_test_executable(mxs922_listener_ssl.cpp mxs922_listener_ssl mxs922_base LABELS maxscale REPL_BACKEND)
# Test of MaxRows filter
add_test_executable(mxs1071_maxrows.cpp mxs1071_maxrows maxrows LABELS maxrowsfilter REPL_BACKEND)
# Test of Masking filter
add_test_script(masking_mysqltest masking_mysqltest_driver.sh masking_mysqltest LABELS maskingfilter REPL_BACKEND)
add_test_script(masking_user masking_user.sh masking_mysqltest LABELS maskingfilter REPL_BACKEND)
# Test of Cache filter
add_test_script(cache_basic cache_basic.sh cache_basic LABELS cachefilter REPL_BACKEND)
# Set utf8mb4 in the backend and restart Maxscale
add_test_executable(mxs951_utfmb4.cpp mxs951_utfmb4 replication LABELS REPL_BACKEND)
# Execute given SQL through readwritesplit (with temporary tables usage)
add_test_executable(mxs957.cpp mxs957 replication LABELS readwritesplit REPL_BACKEND)
# Regression case for the bug "Defunct processes after maxscale have executed script during failover"
add_test_executable(mxs1045.cpp mxs1045 mxs1045 LABELS maxscale REPL_BACKEND)
# MXS-1123: connect_timeout setting causes frequent disconnects
# https://jira.mariadb.org/browse/MXS-1123
add_test_executable(mxs1123.cpp mxs1123 mxs1123 LABELS maxscale REPL_BACKEND)
# 'namedserverfilter' test
add_test_executable(namedserverfilter.cpp namedserverfilter namedserverfilter LABELS namedserverfilter LIGHT REPL_BACKEND)
# Authentication error testing
add_test_executable(no_password.cpp no_password replication LABELS MySQLAuth LIGHT REPL_BACKEND)
# Open and immediatelly close a big number of connections
add_test_executable(open_close_connections.cpp open_close_connections replication LABELS maxscale REPL_BACKEND)
# Open and immediatelly close a big number of connections, ssl is in use
#
# The test is broken due to some problem in the connector. It crashes with a
# double free error somewhere deep inside the connector/SSL libraries.
#
# add_test_script(open_close_connections_ssl open_close_connections ssl LABELS maxscale REPL_BACKEND)
# Persistant connection test
add_test_executable(pers_01.cpp pers_01 pers_01 LABELS maxscale REPL_BACKEND GALERA_BACKEND)
# Test with persistant connections configured and big number iof opened connections ,expect no crash
add_test_executable(pers_02.cpp pers_02 pers_01 LABELS maxscale REPL_BACKEND GALERA_BACKEND)
# Check if prepared statement works via Maxscale (via RWSplit)
add_test_executable(prepared_statement.cpp prepared_statement replication LABELS readwritesplit LIGHT REPL_BACKEND)
# Connect to ReadConn in master mode and check if there is only one backend connection to master
add_test_executable(readconnrouter_master.cpp readconnrouter_master replication LABELS readconnroute LIGHT REPL_BACKEND)
# Creates 100 connections to ReadConn in slave mode and check if connections are distributed among all slaves
add_test_executable(readconnrouter_slave.cpp readconnrouter_slave replication LABELS readconnroute LIGHT REPL_BACKEND)
# Regex filter test
add_test_executable(regexfilter1.cpp regexfilter1 regexfilter1 LABELS regexfilter LIGHT REPL_BACKEND)
# check that Maxscale is reacting correctly on ctrc+c signal and termination does not take ages
add_test_script(run_ctrl_c.sh run_ctrl_c.sh replication LABELS maxscale LIGHT REPL_BACKEND)
# run a set of queries in the loop (see setmix.sql) using Perl client
add_test_script(run_session_hang.sh run_session_hang.sh replication LABELS readwritesplit REPL_BACKEND)
# Checks changes of COM_SELECT and COM_INSERT after queris to check if RWSplit sends queries to master or to slave depending on if it is write or read only query
add_test_executable(rw_select_insert.cpp rw_select_insert replication LABELS readwritesplit REPL_BACKEND)
# Checks connections are distributed equaly among backends
add_test_executable(rwsplit_conn_num.cpp rwsplit_conn_num repl_lgc LABELS readwritesplit LIGHT REPL_BACKEND)
# Check that there is one connection to Master and one connection to one of slaves
add_test_executable(rwsplit_connect.cpp rwsplit_connect replication LABELS readwritesplit LIGHT REPL_BACKEND)
# Test of the read-only mode for readwritesplit when master fails (blocked)
add_test_executable(rwsplit_readonly.cpp rwsplit_readonly rwsplit_readonly LABELS readwritesplit REPL_BACKEND)
# Test of the read-only mode for readwritesplit when master fails (blocked), under load
add_test_executable(rwsplit_readonly_stress.cpp rwsplit_readonly_stress rwsplit_readonly LABELS readwritesplit HEAVY REPL_BACKEND)
# Test readwritesplit multi-statement handling
add_test_executable(rwsplit_multi_stmt.cpp rwsplit_multi_stmt rwsplit_multi_stmt LABELS readwritesplit REPL_BACKEND)
# Test readwritesplit multi-statement handling
add_test_executable(rwsplit_read_only_trx.cpp rwsplit_read_only_trx rwsplit_read_only_trx LABELS readwritesplit REPL_BACKEND)
# Test replication-manager with MaxScale
add_test_executable(replication_manager.cpp replication_manager replication_manager LABELS maxscale REPL_BACKEND)
add_test_executable_notest(replication_manager_2nodes.cpp replication_manager_2nodes replication_manager_2nodes LABELS maxscale REPL_BACKEND)
add_test_executable_notest(replication_manager_3nodes.cpp replication_manager_3nodes replication_manager_3nodes LABELS maxscale REPL_BACKEND)
# Schemarouter duplicate database detection test: create DB on all nodes and then try query againt schema router
add_test_executable(schemarouter_duplicate_db.cpp schemarouter_duplicate_db schemarouter_duplicate_db LABELS schemarouter REPL_BACKEND)
# Test of external script execution
add_test_executable(script.cpp script script LABELS maxscale REPL_BACKEND)
# Check if 'weightby' parameter works
add_test_executable(server_weight.cpp server_weight galera.weight LABELS readwritesplit readconnroute LIGHT GALERA_BACKEND)
# Executes a lot of session commands with "disable_sescmd_history=true" and check that memory consumption is not increasing
add_test_executable(ses_bigmem.cpp ses_bigmem no_ses_cmd_store LABELS readwritesplit REPL_BACKEND)
# test for 'max_sescmd_history' and 'connection_timeout' parameters
add_test_executable(session_limits.cpp session_limits session_limits LABELS readwritesplit REPL_BACKEND)
# Test of schema router
add_test_executable(sharding.cpp sharding sharding LABELS schemarouter BREAKS_REPL)
# MXS-1160: LOAD DATA LOCAL INFILE with schemarouter
add_test_executable(sharding_load_data.cpp sharding_load_data sharding LABELS schemarouter BREAKS_REPL)
# Do short sessions (open conn, short query, close conn) in the loop
add_test_executable(short_sessions.cpp short_sessions replication LABELS readwritesplit readconnroute REPL_BACKEND)
# Do short sessions (open conn, short query, close conn) in the loop, client ssl is ON
add_test_script(short_sessions_ssl short_sessions ssl LABELS readwritesplit readconnroute REPL_BACKEND)
# Regression case for crash if maxadmin 'show monitors' command is issued, but no monitor is not running
add_test_executable(show_monitor_crash.cpp show_monitor_crash show_monitor_crash LABELS maxscale)
# Check how Maxscale works in case of one slave failure, only one slave is configured
add_test_executable(slave_failover.cpp slave_failover replication.one_slave LABELS readwritesplit REPL_BACKEND)
# Execute queries of different size, check data is the same when accessing via Maxscale and directly to backend
add_test_executable(sql_queries.cpp sql_queries replication LABELS readwritesplit REPL_BACKEND)
# Execute queries of different size, check data is the same when accessing via Maxscale and directly to backend, one persistant connection configured
add_test_script(sql_queries_pers1 sql_queries sql_queries_pers1 LABELS maxscale readwritesplit HEAVY REPL_BACKEND)
# Execute queries of different size, check data is the same when accessing via Maxscale and directly to backend, 10 persistant connections configured
add_test_script(sql_queries_pers10 sql_queries sql_queries_pers10 LABELS maxscale readwritesplit HEAVY REPL_BACKEND)
# Execute queries of different size, check data is the same when accessing via Maxscale and directly to backend, client ssl is ON
add_test_script(ssl sql_queries ssl LABELS maxscale readwritesplit REPL_BACKEND)
# Check load balancing, client ssl is ON
add_test_script(ssl_load load_balancing ssl_load LABELS maxscale readwritesplit REPL_BACKEND)
# Check load balancing, client ssl is ON, Galera backend
add_test_script(ssl_load_galera load_balancing_galera ssl_load_galera LABELS maxscale readwritesplit GALERA_BACKEND)
# Testing slaves who have lost their master and how MaxScale works with them
add_test_executable(stale_slaves.cpp stale_slaves replication LABELS mysqlmon REPL_BACKEND)
# Run sysbech test and block one slave during test execution
add_test_executable(sysbench_kill_slave.cpp sysbench_kill_slave replication LABELS UNSTABLE HEAVY REPL_BACKEND)
# Check temporal tables commands functionality
add_test_executable(temporal_tables.cpp temporal_tables replication LABELS readwritesplit REPL_BACKEND)
# Test routing hints
add_test_executable(test_hints.cpp test_hints hints2 LABELS hintfilter LIGHT REPL_BACKEND)
# Binlogrouter tests, these heavily alter the replication so they are run last
add_test_executable(avro.cpp avro avro LABELS avrorouter binlogrouter LIGHT BREAKS_REPL)
# Test avrorouter file compression
add_test_script(avro_compression avro avro_compression LABELS avrorouter binlogrouter LIGHT BREAKS_REPL)
# In the binlog router setup stop Master and promote one of the Slaves to be new Master
add_test_executable(binlog_change_master.cpp binlog_change_master setup_binlog_tx_safe LABELS binlogrouter BREAKS_REPL)
# trying to start binlog setup with incomplete Maxscale.cnf
add_test_executable(binlog_incompl.cpp binlog_incompl binlog_incompl LABELS binlogrouter BREAKS_REPL)
# configure binlog router setup, execute queries and transactions, check data; install semysync plugin, router options semisync=1,transaction_safety=1
add_test_executable(binlog_semisync.cpp binlog_semisync setup_binlog_semisync LABELS binlogrouter HEAVY BREAKS_REPL)
# configure binlog router setup, execute queries and transactions, check data; install semysync plugin, router options semisync=0,transaction_safety=0
add_test_script(binlog_semisync_txs0_ss0 binlog_semisync setup_binlog_semisync_txs0_ss0 LABELS binlogrouter HEAVY BREAKS_REPL)
# configure binlog router setup, execute queries and transactions, check data; install semysync plugin, router options semisync=0,transaction_safety=1
add_test_script(binlog_semisync_txs0_ss1 binlog_semisync setup_binlog_semisync_txs0_ss1 LABELS binlogrouter HEAVY BREAKS_REPL)
# configure binlog router setup, execute queries and transactions, check data; install semysync plugin, router options semisync=1,transaction_safety=0
add_test_script(binlog_semisync_txs1_ss0 binlog_semisync setup_binlog_semisync_txs1_ss0 LABELS binlogrouter HEAVY BREAKS_REPL)
set_tests_properties(binlog_semisync PROPERTIES TIMEOUT 3600)
set_tests_properties(binlog_semisync_txs0_ss0 PROPERTIES TIMEOUT 3600)
set_tests_properties(binlog_semisync_txs0_ss1 PROPERTIES TIMEOUT 3600)
set_tests_properties(binlog_semisync_txs1_ss0 PROPERTIES TIMEOUT 3600)
#
# The encryption tests don't work as they require the file key management plugin
#
# Binlog encription test (aes_cbr encryption)
#add_test_executable(mxs1073_binlog_enc.cpp mxs1073_binlog_enc binlog_enc_aes_cbc LABELS binlogrouter 10.1 BREAKS_REPL)
# Binlog encription test (aes_ctr encryption)
#add_test_script(mxs1073_binlog_enc_aes_ctr mxs1073_binlog_enc binlog_enc_aes_ctr LABELS binlogrouter 10.1 BREAKS_REPL)
# Test of CDC protocol (avro listener)
add_test_executable(cdc_client.cpp cdc_client avro LABELS avrorouter binlogrouter BREAKS_REPL)
# Tries INSERTs with size close to 0x0ffffff * N (with binlog backend)
add_test_executable(different_size_binlog.cpp different_size_binlog setup_binlog LABELS binlogrouter HEAVY BREAKS_REPL)
# Try to configure binlog router to use wrong password for Master and check 'slave status' on binlog
add_test_executable(mxs781_binlog_wrong_passwrd.cpp mxs781_binlog_wrong_passwrd setup_binlog LABELS binlogrouter BREAKS_REPL)
# Regression case for crash if long host name is used for binlog router (in 'change master to ...')
add_test_executable(mxs813_long_hostname.cpp mxs813_long_hostname setup_binlog LABELS binlogrouter BREAKS_REPL)
# configure binlog rouer setup, execute queries and transactions, check data;
add_test_executable(setup_binlog.cpp setup_binlog setup_binlog LABELS binlogrouter BREAKS_REPL)
# configure binlog rouer setup, execute queries and transactions, check data; install semysync plugin, backends started with --binlog-checksum=CRC32 option
# disabled because it is included into setup_binlog test, separate test was created for debugging
# add_test_executable(setup_binlog_crc_32.cpp setup_binlog_crc_32 setup_binlog LABELS binlogrouter BREAKS_REPL)
# configure binlog rouer setup, execute queries and transactions, check data; install semysync plugin, backends started with --binlog-checksum=NONE option
# disabled because it is included into setup_binlog test, separate test was created for debugging
# add_test_executable(setup_binlog_crc_none.cpp setup_binlog_crc_none setup_binlog LABELS binlogrouter LIGHT BREAKS_REPL)
# Creates KDC and tries authrization via GSSAPI (both client and backend)
# works only with yum-based distributions
# TODO: make it working with zypper and apt, move part of KDC setup to MDBCI
add_test_executable(kerberos_setup.cpp kerberos_setup kerberos LABELS HEAVY gssapi REPL_BACKEND)
# enable after fixing MXS-419
# add_test_executable(mxs419_lots_of_connections.cpp mxs419_lots_of_connections replication LABELS REPL_BACKEND)
# TODO: Alter the user_cache test
# add_test_executable(user_cache.cpp user_cache user_cache LABELS REPL_BACKEND)
# https://mariadb.atlassian.net/browse/MXS-576 - it is possible to set negative value for
# 'persistpoolmax' without any warning
#add_test_executable(bad_pers.cpp bad_pers bad_pers LABELS REPL_BACKEND)
# Test Aurora RDS monitor
add_test_executable(auroramon.cpp auroramon auroramon LABELS HEAVY EXTERNAL_BACKEND)
# Disabled for the time being
# add_test_executable(gatekeeper.cpp gatekeeper gatekeeper LABELS gatekeeper)
# not implemented, just template
#add_test_executable(rw_galera_select_insert.cpp rw_galera_select_insert galera LABELS readwritesplit GALERA_BACKEND)
# a tool to delete RDS Aurora cluster
add_test_executable_notest(delete_rds.cpp delete_rds replication LABELS EXTERN_BACKEND)
# a tool to create RDS Aurora cluster
add_test_executable_notest(create_rds.cpp create_rds replication LABELS EXTERN_BACKEND)
# start sysbench ageints RWSplit for infinite execution
add_test_executable_notest(long_sysbench.cpp long_sysbench replication LABELS readwritesplit REPL_BACKEND)
configure_file(templates.h.in templates.h @ONLY)
include(CTest)

View File

@ -0,0 +1,15 @@
## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
##
## # The following are required to submit to the CDash dashboard:
## ENABLE_TESTING()
## INCLUDE(CTest)
set(CTEST_PROJECT_NAME "MaxScale")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "jenkins.engskysql.com")
set(CTEST_DROP_LOCATION "/CDash/submit.php?project=MaxScale")
set(CTEST_DROP_SITE_CDASH TRUE)

View File

@ -0,0 +1,289 @@
# Build and test environment setup
### Full build and test environment setup
<pre>
# install ruby
sudo apt-get install ruby
# install all needed libraries
sudo apt-get install libxslt-dev libxml2-dev libvirt-dev zlib1g-dev
# install vagrant
# it is also possible to install Vagrant from distribution repository, but in case of problems please use 1.7.2
wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.7.2_x86_64.deb
sudo dpkg -i vagrant_1.7.2_x86_64.deb
# install Vagrant plugins
vagrant plugin install vagrant-aws vagrant-libvirt vagrant-mutate
# get MDBCI, build scripts, descriptions of MDBCI boxes and keys from GitHub
git clone https://github.com/OSLL/mdbci.git
git clone git@github.com:mariadb-corporation/mdbci-repository-config.git
git clone git@github.com:mariadb-corporation/build-scripts-vagrant.git
git clone git@github.com:mariadb-corporation/mdbci-boxes
# Copy scripts and boxes to proper places
mv build-scripts-vagrant build-scripts
scp -r mdbci-boxes/* mdbci/
# set proper access rights for ssh keys (for ppc64 machines)
chmod 400 mdbci/KEYS/*
# install all the stuff for test package build
sudo apt-get install cmake gcc g++ libssl-dev
sudo apt-get install mariadb-client shellcheck
# install MariaDB development library
sudo apt-get install libmariadbclient-dev
# Ubuntu repos can contain the sa,e package with different name 'libmariadb-client-lgpl-dev'
# but it can not be used to build maxscale-system-test; please use mariadb.org repositories
# https://downloads.mariadb.org/mariadb/repositories/
# Do not forget to remove all other MariaDB and MySQL packages!
# install qemu (more info https://en.wikibooks.org/wiki/QEMU/Installing_QEMU)
sudo apt-get install qemu qemu-kvm libvirt-bin
# install virt-manager (if you prefer UI)
sudo apt-get install virt-manager
# install docker (if needed) - see https://docs.docker.com/engine/installation/
# if cmake from distribution repository is too old it is recommended to build it from latest sources
wget https://cmake.org/files/v3.4/cmake-3.4.1.tar.gz # replace 3.4.1 to latest version
tar xzvf cmake-3.4.1.tar.gz
cd cmake-3.4.1
./bootstrap
make
sudo make install
cd
# sysbench 0.5 should be in sysbench_deb7 directory; it can be built from source:
git clone https://github.com/akopytov/sysbench.git
cd sysbench
./autogen.sh
./configure
make
cd ..
mv sysbench sysbench_deb7
# for OVH servers it is needed to move 'docker' and 'libvirt' working directories to /home
# (replace 'vagrant' to your home directory name)
cd /var/lib/
sudo mv docker /home/vagrant/
sudo ln -s /home/vagrant/docker docker
cd libvirt
sudo mv images /home/vagrant/
sudo ln -s /home/vagrant/images images
cd
# (HACK) in case of problem with building sysbench:
scp -r vagrant@maxscale-jenkins.mariadb.com:/home/vagrant/sysbench_deb7 .
# (HACK) in case of problem with 'dummy' box (problem is caused by MDBCI bug):
scp -r vagrant@maxscale-jenkins.mariadb.com:/home/vagrant/.vagrant.d/boxes/dummy .vagrant.d/boxes/
# MariaDBManager-GPG* files are needed for Maxscale builds in the home directory
# put AWS keys to aws-config.yml (see https://github.com/OSLL/mdbci/blob/master/aws-config.yml.template)
# add curent user to the group 'libvirtd'
sudo usermod -a -G user_name libvirtd
# start libvirt default pool
virsh pool-start default
</pre>
### Setup VMs manually
#### Empty virtual machine
Following template can be used to create empty VM (for qemu machines):
<pre>
{
"cookbook_path" : "../recipes/cookbooks/",
"build" :
{
"hostname" : "default",
"box" : "###box###",
"product" : {
"name" : "packages"
}
}
}
</pre>
for AWS machines:
<pre>
{
"cookbook_path" : "../recipes/cookbooks/",
"aws_config" : "../aws-config.yml",
"build" :
{
"hostname" : "build",
"box" : "###box###"
}
}
</pre>
Following boxes are availabe:
* qemu: debian_7.5_libvirt, ubuntu_trusty_libvirt, centos_7.0_libvirt, centos_6.5_libvirt
* AWS: rhel5, rhel6, rhel7, sles11, sles12, fedora20, fedora21, fediora22, ubuntu_wily, ubuntu_vivid, centos7, deb_jessie
#### Maxscale and backend machines creation
* Generation of Maxscale repository description
It is necessary to generate descriptions of MariaDB and Maxscale repositories before bringin up Maxscale machine with Vagrant
<pre>
export ci_url="http://my_repository_site.com/repostory/"
~/mdbci-repository-config/generate_all.sh $repo_dir
~/mdbci-repository-config/maxscale-ci.sh $target $repo_dir
</pre>
where
<pre>
$repo_dir - directory where repository descriptions will be created
$target - directory with MaxScale packages in the repositoy
</pre>
example:
<pre>
export ci_url="http://max-tst-01.mariadb.com/ci-repository/"
~/mdbci-repository-config/generate_all.sh repo.d
~/mdbci-repository-config/maxscale-ci.sh develop repo.d
</pre>
More information can be found in the [MDBCI documentation](https://github.com/OSLL/mdbci#repod-files) and in the [mdbci-repository-config documentaion](https://github.com/mariadb-corporation/mdbci-repository-config#mdbci-repository-config)
* Preparing configuration description
Virtual machines should be described in JSON format. Example template can be found in the [build-scripts package](https://github.com/mariadb-corporation/build-scripts-vagrant/blob/master/test/template.libvirt.json).
MariaDB machine description example:
<pre>
"node0" :
{
"hostname" : "node0",
"box" : "centos_7.0_libvirt",
"product" : {
"name": "mariadb",
"version": "10.0",
"cnf_template" : "server1.cnf",
"cnf_template_path": "~/build-scripts/test-setup-scripts/cnf"
}
}
</pre>
"cnf_template" defines .cnf file which will be places into MariaDB machine. [build-scripts package](https://github.com/mariadb-corporation/build-scripts-vagrant/tree/master/test-setup-scripts/cnf) contains examples of .cnf files.
MariaDB Galera machine description example:
<pre>
"galera0" :
{
"hostname" : "galera0",
"box" : "centos_7.0_libvirt",
"product" : {
"name": "galera",
"version": "10.0",
"cnf_template" : "galera_server1.cnf",
"cnf_template_path": "~/build-scripts/test-setup-scripts/cnf"
}
}
</pre>
For Galera machines MDBCI automatically puts following information into .cnf file:
|field|description|
|------|----|
|###NODE-ADDRESS###|IP address of the node (for AWS - private IP)|
|###NODE-NAME###|Replaces by node name ("node0" in this example)|
|###GALERA-LIB-PATH###|Path to the Galera library file (.so file)|
Example of Maxscale machine description:
<pre>
"maxscale" :
{
"hostname" : "maxscale",
"box" : "centos_7.0_libvirt",
"product" : {
"name": "maxscale"
}
}
</pre>
#### Generation configuration and bringing machines up
After creation machines description JSON two steps are needed.
1. Generate configuration
<pre>
./mdbci --override --template $template_name.json --repo-dir $repo_dir generate $name
</pre>
where
|variable|description|
|----|----|
|$template_name|name of machines descripiton JSON file|
|$repo_dir|directory with repositories description generated by mdbci-repository-config (repo.d)|
|$name|name of test configuration; will be used as directory name for Vagrant files|
2. Bringing machines up
<pre>
./mdbci up $name
</pre>
#### Configuring DB users
Automatic DB users is not implemented yet, so it have to be done manually. See [setup_repl.sh](https://github.com/mariadb-corporation/build-scripts-vagrant/blob/master/test-setup-scripts/setup_repl.sh) and [setup_galera.sh](https://github.com/mariadb-corporation/build-scripts-vagrant/blob/master/test-setup-scripts/galera/setup_galera.sh) for details.
Any test from 'maxscale-system-test' checks Master/Slave and Galera configurations and restores them if they are broken, but it works only if DB users are created.
TODO: add it into 'maxscale-system-test'
### Access VMs
MDBCI provides a number of commands to get information about running vrtial machines. See [MDBCI documentation](https://github.com/OSLL/mdbci#mdbci-syntax) for details.
[set_env_vagrant.sh script](https://github.com/mariadb-corporation/build-scripts-vagrant/blob/master/test/set_env_vagrant.sh) defines environmental variables needed by 'maxscale-system-test'. The same variables can be used to access VMs manually.
Script have to be executed fro 'mbdci' directory. Do not forget '.':
<pre>
cd ~/mdbci/
. ../build-scripts/test/set_env_vagrant.sh $name
</pre>
After it virual machines can be accessed via ssh, for example:
<pre>
ssh -i $maxscale_sshkey $maxscale_access_user@$maxscale_IP
</pre>
Another way is to use 'vagrant ssh':
<pre>
cd ~/mdbci/$name/
vagrant ssh &lt;node_name&gt;
</pre>
MDBCI can give IP address, path to ssh key:
<pre>
./mdbci show network &lt;configuration_name&gt;/&lt;node_name&gt; --silent
./mdbci show keyfile &lt;configuration_name&gt;/&lt;node_name&gt; --silent
./mdbci ssh --command 'whoami' &lt;configuration_name&gt;/&lt;node_name&gt; --silent
</pre>
Node name for build machine is 'build'
Nodes names for typical test setup are node0, ..., node3, galera0, ..., galera3, maxscale
Example:
<pre>
./mdbci show network centos6_vm01/build --silent
./mdbci show keyfile centos6_vm01/build --silent
./mdbci ssh --command 'whoami' centos6_vm01/build --silent
</pre>
### Destroying configuration
<pre>
cd ~/mdbci/$name
vagrant destroy -f
</pre>

View File

@ -0,0 +1,204 @@
# Creating a test case
This document describes basic principles of test case creation and provides list of basic usefull functions and properties.
For detailed function and properties description and thier full list please see documetation generated by Doxygen.
## Test case basics
For every test case following should be created:
- test executable
- record in the 'templates' file
- Maxscale configuration template (if test requires special Maxscale configuration)
- [CMakeLists.txt](CMakeLists.txt) record:
- add_test_executable(<source.cpp> <binary_name> <cnf_template_name>)
- 'set_tests_properties' if test should be added to the group or bigger timeout should be defined (> default 1800s)
## 'templates' file
'templates' file contains information about Maxscale configuration template for every test in plain text format:
\<test_executable_name\> \<suffix_of_cnf_template\>
Template itself should be:
cnf/maxscale.cnf.template.\<suffix_of_cnf_template\>
## Maxscale configuration template
All templates are in cnf/ directory:
cnf/maxscale.cnf.template.\<suffix_of_cnf_template\>
Template can contain following varables:
|Variable|Maeaning|
|--------|--------|
|###threads###| Number of Maxscale treads|
|###node_server_IP_N###|IP of Master/Slave node N|
|###node_server_port_N###|port of Master/Slave node N|
|###galera_server_IP_N###|IP of Galera node N|
|###galera_server_port_N###|port of Galera node N|
## Test creation principles
* start from initializing of an object of TestConnections class
* set timeout before every operation which can got stuck, do not forget to disable timeout before long sleep()
* use TestConnections::tprintf function to print test log
* use TestConnections::add_result() to idicate test failure and print explanation message
* execute TestConnections::copy_all_logs at the end of test
* return TestConnections::global_result value
* do not leave any node blocked by firewall
## Class TestConnections
This class contains all information about Maxscale node and about all backend nodes as well as a set of functions
to handle Maxscale and backends, interact with Maxscale routers and Maxadmin.
Here is only list of main functions, for all details see Doxygen comments in [testconnections.h](testconnections.h)
Currently two backend sets are supported (represented by Mariadb_nodes class objects): 'repl' and 'galera'
- contains all info and operations for Master/Slave and Galera setups
(see Doxygen comments in [mariadb_nodes.h](mariadb_nodes.h) )
It is assumed that following routers+listers are configured
|Router|Port|
|------|----|
|RWSplit|4006|
|ReadConn master|4008|
|ReadConn Slave|4009|
|binlog|5306|
|test case -specific|4016|
### Most important fuctions and variables
Please check Doxygen comments for details
#### TestConnections(int argc, char *argv[]);
* reads all information from environmental variables
* checks backends, if broken - does one attempt to restore
* create maxscale.cnf out of template and copy it to Maxscale node
* create needed directories, set access righs for them, cleanup logs, coredumps
* start Maxscale
* initialize internal structures
#### Timeout functions
int set_timeout(int timeout_seconds)
stop_timeout()
If after set_timeout() a new call of set_timeout() or stop_timeout() is not done the test execution terminated,
logs from Maxscale are copied to host.
#### Open connection functions
|Function|Short description|
|----|---|
| int connect_maxscale();<br> int connect_rwsplit();<br> int connect_readconn_master();<br> int connect_maxscale_slave();|store MYSQL handler in TestConnections object (only one cnnection can be created by them, second call leads to MYSQL handler leak)|
|MYSQL * open_rwsplit_connection() <br> MYSQL * open_readconn_master_connection() <br> MYSQL * open_readconn_slave_connection() |returns MYSQL handler (can be used to create a number of connections to each router)|
| int create_connections(int conn_N) |- open and then close N connections to each router|
A number of useful wrappers for mysql_real_connect() are not included into TestConnections class, but
they are availve from [mariadb_func.h](mariadb_func.h)
#### Backend check and setup functions
|Function|Short description|
|----|---|
|start_replication()|Configure nodes from 'repl' object as Master/Slave|
|start_galera()|Configure nodes from 'galera'|
|start_binlog()|Configure nodes from 'repl' in following way: node0 - Master, node1 - slave of node0, all others - slaves of Maxscale binlog router|
|start_mm()|Configure nodes from 'repl' in multimuster setup|
#### Result reporting functions
|Function|Short description|
|----|---|
|add_result()|failure printing, increase global_result|
|tprint()| printing with timestamp|
|copy_logs()|copy Maxscale log, maxscale.cnf file and core dump from Maxscale machine to current directory|
#### Different checks functions
|Function|Short description|
|----|---|
|try_query()|try SQL query and print error message in case of failure, increase global_result|
|check_t1_table()|check if t1 present in give DB|
|test_maxscale_connections|check status of connections to RWSplit, ReadConn master, ReadConn slave routers|
|check_maxscale_alive()|Check if RWSplit, ReadConn master, ReadConn slave routers are alive|
|check_log_err()|Check Maxscale log for presence of absence of specific string|
|find_connected_slave|find first slave that have connections from Maxscale|
#### Maxscale machine control functions
|Function|Short description|
|----|---|
|start_maxscale()||
|stop_maxscale()||
|restart_maxscale()||
|execute_ssh_maxscale()|execute command on Maxscale node via ssh|
#### Properties
|Name|Short description|Corresponding env variable|
|----|-----|----|
|global_result|0 if there is not single failure during the test| - |
|repl|Mariadb_nodes object for Master/Slave nodes| - |
|galera|Mariadb_nodes object for Galera nodes| - |
|smoke|do short tests if TRUE|smoke|
|maxscale_IP|IP address of Maxscale machine|maxscale_IP|
|maxscale_user|DB user name to access via Maxscale|maxscale_user|
|maxscale_password|password for MaxscaleDB user|maxscale_password|
|maxadmin_password|password for MaxAdmin interface (user name is hard coded 'admin')|maxadmin_password|
|conn_rwsplit|MYSQL handler of connections to RWSplit router| - |
|conn_master|MYSQL handler of connections to ReadConn router in master mode| - |
|conn_slave|MYSQL handler of connections to ReadConn router in master mode| - |
### Mariadb_nodes class
#### Master/Slave and Galera setup and check
|Function|Short description|
|----|---|
|start_replication()|Configure nodes from 'repl' object as Master/Slave|
|start_galera()|Configure nodes from 'galera'|
|set_slave()|execute CHANGE MASTER TO agains the node|
|check_replication()|Check if 'repl' nodes are properly configured as Master/Slave|
|check_galera()|Check if 'galera' nodes are are properly configured as Galera cluster|
|change_master|Make another node to be a master|
#### Connections functions
|Function|Short description|
|----|---|
|connect()|open connections to all nodes, store MYSQL handlers in internal variable, second call leads to handlers leak|
|close_connections()|close connections to all nodes|
#### Nodes control functions
|Function|Short description|
|----|---|
|block_node()|block MariaDB server on the node by firawall|
|unblock_node()|unblock MariaDB server on the node by firawall|
|unblock_all_nodes()|unblock MariaDB server on all nodes by firawall|
|stop_node()|stop MariaDB server on the node|
|start node()|start MariaDB server on the node|
|restart_node()|stop and restart MariaDB server on the node|
|check_node()|check if MariaDB server on the node is alive|
|check_and_restart_node()|check if MariaDB server on the node is alive and restart it if it is not alive|
|stop_nodes()|stop MariaDB server on all nodes|
|ssh_node()|Execute command on the node via ssh, return error code|
|ssh_node_output()|Same as ssh_nodE(), but return command output|
|flush_hosts()|Execute 'mysqladmin flush-hosts' on all nodes|
|execute_query_all_nodes()|Execute same query on all nodes|
#### Properties
|Name|Short description|Corresponding env variable|
|----|-----|----|
|N|Number of nodes|node_N <br> galera_N|
|user_name|DB user name|node_user <br> galera_user|
|password|password for DB user|node_password <br> galera_password|
|IP[ ]|IP address of the node|node_XXX <br> galera_XXX|
|IP_private[ ]|private IP of the node (for AWS nodes)|node_private_XXX <br> galera_private_XXX|
|port[ ]|MariaDB port for the node|node_port_XXX <br> galera_port_XXX|
|nodes[ ]|MYSQL handler| - |
### Maxadmin operations functions
[maxadmin_operations.h](maxadmin_operations.h) contains fuctions to communicate to Maxscale via MaxAdmin interface
|Function|Short description|
|----|---|
|execute_maxadmin_command()|send MaxAdmin command to Maxscale|
|execute_maxadmin_command_print()|send MaxAdmin command to Maxscale and print reply|
|get_maxadmin_param()|send MaxAdmin command to Maxscale and try to find the value of given parameter in output|

View File

@ -0,0 +1,6 @@
BEGIN;
SELECT (@@server_id) INTO @a;
SELECT @a;
@a
####server_id####
COMMIT;

View File

@ -0,0 +1,8 @@
USE test;
drop table if exists t1;
create table t1 (id integer);
set autocommit=0;
begin;
insert into t1 values(1);
commit;
drop table t1;

View File

@ -0,0 +1,4 @@
USE test;
SELECT IF(@@server_id <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)

View File

@ -0,0 +1,9 @@
USE test;
drop table if exists t1;
create table t1 (id integer);
set autocommit=0;
insert into t1 values(1);
select count(*) from t1;
count(*)
1
drop table t1;

View File

@ -0,0 +1,9 @@
USE test;
drop table if exists t1;
create table t1 (id integer);
set autocommit=OFF;
insert into t1 values(1);
select count(*) from t1;
count(*)
1
drop table t1;

View File

@ -0,0 +1,11 @@
USE test;
drop table if exists t1;
create table t1 (id integer);
set autocommit=0;
begin;
insert into t1 values(1);
commit;
select count(*) from t1;
count(*)
1
drop table t1;

View File

@ -0,0 +1,11 @@
USE test;
drop table if exists t1;
create table t1 (id integer);
set autocommit=0;
begin;
insert into t1 values(1);
commit;
select count(*) from t1;
count(*)
1
drop table t1;

View File

@ -0,0 +1,11 @@
USE test;
DROP DATABASE If EXISTS FOO;
SET autocommit=1;
BEGIN;
CREATE DATABASE FOO;
SELECT (@@server_id) INTO @a;
SELECT IF(@a <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)
DROP DATABASE FOO;
COMMIT;

View File

@ -0,0 +1,17 @@
USE test;
DROP TABLE IF EXISTS T1;
DROP EVENT IF EXISTS myevent;
SET autocommit=1;
BEGIN;
CREATE TABLE T1 (id integer);
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
UPDATE t1 SET id = id + 1;
SELECT (@@server_id) INTO @a;
SELECT IF(@a <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)
DROP TABLE T1;
DROP EVENT myevent;
COMMIT;

View File

@ -0,0 +1,11 @@
USE test;
DROP TABLE IF EXISTS T1;
SET autocommit=1;
BEGIN;
CREATE TABLE T1 (id integer);
SELECT (@@server_id) INTO @a;
SELECT IF(@a <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)
DROP TABLE T1;
COMMIT;

View File

@ -0,0 +1,14 @@
USE test;
DROP PROCEDURE IF EXISTS simpleproc;
SET autocommit=1;
BEGIN;
CREATE PROCEDURE simpleproc (OUT param1 INT)
BEGIN
SELECT COUNT(*) INTO param1 FROM t;
END //
SELECT (@@server_id) INTO @a;
SELECT IF(@a <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)
DROP PROCEDURE simpleproc;
COMMIT;

View File

@ -0,0 +1,13 @@
USE test;
DROP FUNCTION IF EXISTS hello;
SET autocommit=1;
BEGIN;
CREATE FUNCTION hello (s CHAR(20))
RETURNS CHAR(50) DETERMINISTIC
RETURN CONCAT('Hello, ',s,'!');
SELECT (@@server_id) INTO @a;
SELECT IF(@a <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)
DROP FUNCTION hello;
COMMIT;

View File

@ -0,0 +1,12 @@
USE test;
DROP TABLE IF EXISTS T1;
CREATE TABLE T1 (id integer);
SET autocommit=1;
BEGIN;
CREATE INDEX foo_t1 on T1 (id);
SELECT (@@server_id) INTO @a;
SELECT IF(@a <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;
result
OK (slave)
DROP TABLE T1;
COMMIT;

View File

@ -0,0 +1,6 @@
use test;
set autocommit=1;
use mysql;
select count(*) from user where user='skysql';
count(*)
2

View File

@ -0,0 +1,15 @@
USE test;
DROP TABLE IF EXISTS myCity;
SET autocommit = 0;
START TRANSACTION;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
START TRANSACTION;
DELETE FROM myCity;
SELECT COUNT(*) FROM myCity;
COUNT(*)
0
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,15 @@
USE test;
DROP TABLE IF EXISTS myCity;
SET autocommit = Off;
START TRANSACTION;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
START TRANSACTION;
DELETE FROM myCity;
SELECT COUNT(*) FROM myCity;
COUNT(*)
0
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,13 @@
USE test;
DROP TABLE IF EXISTS myCity;
SET autocommit = 0;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
DELETE FROM myCity;
SELECT COUNT(*) FROM myCity;
COUNT(*)
0
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,13 @@
USE test;
DROP TABLE IF EXISTS myCity;
SET autocommit = oFf;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
DELETE FROM myCity;
SELECT COUNT(*) FROM myCity;
COUNT(*)
0
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,5 @@
--disable_query_log
--disable_result_log
SELECT SLEEP(5);
--enable_result_log
--enable_query_log

View File

@ -0,0 +1,11 @@
--source testconf.inc
USE test;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (id integer);
set autocommit=0; # open transaction
begin;
insert into t1 values(1); # write to master
commit;
drop table t1;

View File

@ -0,0 +1,3 @@
--source testconf.inc
USE test;
SELECT IF(@@server_id <> @TMASTER_ID,'OK (slave)','FAIL (master)') AS result;

View File

@ -0,0 +1,11 @@
--source testconf.inc
USE test;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (id integer);
set autocommit=0; # open transaction
insert into t1 values(1); # write to master
select count(*) from t1; # read from master
drop table t1;

View File

@ -0,0 +1,11 @@
--source testconf.inc
USE test;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (id integer);
set autocommit=OFF; # open transaction
insert into t1 values(1); # write to master
select count(*) from t1; # read from master
drop table t1;

View File

@ -0,0 +1,13 @@
--source testconf.inc
USE test;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (id integer);
set autocommit=0; # open transaction
begin;
insert into t1 values(1); # write to master
commit;
select count(*) from t1; # read from master since autocommit is disabled
drop table t1;

View File

@ -0,0 +1,13 @@
--source testconf.inc
USE test;
--disable_warnings
drop table if exists t1;
--enable_warnings
create table t1 (id integer);
set autocommit=0; # open transaction
begin;
insert into t1 values(1); # write to master
commit;
select count(*) from t1; # read from master since autocommit is disabled
drop table t1;

View File

@ -0,0 +1,4 @@
use test;
set autocommit=1;
use mysql;
select count(*) from user where user='skysql';

View File

@ -0,0 +1,16 @@
--source testconf.inc
USE test;
--disable_warnings
DROP TABLE IF EXISTS myCity;
--enable_warnings
SET autocommit = 0;
START TRANSACTION;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
START TRANSACTION;
DELETE FROM myCity;
SELECT COUNT(*) FROM myCity; # read transaction's modifications from master
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,16 @@
--source testconf.inc
USE test;
--disable_warnings
DROP TABLE IF EXISTS myCity;
--enable_warnings
SET autocommit = Off;
START TRANSACTION;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
START TRANSACTION;
DELETE FROM myCity;
SELECT COUNT(*) FROM myCity; # read transaction's modifications from master
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,16 @@
--source testconf.inc
USE test;
--disable_warnings
DROP TABLE IF EXISTS myCity;
--enable_warnings
SET autocommit = 0;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
DELETE FROM myCity; # implicit transaction started
SELECT COUNT(*) FROM myCity; # read transaction's modifications from master
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,16 @@
--source testconf.inc
USE test;
--disable_warnings
DROP TABLE IF EXISTS myCity;
--enable_warnings
SET autocommit = oFf;
CREATE TABLE myCity (a int, b char(20));
INSERT INTO myCity VALUES (1, 'Milan');
INSERT INTO myCity VALUES (2, 'London');
COMMIT;
DELETE FROM myCity; # implicit transaction started
SELECT COUNT(*) FROM myCity; # read transaction's modifications from master
COMMIT;
DROP TABLE myCity;

View File

@ -0,0 +1,127 @@
# Jenkins
## List of Jenkins installations
| URL | Description |
|----|----|
|[max-tst-01.mariadb.com:8089](http://max-tst-01.mariadb.com:8089)|AWS, qemu; Regular testing for different MariaDB versions, different Linux distributions, Developers testing|
|[maxscale-jenkins.mariadb.com:8089/](http://maxscale-jenkins.mariadb.com:8089/)|AWS, VBox; Regular builds for all distributions, build for Coverity, regular test VBox+CentOS6+MariaDB5.5|
|[maxscale-jenkins.mariadb.com:8090](http://maxscale-jenkins.mariadb.com:8090/)|MDBCI testing and debugging, Jenkins experiments|
## Basic Jenkins jobs
### [max-tst-01.mariadb.com:8089](http://max-tst-01.mariadb.com:8089)
| Job | Description |
|----|----|
|[build_and_test](http://max-tst-01.mariadb.com:8089/view/test/job/build_and_test/)|Build Maxscale and run systems tests|
|[run_test](http://max-tst-01.mariadb.com:8089/view/test/job/run_test/)|Run system tests, Maxscale package should be in the repository|
|[build](http://max-tst-01.mariadb.com:8089/job/build/build)|Build Maxscale, create repository and publish it to [http://max-tst-01.mariadb.com/ci-repository/](http://max-tst-01.mariadb.com/ci-repository/)|
|[run_test_no_env_rebuild](http://max-tst-01.mariadb.com:8089/view/test/job/run_test_no_env_rebuild/)|Run system tests without creating a new set of VMs|
|[create_env](http://max-tst-01.mariadb.com:8089/view/env/job/create_env/)|Create VMs, install build environment to Maxscale machine, build Maxscale on Maxscale machine|
|[destroy](http://max-tst-01.mariadb.com:8089/view/axilary/job/destroy/)|Destroy VMs created by [run_test](http://max-tst-01.mariadb.com:8089/view/test/job/run_test/) or [create_env](http://max-tst-01.mariadb.com:8089/view/env/job/create_env/)|
|[remove_lock](http://max-tst-01.mariadb.com:8089/view/axilary/job/remove_lock/)|Remove Vagrant lock set by [run_test](http://max-tst-01.mariadb.com:8089/view/test/job/run_test/) or [create_env](http://max-tst-01.mariadb.com:8089/view/env/job/create_env/)|
Every test run should have unique name (parameter 'name'). This name is used as a name of MDBCI configuration.
If parameter 'do_not_destroy' is set to 'yes' virtual machines (VM) are not destroyed after tests execution and can be laters used
for debugging or new test runs (see [run_test_no_env_rebuild](http://max-tst-01.mariadb.com:8089/view/test/job/run_test_no_env_rebuild/))
VMs can be accessed from vagrant@max-tst-01.mariadb.com machine using 'mdbci ssh' or 'vagrant ssh' as well as direct ssh
access using environmental variables provided by
[set_env_vagrant.sh](https://github.com/mariadb-corporation/maxscale-system-test/blob/master/ENV_SETUP.md#access-vms)
script.
Parameter 'box' defines type of VM and Linux distribution to be used for tests.
Test results go to [CDash](http://jenkins.engskysql.com/CDash/index.php?project=MaxScale), logs and core dumps are
stored [here](http://max-tst-01.mariadb.com/LOGS/).
[create_env](http://max-tst-01.mariadb.com:8089/view/env/job/create_env/) job allows to create a set of VMs
(for backend and Maxscale) and does Maxscale build on the Maxscale VM. After execution this job Maxscale machine
contains Maxscale source and binaries. *NOTE:* to properly configure Maxscale init scripts it is necessary to
use rpm/dpkg tool to install Maxscale package (package can be found in the Maxscale build directory).
[run_test](http://max-tst-01.mariadb.com:8089/view/test/job/run_test/) and
[create_env](http://max-tst-01.mariadb.com:8089/view/env/job/create_env/)
jobs create Vagrant lock which prevents running two Vagrant instances in parallel (such parallel execution can
cause Vagrant of VM provider failures). In case of job crash or interruption by user Vagrant lock stays in locked state
and prevents any new VM creation. To remove lock job
[remove_lock](http://max-tst-01.mariadb.com:8089/view/axilary/job/remove_lock/)
should be used.
## Process examples
### Running regression test against a branch
Execute [build_and_test](http://max-tst-01.mariadb.com:8089/view/test/job/build_and_test/)
Recommendations regarding parameters:
* 'name' - unique name: it can be any text string, but as a good practice rule: 'name' should refer to branch,
Linux distribution, date/time of testing, MariaDB version
* 'box' - most recommended boxes are 'centos_7.0_libvirt' (QEMU box) and 'centos7' (Amazon Web Services box)
* 'source' - which type of source to use. BRANCH for git branch, TAG for a git tag and COMMIT for a commit ID.
* 'value' - name of the branch (if 'source' is BRANCH), name of the GIT tag (if 'source' is TAG) or commint ID (if 'source' is COMMIT)
### Build MaxScale
Execute [build](http://max-tst-01.mariadb.com:8089/job/build/build) job.
Parameter 'target' means a name of repository to put packages:
e.g. if 'target' is 'develop' packages are going to
[http://max-tst-01.mariadb.com/ci-repository/develop/](http://max-tst-01.mariadb.com/ci-repository/develop)
NOTE: building is executed only for selected distribution ('box' parameter). Be careful with other distributions: if build is not executed for same distribution old version can be in the repository (from some old builds). Later tests have to be executed against the same distribution otherwise they can be run against old version of MaxScale. It is recommended to use unique name for 'target'.
To debug failed build:
* set 'do_not_destroy_vm' parameter to 'yes'
* after the build:
<pre>
ssh -i vagrant.pem vagrant@max-tst-01.mariadb.com
cd ~/mdbci/build-&lt;box&gt;-&lt;date&gt;&lt;time&gt;
vagrant ssh
</pre>
For example:
<pre>
ssh -i vagrant.pem vagrant@max-tst-01.mariadb.com
cd ~/mdbci/build_centos6-20160119-0935
vagrant ssh
</pre>
### Create set of Master/Slave and Galera nodes and setup build environment for Maxscale on one more node
Execute [create_env](http://max-tst-01.mariadb.com:8089/view/env/job/create_env/) job.
Login to Maxscale machine (see [environment documentation](ENV_SETUP.md#access-vms)).
MaxScale source code, binaries and packages can be found in the ~/workspace/ directory.
All build tools are installed. GIT can be used to go trough source code.
It is not recommended to commit anything from virtual machine to GitHub.
Please use 'rpm' or 'dpkg' to properly install Maxscale package (/etc/init.d/maxscale script will not be
installed without execution of 'rpm' or 'dpkg')
### Running test agains exiting version of Maxscale
Execute [run_test](http://max-tst-01.mariadb.com:8089/view/test/job/run_test/) job.
Be sure Maxscale binary repository is present on the
[http://max-tst-01.mariadb.com/ci-repository/](http://max-tst-01.mariadb.com/ci-repository/)
server. Please check:
* there is a directory with the name equal to 'target' parameter
* there is sub-directory for selected distribution ('box' parameter)
e.g. if 'target' is 'develop' and distribution is CentOS7 (boxes 'centos7' or 'centos_7.0_libvirt') the directory [http://max-tst-01.mariadb.com/ci-repository/develop/mariadb-maxscale/centos/7/x86_64/](http://max-tst-01.mariadb.com/ci-repository/develop/mariadb-maxscale/centos/7/x86_64/) have to contain Maxscale RPM packages.
If parameter 'do_not_destroy' set to 'yes' after the test virtual machine will not be destroyed and
can be used for debugging. See [environment documentation](ENV_SETUP.md#access-vms) to get know how to access virtual machines.
### Maintenance operations
If test run was executed with parameter 'do_not_destroy' set yo 'yes' please do not forget to execute
[destroy](http://max-tst-01.mariadb.com:8089/view/axilary/job/destroy/) against your 'target'
This job also have to be executed if test run job crashed or it was interrupted.
In case of build or test job crash, interruption, Jenkins crash during Vagrant operation it is possible that Vagrant lock
stays in locked state and no other job can progress (job can be started, but it is waiting for Vagrant lock -
'/home/vagrant/vagrant_lock' can be seen in the job log). In this case lock can be removed by [remove_lock](http://max-tst-01.mariadb.com:8089/view/axilary/job/remove_lock/) job.

View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

View File

@ -0,0 +1,67 @@
# maxscale-system-test
System level tests for MaxScale
## Basics
- every test is separate executable file
- backend for test:
- 1 machine for Maxscale
- >= 4 machines for Master/Slave
- >= 4 machines for Galera cluster
- environmental variables contains all information about backend: IPs, user names, passwords, paths to tools, etc
- backed can be created with help of [MDBCI tool](https://github.com/OSLL/mdbci)
- configuring of Master/Slave and Galera can be done with help of [build scripts package](https://github.com/mariadb-corporation/build-scripts-vagrant)
## Manuals
[How to run tests](https://github.com/mariadb-corporation/build-scripts-vagrant/blob/master/RUN_TEST.md)
[Hints: How to write a test](HOW_TO_WRITE_TEST.md)
[Build and test environment setup (if you want to play with MDBCI and Vagrant on your local machine](ENV_SETUP.md)
[Jenkins instructions](JENKINS.md)
## Environmental variables
|variable|meaning|
|--------|-------|
|node_N|Number of machines for Master/Slave|
|node_XXX_network|IP address of Master/Slave machine number XXX|
|node_XXX_private_ip|private IP address of Master/Slave machine XXX for AWS machines (for everything else - same as node_XXX|
|node_XXX_port|MariaDB port of Master/Slave machine XXX|
|node_XXX_whoami|user name to access Master/Slave machine XXX via ssh|
|node_XXX_access_sudo|'sudo ' if node_access_user_XXX does not have root rights, empty string if node_access_user_XXX has root rights|
|node_XXX_keyfile|full name of secret key to access Master/Slave machine XXX via ssh|
|node_XXX_start_db_command|bash command to start DB server on Master/Slave machine XXX|
|node_XXX_stop_db_command|bash command to stop DB server on Master/Slave machine XXX|
|node_user|DB user name to access Master/Slave nodes (have to have all priveligies with GRANT option)|
|node_password|password for node_user|
|galera_N|Number of machines for Galera|
|galera_XXX_network|IP address of Galera machine number XXX|
|galera_XXX_private|private IP address of Galera machine XXX for AWS machines (for everything else - same as node_XXX|
|galera_XXX_port|MariaDB port of Galera machine XXX|
|galera_XXX_whoami|user name to access Galera machine XXX via ssh|
|galera_XXX_access|'sudo ' if node_access_user_XXX does not have root rights, empty string if node_access_user_XXX has root rights|
|galera_XXX_keyfile|full name of secret key to access Galera machine XXX via ssh|
|galera_XXX_start_db_command|bash command to start DB server on Galera machine XXX|
|galera_XXX_stop_db_command|bash command to stop DB server on Galera machine XXX|
|galera_user|DB user name to access Galera nodes (have to have all priveligies with GRANT option)|
|galera_password|password for node_user|
|maxscale_cnf|full name of Maxscale configuration file (maxscale.cnf)|
|maxscale_log_dir|directory for Maxscale log files|
|maxscale_IP|IP address of Maxscale machine|
|maxscale_sshkey|full name of secret key to access Maxscale machine via ssh|
|maxscale_access_user|user name to access Maxscale machine via ssh|
|maxscale_access_sudo|'sudo ' if maxscale_access_user does not have root rights, empty string if maxscale_access_user has root rights|
|maxscale_user|DB user to access via Maxscale|
|maxscale_password|password for maxscale_user|
|maxscale_hostname|hostname of Maxscale machine|
|sysbench_dir|directory where Sysbanch is installed|
|ssl|'yes' if tests should try to use ssl to connect to Maxscale and to backends (obsolete, now should be 'yes' in all cases)|
|smoke|if 'yes' all tests are executed in 'quick' mode (less iterations, skip heavy operations)|
|backend_ssl|if 'yes' ssl config will be added to all servers definition in maxscale.cnf|
|use_snapshots|if TRUE every test is trying to revert snapshot before running the test|
|take_snapshot_command|revert_snapshot_command|
|revert_snapshot_command|Command line to revert a snapshot of all VMs|
|no_nodes_check|if yes backend checks are not executed (needed in case of RDS or similar backend)|
|no_backend_log_copy|if yes logs from backend nodes are not copied (needed in case of RDS or similar backend)|
|no_maxscale_start|Do not start Maxscale automatically|

View File

@ -0,0 +1,32 @@
# Results locations
| Location | Description |
|----------|-------------|
|[run_test](http://max-tst-01.mariadb.com:8089/view/test/job/run_test/) Jenkins job log|Vagrant and test application outputs|
|[CDash](jenkins.engskysql.com/CDash/index.php?project=MaxScale)|CTest reports|
|[http://max-tst-01.mariadb.com/LOGS/](http://max-tst-01.mariadb.com/LOGS/)|MaxScale logs and core dumps|
|/home/vagrant/LOGS|Same as [http://max-tst-01.mariadb.com/LOGS/](http://max-tst-01.mariadb.com/LOGS/)|
|Maxscale VM /var/log/maxscale|MaxScale log from latest test case|
|Maxscale VM /tpm/core*|Core dump from latest test case|
|Maxscale VM home directory|QLA filter files (if enabled in MaxScale test configuration|
|nodeN, galeraN VMs|MariaDB/MySQL logs (see MariaDB/MySQL documentation for details)|
For access to VMs see [environment documentation](ENV_SETUP.md#access-vms)
Jenkins job log consists of following parts:
* Vagrant output: VMs creation priocess, MariaDB Master/Slave and MariaDB Galera stuff installation, MaxScale installation
* [set_env_vagrant.sh](https://github.com/mariadb-corporation/build-scripts-vagrant/blob/master/test/set_env_vagrant.sh) output: retrieval of all VM parameters
* setup scripts output: MariaDB initialisation on backend nodes, DB users setup, enabling core dump on MaxScale VM
* test application output for all tests: eevry line starts from test case number and ':' (can be grepped)
* CTest final printing: N of M tests passed, CTest warnings, email sending logs
To check presence of core dumps:
<pre>
find /home/vagrant/LOGS/&lt;last_test_results_dir&gt; | grep core
</pre>
where 'last_test_results_dir' - automatically generated name of logs directory (based on date and time of test run)
To understand test case output please see test case description in Doxygen comments in every test case source file.
VMs are alive after the test run only if test run is done with 'do_not_destroy' parameter.

View File

@ -0,0 +1,14 @@
--style=allman
--indent=spaces=4
--indent-switches
--indent-labels
--min-conditional-indent=0
--pad-oper
--pad-header
--add-brackets
--convert-tabs
--max-code-length=110
--break-after-logical
--mode=c
--suffix=none
--max-instatement-indent=110

View File

@ -0,0 +1,157 @@
/**
* @file auroramon.cpp test of Aurora RDS monitor
* - create RDS cluster
* - find 'writer' node and uses 'maxadmin' to check that this node is "Master, Running"
* - do forced failover
* - find 'writer' again and repeat check
* - destroy RDS cluster
*/
#include "testconnections.h"
#include "execute_cmd.h"
#include "rds_vpc.h"
int set_endspoints(RDS * cluster)
{
json_t *endpoint;
long long int port;
const char * IP;
char p[64];
size_t i;
char cmd[1024];
json_t * endpoints = cluster->get_endpoints();
if (endpoints == NULL)
{
return -1;
}
json_array_foreach(endpoints, i, endpoint)
{
port = json_integer_value(json_object_get(endpoint, "Port"));
IP = json_string_value(json_object_get(endpoint, "Address"));
printf("host: %s \t port: %lld\n", IP, port);
sprintf(cmd, "node_%03d_network", (int) i);
setenv(cmd, IP, 1);
sprintf(cmd, "node_%03d_port", (int) i);
sprintf(p, "%lld", port);
setenv(cmd, p, 1);
}
setenv("node_password", "skysqlrds", 1);
setenv("maxscale_user", "skysql", 1);
setenv("maxscale_password", "skysqlrds", 1);
setenv("no_nodes_check", "yes", 1);
setenv("no_backend_log_copy", "yes", 1);
return 0;
}
void compare_masters(TestConnections* Test, RDS * cluster)
{
const char * aurora_master;
cluster->get_writer(&aurora_master);
Test->tprintf("Aurora writer node: %s\n", aurora_master);
char maxadmin_status[1024];
int i;
char cmd[1024];
for (i = 0; i < Test->repl->N; i++)
{
sprintf(cmd, "show server server%d", i + 1);
Test->get_maxadmin_param(cmd, (char *) "Status:", &maxadmin_status[0]);
Test->tprintf("Server%d status %s\n", i + 1, maxadmin_status);
sprintf(cmd, "node%03d", i);
if (strcmp(aurora_master, cmd) == 0)
{
if (strcmp(maxadmin_status, "Master, Running"))
{
Test->tprintf("Maxadmin reports node%03d is a Master as expected", i);
}
else
{
Test->add_result(1, "Server node%03d status is not 'Master, Running'', it is '%s'", i, maxadmin_status);
}
}
else
{
if (strcmp(maxadmin_status, "Slave, Running"))
{
Test->tprintf("Maxadmin reports node%03d is a Slave as expected", i);
}
else
{
Test->add_result(1, "Server node%03d status is not 'Slave, Running'', it is '%s'", i, maxadmin_status);
}
}
}
}
int main(int argc, char *argv[])
{
RDS * cluster = new RDS((char *) "auroratest");
if (cluster->create_rds_db(4) != 0)
{
printf("Error RDS creation\n");
return 1;
}
cluster->wait_for_nodes(4);
if (set_endspoints(cluster) != 0)
{
printf("Error getting RDS endpoints\n");
return 1;
}
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(30);
compare_masters(Test, cluster);
Test->set_timeout(30);
Test->tprintf("Executing a query through readwritesplit before failover");
Test->connect_rwsplit();
Test->try_query(Test->conn_rwsplit, "show processlist");
char server_id[1024];
Test->tprintf("Get aurora_server_id\n");
find_field(Test->conn_rwsplit, "select @@aurora_server_id;", "server_id", &server_id[0]);
Test->close_rwsplit();
Test->tprintf("server_id before failover: %s\n", server_id);
Test->stop_timeout();
Test->tprintf("Performing cluster failover\n");
Test->add_result(cluster->do_failover(), "Failover failed\n");
Test->tprintf("Failover done\n");
// Do the failover here and wait until it is over
//sleep(10);
Test->set_timeout(30);
Test->tprintf("Executing a query through readwritesplit after failover");
Test->connect_rwsplit();
Test->try_query(Test->conn_rwsplit, "show processlist");
Test->tprintf("Get aurora_server_id\n");
find_field(Test->conn_rwsplit, "select @@aurora_server_id;", "server_id", &server_id[0]);
Test->close_rwsplit();
Test->tprintf("server_id after failover: %s\n", server_id);
compare_masters(Test, cluster);
//Test->check_maxscale_alive();
Test->stop_timeout();
cluster->delete_rds_cluster();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,107 @@
/**
* @file avro.cpp test of avro
* - setup binlog and avro
* - put some data to t1
* - check avro file with "maxavrocheck -vv /var/lib/maxscale/avro/test.t1.000001.avro"
* - check that data in avro file is correct
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
#include "sql_t1.h"
#include "test_binlog_fnc.h"
#include <jansson.h>
#include "maxinfo_func.h"
#include <sstream>
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(600);
Test->stop_maxscale();
Test->ssh_maxscale(true, (char *) "rm -rf /var/lib/maxscale/avro");
Test->repl->connect();
execute_query(Test->repl->nodes[0], "DROP TABLE IF EXISTS t1");
Test->repl->close_connections();
sleep(5);
Test->start_binlog();
Test->set_timeout(120);
Test->stop_maxscale();
Test->ssh_maxscale(true, "rm -rf /var/lib/maxscale/avro");
Test->set_timeout(120);
Test->start_maxscale();
Test->set_timeout(60);
Test->repl->connect();
create_t1(Test->repl->nodes[0]);
insert_into_t1(Test->repl->nodes[0], 3);
execute_query(Test->repl->nodes[0], "FLUSH LOGS");
Test->repl->close_connections();
Test->set_timeout(120);
sleep(10);
char * avro_check = Test->ssh_maxscale_output(true,
"maxavrocheck -vv /var/lib/maxscale/avro/test.t1.000001.avro | grep \"{\"");
char * output = Test->ssh_maxscale_output(true, "maxavrocheck -d /var/lib/maxscale/avro/test.t1.000001.avro");
std::istringstream iss;
iss.str(output);
int x1_exp = 0;
int fl_exp = 0;
int x = 16;
for (std::string line; std::getline(iss, line);)
{
long long int x1, fl;
Test->set_timeout(20);
get_x_fl_from_json((char*)line.c_str(), &x1, &fl);
if (x1 != x1_exp || fl != fl_exp)
{
Test->add_result(1, "Output:x1 %lld, fl %lld, Expected: x1 %d, fl %d",
x1, fl, x1_exp, fl_exp);
break;
}
if ((++x1_exp) >= x)
{
x1_exp = 0;
x = x * 16;
fl_exp++;
Test->tprintf("fl = %d", fl_exp);
}
}
if (fl_exp != 3)
{
Test->add_result(1, "not enough lines in avrocheck output\n");
}
Test->set_timeout(120);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,60 @@
/**
* @file avro_long.cpp test of avro
* - setup binlog and avro
* - put some data to t1 in the loop
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
#include "sql_t1.h"
#include "test_binlog_fnc.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(600);
Test->stop_maxscale();
Test->ssh_maxscale(true, (char *) "rm -rf /var/lib/maxscale/avro");
//Test->ssh_maxscale(true, (char *) "mkdir /var/lib/maxscale/avro; chown -R maxscale:maxscale /var/lib/maxscale/avro");
Test->repl->connect();
execute_query(Test->repl->nodes[0], (char *) "DROP TABLE IF EXISTS t1;");
Test->repl->close_connections();
sleep(5);
Test->start_binlog();
Test->set_timeout(120);
Test->stop_maxscale();
Test->ssh_maxscale(true, (char *) "rm -rf /var/lib/maxscale/avro");
Test->set_timeout(120);
Test->start_maxscale();
Test->set_timeout(60);
Test->repl->connect();
create_t1(Test->repl->nodes[0]);
for (int i = 0; i < 1000000; i++)
{
Test->set_timeout(60);
insert_into_t1(Test->repl->nodes[0], 3);
Test->tprintf("i=%d\n", i);
}
Test->repl->close_connections();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,40 @@
/**
* @backend_auth_fail.cpp Repeatedly connect to maxscale while the backends reject all connections
*
* MaxScale should not crash
*/
#include "testconnections.h"
int main(int argc, char** argv)
{
MYSQL *mysql[1000];
TestConnections * Test = new TestConnections(argc, argv);
Test->stop_timeout();
Test->repl->execute_query_all_nodes((char *) "set global max_connections = 10;");
for (int x = 0; x < 3; x++)
{
Test->tprintf("Creating 100 connections...\n");
for (int i = 0; i < 100; i++)
{
Test->set_timeout(30);
mysql[i] = Test->open_readconn_master_connection();
execute_query_silent(mysql[i], "select 1");
}
Test->stop_timeout();
for (int i = 0; i < 100; i++)
{
Test->set_timeout(30);
mysql_close(mysql[i]);
}
}
Test->stop_timeout();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,27 @@
/**
* @file bad_pres.cpp check that Maxscale prints warning if persistpoolmax=-1 for all backends (bug MXS-576)
*
* - Maxscale.cnf contains persistpoolmax=-1 for all servers
* - check log warning about it
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->connect_maxscale();
Test->check_log_err((char *) "warning -1", true);
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,228 @@
#include "big_load.h"
#include <pthread.h>
void load(long int *new_inserts, long int *new_selects, long int *selects, long int *inserts, int threads_num,
TestConnections * Test, long int *i1, long int *i2, int rwsplit_only, bool galera, bool report_errors)
{
char sql[1000000];
thread_data data;
Mariadb_nodes * nodes;
if (galera)
{
nodes = Test->galera;
}
else
{
nodes = Test->repl;
}
int sql_l = 20000;
int run_time = 100;
if (Test->smoke)
{
sql_l = 500;
run_time = 10;
}
nodes->connect();
Test->connect_rwsplit();
data.i1 = 0;
data.i2 = 0;
data.exit_flag = 0;
data.Test = Test;
data.rwsplit_only = rwsplit_only;
// connect to the MaxScale server (rwsplit)
if (Test->conn_rwsplit == NULL )
{
if (report_errors)
{
Test->add_result(1, "Can't connect to MaxScale\n");
}
//Test->copy_all_logs();
exit(1);
}
else
{
create_t1(Test->conn_rwsplit);
create_insert_string(sql, sql_l, 1);
if ((execute_query(Test->conn_rwsplit, sql) != 0) && (report_errors))
{
Test->add_result(1, "Query %s failed\n", sql);
}
// close connections
Test->close_rwsplit();
Test->tprintf("Waiting for the table to replicate\n");
Test->repl->sync_slaves();
pthread_t thread1[threads_num];
pthread_t thread2[threads_num];
int iret1[threads_num];
int iret2[threads_num];
Test->tprintf("COM_INSERT and COM_SELECT before executing test\n");
Test->add_result(get_global_status_allnodes(&selects[0], &inserts[0], nodes, 0),
"get_global_status_allnodes failed\n");
data.exit_flag = 0;
/* Create independent threads each of them will execute function */
for (int i = 0; i < threads_num; i++)
{
iret1[i] = pthread_create(&thread1[i], NULL, query_thread1, &data);
iret2[i] = pthread_create(&thread2[i], NULL, query_thread2, &data);
}
Test->tprintf("Threads are running %d seconds \n", run_time);
sleep(run_time);
data.exit_flag = 1;
Test->tprintf("Waiting for all threads to exit\n");
Test->set_timeout(100);
for (int i = 0; i < threads_num; i++)
{
pthread_join(thread1[i], NULL);
pthread_join(thread2[i], NULL);
}
sleep(1);
Test->tprintf("COM_INSERT and COM_SELECT after executing test\n");
get_global_status_allnodes(&new_selects[0], &new_inserts[0], nodes, 0);
print_delta(&new_selects[0], &new_inserts[0], &selects[0], &inserts[0], nodes->N);
Test->tprintf("First group of threads did %d queries, second - %d \n", data.i1, data.i2);
}
nodes->close_connections();
*i1 = data.i1;
*i2 = data.i2;
}
void *query_thread1( void *ptr )
{
MYSQL * conn1;
MYSQL * conn2;
MYSQL * conn3;
int conn_err = 0;
thread_data * data = (thread_data *) ptr;
conn1 = open_conn_db_timeout(data->Test->rwsplit_port,
data->Test->maxscale_IP,
(char *) "test",
data->Test->maxscale_user,
data->Test->maxscale_password,
20,
data->Test->ssl);
//conn1 = data->Test->open_rwsplit_connection();
if (mysql_errno(conn1) != 0)
{
conn_err++;
}
if (data->rwsplit_only == 0)
{
//conn2 = data->Test->open_readconn_master_connection();
conn2 = open_conn_db_timeout(data->Test->readconn_master_port,
data->Test->maxscale_IP,
(char *) "test",
data->Test->maxscale_user,
data->Test->maxscale_password,
20,
data->Test->ssl);
if (mysql_errno(conn2) != 0)
{
conn_err++;
}
//conn3 = data->Test->open_readconn_slave_connection();
conn3 = open_conn_db_timeout(data->Test->readconn_slave_port,
data->Test->maxscale_IP,
(char *) "test",
data->Test->maxscale_user,
data->Test->maxscale_password,
20,
data->Test->ssl);
if (mysql_errno(conn3) != 0)
{
conn_err++;
}
}
if (conn_err == 0)
{
while (data->exit_flag == 0)
{
if (execute_query_silent(conn1, (char *) "SELECT * FROM t1;") == 0)
{
__sync_fetch_and_add(&data->i1, 1);
}
if (data->rwsplit_only == 0)
{
execute_query_silent(conn2, (char *) "SELECT * FROM t1;");
execute_query_silent(conn3, (char *) "SELECT * FROM t1;");
}
}
mysql_close(conn1);
if (data->rwsplit_only == 0)
{
mysql_close(conn2);
mysql_close(conn3);
}
}
return NULL;
}
void *query_thread2(void *ptr )
{
MYSQL * conn1;
MYSQL * conn2;
MYSQL * conn3;
thread_data * data = (thread_data *) ptr;
//conn1 = data->Test->open_rwsplit_connection();
conn1 = open_conn_db_timeout(data->Test->rwsplit_port,
data->Test->maxscale_IP,
(char *) "test",
data->Test->maxscale_user,
data->Test->maxscale_password,
20,
data->Test->ssl);
if (data->rwsplit_only == 0)
{
//conn2 = data->Test->open_readconn_master_connection();
//conn3 = data->Test->open_readconn_slave_connection();
conn2 = open_conn_db_timeout(data->Test->readconn_master_port,
data->Test->maxscale_IP,
(char *) "test",
data->Test->maxscale_user,
data->Test->maxscale_password,
20,
data->Test->ssl);
//if (mysql_errno(conn2) != 0) { conn_err++; }
conn3 = open_conn_db_timeout(data->Test->readconn_slave_port,
data->Test->maxscale_IP,
(char *) "test",
data->Test->maxscale_user,
data->Test->maxscale_password,
20,
data->Test->ssl);
//if (mysql_errno(conn3) != 0) { conn_err++; }
}
while (data->exit_flag == 0)
{
sleep(1);
if (execute_query_silent(conn1, (char *) "SELECT * FROM t1;") == 0)
{
__sync_fetch_and_add(&data->i2, 1);
}
if (data->rwsplit_only == 0)
{
execute_query_silent(conn2, (char *) "SELECT * FROM t1;");
execute_query_silent(conn3, (char *) "SELECT * FROM t1;");
}
}
mysql_close(conn1);
if (data->rwsplit_only == 0)
{
mysql_close(conn2);
mysql_close(conn3);
}
return NULL;
}

View File

@ -0,0 +1,39 @@
#ifndef BIG_LOAD_H
#define BIG_LOAD_H
#include "testconnections.h"
#include "sql_t1.h"
#include "get_com_select_insert.h"
//pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
typedef struct
{
int exit_flag;
long i1;
long i2;
int rwsplit_only;
TestConnections * Test;
} thread_data;
void *query_thread1(void *ptr );
void *query_thread2(void *ptr );
/**
* @brief load Creates load on Maxscale routers
* @param new_inserts COM_INSERT variable values array for all nodes after test
* @param new_selects COM_SELECT variable values array for all nodes after test
* @param selects COM_SELECT variable values array for all nodes before test
* @param inserts COM_INSERT variable values array for all nodes before test
* @param threads_num Number of load threads
* @param Test TestConnections object
* @param i1 Number of queries executed by "fast" threads (no wating between queries)
* @param i2 Number of queries executed by "slow" threads (sleep 1 second between queries)
* @param rwsplit_only if 1 create load only on RWSplit router, do not load ReadConn router
* @param galera if true use Galera backend (Test->galera instead of Test->repl)
* @param report_errors if true call add_result() in case of query failure
*/
void load(long *new_inserts, long *new_selects, long *selects, long *inserts, int threads_num,
TestConnections *Test, long *i1, long *i2, int rwsplit_only, bool galera, bool report_errors);
#endif // BIG_LOAD_H

View File

@ -0,0 +1,23 @@
#include "big_transaction.h"
int big_transaction(MYSQL * conn, int N)
{
int local_result = 0;
char sql[1000000];
local_result += create_t1(conn);
local_result += execute_query(conn, (char *) "START TRANSACTION");
local_result += execute_query(conn, (char *) "SET autocommit = 0");
for (int i = 0; i < N; i++)
{
create_insert_string(sql, 10000, i);
local_result += execute_query(conn, sql);
local_result += execute_query(conn, "CREATE TABLE t2(id int);");
local_result += execute_query(conn, sql);
local_result += execute_query(conn, "DROP TABLE t2;");
local_result += execute_query(conn, sql);
}
local_result += execute_query(conn, (char *) "COMMIT");
return local_result;
}

View File

@ -0,0 +1,17 @@
#ifndef BIG_TRANSACTION_H
#define BIG_TRANSACTION_H
#include <mariadb/mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include "sql_t1.h"
/**
* @brief big_transaction Executes big transaction (includes N INSERTs of 10000 rows)
* @param conn MYSQL connection handler
* @param N Number of INSERTs
* @return 0 if success
*/
int big_transaction(MYSQL * conn, int N);
#endif // BIG_TRANSACTION_H

View File

@ -0,0 +1,72 @@
/**
* @file binlog_big_transaction.cpp test of simple binlog router setup and execute a number of big transactions
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
#include "sql_t1.h"
#include "test_binlog_fnc.h"
#include "big_transaction.h"
void *disconnect_thread( void *ptr );
TestConnections * Test ;
int exit_flag;
int main(int argc, char *argv[])
{
Test = new TestConnections(argc, argv);
Test->set_timeout(3000);
Test->set_log_copy_interval(300);
Test->repl->connect();
execute_query(Test->repl->nodes[0], (char *) "DROP TABLE IF EXISTS t1;");
Test->repl->close_connections();
sleep(5);
Test->start_binlog();
pthread_t threads;
int iret;
exit_flag = 0;
iret = pthread_create( &threads, NULL, disconnect_thread, NULL);
Test->repl->connect();
for (int i = 0; i < 100000; i++)
{
Test->set_timeout(3000);
Test->tprintf("Trying transactions: %d\n", i);
Test->add_result(big_transaction(Test->repl->nodes[0], 7), "Transaction %d failed!\n", i);
}
Test->repl->close_connections();
int rval = Test->global_result;
delete Test;
return rval;
}
void *disconnect_thread( void *ptr )
{
MYSQL * conn;
char cmd[256];
int i;
conn = open_conn(Test->binlog_port, Test->maxscale_IP, Test->repl->user_name, Test->repl->password,
Test->repl->ssl);
Test->add_result(mysql_errno(conn), "Error connecting to Binlog router, error: %s\n", mysql_error(conn));
i = 3;
while (exit_flag == 0)
{
sprintf(cmd, "DISCONNECT SERVER %d", i);
execute_query(conn, cmd);
i++;
if (i > Test->repl->N)
{
i = 3;
sleep(30);
execute_query(conn, (char *) "DISCONNECT SERVER ALL");
}
sleep(5);
}
return NULL;
}

View File

@ -0,0 +1,322 @@
/**
* @file binlog_change_master.cpp In the binlog router setup stop Master and promote one of the Slaves to be new Master
* - setup binlog
* - start thread wich executes transactions
* - block master
* - transaction thread tries to elect a new master a continue with new master
* - continue transaction with new master
* - stop transactions
* - wait
* - chack data on all nodes
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
#include "sql_t1.h"
#include "test_binlog_fnc.h"
#include "big_transaction.h"
void *disconnect_thread( void *ptr );
void *transaction_thread( void *ptr );
TestConnections * Test ;
int exit_flag;
int master = 0;
int i_trans = 0;
int failed_transaction_num = 0;
/** The amount of rows each transaction inserts */
const int N_INSERTS = 100;
int transaction(MYSQL * conn, int N)
{
int local_result = 0;
char sql[1000000];
Test->tprintf("START TRANSACTION\n");
local_result += execute_query(conn, (char *) "START TRANSACTION");
if (local_result != 0)
{
Test->tprintf("START TRANSACTION Failed\n");
return local_result;
}
Test->tprintf("SET autocommit = 0\n");
local_result += execute_query(conn, (char *) "SET autocommit = 0");
if (local_result != 0)
{
Test->tprintf("SET Failed\n");
return local_result;
}
create_insert_string(sql, N_INSERTS, N);
Test->tprintf("INSERT\n");
local_result += execute_query(conn, sql);
if (local_result != 0)
{
Test->tprintf("Insert Failed\n");
return local_result;
}
Test->tprintf("COMMIT\n");
local_result += execute_query(conn, (char *) "COMMIT");
if (local_result != 0)
{
Test->tprintf("Commit Failed\n");
return local_result;
}
return local_result;
}
int main(int argc, char *argv[])
{
int j;
Test = new TestConnections(argc, argv);
Test->set_timeout(3000);
Test->repl->connect();
execute_query(Test->repl->nodes[0], (char *) "DROP TABLE IF EXISTS t1;");
Test->repl->close_connections();
sleep(5);
Test->repl->connect();
Test->repl->execute_query_all_nodes((char *) "STOP SLAVE");
Test->repl->execute_query_all_nodes((char *) "RESET SLAVE ALL");
Test->repl->execute_query_all_nodes((char *) "RESET MASTER");
Test->tprintf("Starting binlog configuration\n");
Test->start_binlog();
pthread_t disconnec_thread_t;
int disconnect_iret;
pthread_t transaction_thread_t;
int transaction_iret;
exit_flag = 0;
Test->tprintf("Starting query thread\n");
transaction_iret = pthread_create(&transaction_thread_t, NULL, transaction_thread, NULL);
Test->tprintf("Sleeping\n");
Test->stop_timeout();
Test->repl->connect();
int flushes = Test->smoke ? 2 : 5;
for (j = 0; j < flushes; j++)
{
Test->tprintf("Flush logs on master\n");
execute_query(Test->repl->nodes[0], (char *) "flush logs");
sleep(15);
}
sleep(15);
Test->tprintf("Blocking master\n");
Test->repl->block_node(0);
Test->stop_timeout();
sleep(30);
Test->tprintf("Done! Waiting for thread\n");
exit_flag = 1;
pthread_join(transaction_thread_t, NULL );
Test->tprintf("Done!\n");
Test->tprintf("Checking data on the node3 (slave)\n");
char sql[256];
char rep[256];
int rep_d;
Test->tprintf("Sleeping to let replication happen\n");
sleep(30);
Test->repl->connect();
for (int i_n = 3; i_n < Test->repl->N; i_n++)
{
for (j = 0; j < i_trans; j++)
{
sprintf(sql, "select count(*) from t1 where fl=%d;", j);
find_field(Test->repl->nodes[i_n], sql, (char *) "count(*)", rep);
Test->tprintf("Transaction %d put %s rows\n", j, rep);
sscanf(rep, "%d", &rep_d);
if ((rep_d != N_INSERTS) && (j != (failed_transaction_num - 1)))
{
Test->add_result(1, "Transaction %d did not put data into slave\n", j);
}
if ((j == (failed_transaction_num - 1)) && (rep_d != 0) && (rep_d != N_INSERTS))
{
Test->add_result(1, "Incomplete transaction detected - %d\n", j);
}
if ((j == (failed_transaction_num - 1) && rep_d == 0))
{
Test->tprintf("Transaction %d was rejected, OK\n", j);
}
}
}
Test->repl->close_connections();
int rval = Test->global_result;
delete Test;
return rval;
}
const char * setup_slave1 =
"change master to MASTER_HOST='%s',\
MASTER_USER='repl',\
MASTER_PASSWORD='repl',\
MASTER_LOG_FILE='%s',\
MASTER_LOG_POS=%s,\
MASTER_PORT=%d";
int select_new_master(TestConnections * test)
{
char log_file[256];
char log_file_new[256];
char log_pos[256];
char maxscale_log_file[256];
char maxscale_log_file_new[256];
char maxscale_log_pos[256];
// Stopping slave
test->tprintf("Connection to backend\n");
test->repl->connect();
test->tprintf("'stop slave' to node2\n");
test->try_query(Test->repl->nodes[2], (char *) "stop slave;");
test->tprintf("'reset slave all' to node2\n");
test->try_query(Test->repl->nodes[2], (char *) "RESET slave all;");
//execute_query(Test->repl->nodes[2], (char *) "reset master;");
// Get master status
test->tprintf("show master status\n");
find_field(test->repl->nodes[2], (char *) "show master status", (char *) "File", &log_file[0]);
find_field(test->repl->nodes[2], (char *) "show master status", (char *) "Position", &log_pos[0]);
test->tprintf("Real master file: %s\n", log_file);
test->tprintf("Real master pos : %s\n", log_pos);
test->tprintf("Connecting to MaxScale binlog router (with any DB)\n");
MYSQL * binlog = open_conn_no_db(test->binlog_port, test->maxscale_IP, test->repl->user_name,
test->repl->password, test->ssl);
test->add_result(mysql_errno(binlog), "Error connection to binlog router %s\n", mysql_error(binlog));
test->tprintf("show master status on maxscale\n");
find_field(binlog, (char *) "show master status", (char *) "File", &maxscale_log_file[0]);
find_field(binlog, (char *) "show master status", (char *) "Position", &maxscale_log_pos[0]);
if (!maxscale_log_file[0] || !maxscale_log_pos[0])
{
test->add_result(1, "Failed to query for master status");
return 1;
}
test->tprintf("Real master file: %s\n", maxscale_log_file);
test->tprintf("Real master pos : %s\n", maxscale_log_pos);
char * p = strchr(maxscale_log_file, '.') + 1;
test->tprintf("log file num %s\n", p);
int pd;
sscanf(p, "%d", &pd);
test->tprintf("log file num (d) %d\n", pd);
p[0] = '\0';
test->tprintf("log file name %s\n", maxscale_log_file);
sprintf(maxscale_log_file_new, "%s%06d", maxscale_log_file, pd + 1);
test->try_query(test->repl->nodes[2], (char *) "reset master");
test->tprintf("Flush logs %d times\n", pd + 1);
for (int k = 0; k < pd + 1; k++)
{
test->try_query(test->repl->nodes[2], (char *) "flush logs");
}
// Set Maxscale to new master
test->try_query(binlog, "stop slave");
test->tprintf("configuring Maxscale binlog router\n");
test->tprintf("reconnect to binlog\n");
mysql_close(binlog);
binlog = open_conn_no_db(test->binlog_port, test->maxscale_IP, test->repl->user_name, test->repl->password,
test->ssl);
test->add_result(mysql_errno(binlog), "Error connection to binlog router %s\n", mysql_error(binlog));
char str[1024];
//sprintf(str, setup_slave1, test->repl->IP[2], log_file_new, test->repl->port[2]);
sprintf(str, setup_slave1, test->repl->IP[2], maxscale_log_file_new, "4", test->repl->port[2]);
test->tprintf("change master query: %s\n", str);
test->try_query(binlog, str);
test->try_query(binlog, "start slave");
test->repl->close_connections();
}
void *disconnect_thread( void *ptr )
{
MYSQL * conn;
char cmd[256];
int i;
conn = open_conn(Test->binlog_port, Test->maxscale_IP, Test->repl->user_name, Test->repl->password,
Test->repl->ssl);
Test->add_result(mysql_errno(conn), "Error connecting to Binlog router, error: %s\n", mysql_error(conn));
i = 3;
while (exit_flag == 0)
{
sprintf(cmd, "DISCONNECT SERVER %d", i);
execute_query(conn, cmd);
i++;
if (i > Test->repl->N)
{
i = 3;
sleep(30);
execute_query(conn, (char *) "DISCONNECT SERVER ALL");
}
sleep(5);
}
return NULL;
}
void *transaction_thread( void *ptr )
{
MYSQL * conn;
int trans_result = 0;
conn = open_conn_db_timeout(Test->repl->port[master], Test->repl->IP[master], (char *) "test",
Test->repl->user_name, Test->repl->password, 20, Test->repl->ssl);
Test->add_result(mysql_errno(conn), "Error connecting to Binlog router, error: %s\n", mysql_error(conn));
create_t1(conn);
while ((exit_flag == 0))
{
Test->tprintf("Transaction %d\n", i_trans);
trans_result = transaction(conn, i_trans);
if (trans_result != 0)
{
Test->tprintf("Transaction %d failed, doing master failover\n", i_trans);
failed_transaction_num = i_trans;
Test->tprintf("Closing connection\n");
mysql_close(conn);
Test->tprintf("Calling select_new_master()\n");
select_new_master(Test);
master = 2;
conn = open_conn_db_timeout(Test->repl->port[master], Test->repl->IP[master], (char *) "test",
Test->repl->user_name, Test->repl->password, 20, Test->repl->ssl);
Test->add_result(mysql_errno(conn), "Error connecting to Binlog router, error: %s\n", mysql_error(conn));
Test->tprintf("Retrying transaction %d\n", i_trans);
i_trans--;
}
i_trans++;
}
i_trans--;
return NULL;
}

View File

@ -0,0 +1,12 @@
[mysqld]
plugin-load-add=file_key_management.so
file_key_management_encryption_algorithm=aes_cbc
file_key_management_filename = /etc/mariadb_binlog_keys.txt
encrypt-binlog=1
# Enable checksum
binlog_checksum=CRC32
#Enable large packets handling
max_allowed_packet=1042M
innodb_log_file_size=142M

View File

@ -0,0 +1,12 @@
[mysqld]
plugin-load-add=file_key_management.so
file_key_management_encryption_algorithm=aes_ctr
file_key_management_filename = /etc/mariadb_binlog_keys.txt
encrypt-binlog=1
# Enable checksum
binlog_checksum=CRC32
#Enable large packets handling
max_allowed_packet=1042M
innodb_log_file_size=142M

View File

@ -0,0 +1,16 @@
/**
* @file binlog_failover.cpp binlog_failover Test of failover scenarion for binlog router
*
* - setup following configuration:
* - one master
* - two maxscale binlog machines
* - two slaves connected to each maxscale binlog mashine
* - put some date via master
* - block master
* - stop all Maxscale machines with STOP SLAVE command
* - check which Maxscale machine contains most recent data (let's call this machine 'most_recent_maxscale')
* - use CHANGE MASETER on the second Maxscale machine to point it to the Maxscale machine from the previous step ('most_recent_maxscale')
* - wait until second Maxscale is in sync with 'most_recent_maxscale' (use SHOW MASTER STATUS)
* - select new master (HOW??)
* - set all Maxscale machines to be a slaves of new master
*/

View File

@ -0,0 +1,26 @@
/**
* @file setup_incompl trying to start binlog setup with incomplete Maxscale.cnf
* check for crash
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
#include "sql_t1.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(60);
Test->connect_maxscale();
Test->close_maxscale_connections();
sleep(10);
Test->check_log_err("fatal signal 11", false);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,91 @@
/**
* @file binlog_semisync.cpp Same test as setup_binlog, but with semisync enabled
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
#include "sql_t1.h"
#include "test_binlog_fnc.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->tprintf("Test object initialized\n");
Test->set_timeout(3000);
int options_set = 3;
if (Test->smoke)
{
options_set = 1;
}
Test->tprintf("Trying to connect to backend\n");
if (Test->repl->connect() == 0)
{
Test->tprintf("DROP TABLE t1\n");
execute_query(Test->repl->nodes[0], (char *) "DROP TABLE IF EXISTS t1;");
//Test->tprintf("SET GLOBAL rpl_semi_sync_master_enabled = 1;\n");
//execute_query(Test->repl->nodes[0], (char *) "SET GLOBAL rpl_semi_sync_master_enabled = 1;");
Test->repl->close_connections();
sleep(5);
for (int option = 0; option < options_set; option++)
{
Test->binlog_cmd_option = option;
Test->start_binlog();
Test->repl->connect();
Test->tprintf("install semisync plugin\n");
execute_query(Test->repl->nodes[0],
(char *) "INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';");
//sleep(10);
Test->tprintf("Reconnect\n");
Test->repl->close_connections();
Test->repl->connect();
Test->tprintf("SET GLOBAL rpl_semi_sync_master_enabled = 1;\n");
execute_query(Test->repl->nodes[0], (char *) "SET GLOBAL rpl_semi_sync_master_enabled = 1;");
//sleep(10);
Test->repl->close_connections();
test_binlog(Test);
Test->repl->connect();
Test->tprintf("SET GLOBAL rpl_semi_sync_master_enabled = 0;\n");
execute_query(Test->repl->nodes[0], (char *) "SET GLOBAL rpl_semi_sync_master_enabled = 0;");
//sleep(10);
Test->repl->close_connections();
test_binlog(Test);
Test->repl->connect();
Test->tprintf("uninstall semisync plugin\n");
execute_query(Test->repl->nodes[0], (char *) "UNINSTALL PLUGIN rpl_semi_sync_master;");
Test->tprintf("Reconnect\n");
Test->repl->close_connections();
Test->repl->connect();
Test->tprintf("SET GLOBAL rpl_semi_sync_master_enabled = 1;\n");
execute_query(Test->repl->nodes[0], (char *) "SET GLOBAL rpl_semi_sync_master_enabled = 1;");
//sleep(10);
Test->repl->close_connections();
test_binlog(Test);
Test->repl->connect();
Test->tprintf("SET GLOBAL rpl_semi_sync_master_enabled = 0;\n");
execute_query(Test->repl->nodes[0], (char *) "SET GLOBAL rpl_semi_sync_master_enabled = 0;");
sleep(10);
Test->repl->close_connections();
test_binlog(Test);
}
}
else
{
Test->add_result(1, "Can't connect to backend\n");
}
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,193 @@
#include "blob_test.h"
int test_longblob(TestConnections* Test, MYSQL * conn, char * blob_name, unsigned long chunk_size, int chunks,
int rows)
{
unsigned long size = chunk_size;
unsigned long * data;
unsigned long i, j;
MYSQL_BIND param[1];
char sql[256];
int global_res = Test->global_result;
//Test->tprintf("chunk size %lu chunks %d inserts %d\n", chunk_size, chunks, rows);
char *insert_stmt = (char *) "INSERT INTO long_blob_table(x, b) VALUES(1, ?)";
Test->tprintf("Creating table with %s\n", blob_name);
Test->try_query(conn, (char *) "DROP TABLE IF EXISTS long_blob_table");
sprintf(sql, "CREATE TABLE long_blob_table(id int NOT NULL AUTO_INCREMENT, x INT, b %s, PRIMARY KEY (id))",
blob_name);
Test->try_query(conn, sql);
for (int k = 0; k < rows; k++)
{
Test->tprintf("Preparintg INSERT stmt\n");
MYSQL_STMT * stmt = mysql_stmt_init(conn);
if (stmt == NULL)
{
Test->add_result(1, "stmt init error: %s\n", mysql_error(conn));
}
Test->add_result(mysql_stmt_prepare(stmt, insert_stmt, strlen(insert_stmt)), "Error preparing stmt: %s\n",
mysql_stmt_error(stmt));
param[0].buffer_type = MYSQL_TYPE_STRING;
param[0].is_null = 0;
Test->tprintf("Binding parameter\n");
Test->add_result(mysql_stmt_bind_param(stmt, param), "Error parameter binding: %s\n", mysql_stmt_error(stmt));
Test->tprintf("Filling buffer\n");
data = (unsigned long *) malloc(size * sizeof(long int));
if (data == NULL)
{
Test->add_result(1, "Memory allocation error\n");
}
Test->tprintf("Sending data in %d bytes chunks, total size is %d\n", size * sizeof(unsigned long),
(size * sizeof(unsigned long)) * chunks);
for (i = 0; i < chunks; i++)
{
for (j = 0; j < size; j++)
{
data[j] = j + i * size;
}
Test->set_timeout(300);
Test->tprintf("Chunk #%d\n", i);
if (mysql_stmt_send_long_data(stmt, 0, (char *) data, size * sizeof(unsigned long)) != 0)
{
Test->add_result(1, "Error inserting data, iteration %d, error %s\n", i, mysql_stmt_error(stmt));
return 1;
}
}
//for (int k = 0; k < rows; k++)
//{
Test->tprintf("Executing statement: %02d\n", k);
Test->set_timeout(3000);
Test->add_result(mysql_stmt_execute(stmt), "INSERT Statement with %s failed, error is %s\n", blob_name,
mysql_stmt_error(stmt));
//}
Test->add_result(mysql_stmt_close(stmt), "Error closing stmt\n");
}
if (global_res == Test->global_result)
{
Test->tprintf("%s is OK\n", blob_name);
}
else
{
Test->tprintf("%s FAILED\n", blob_name);
}
return 0;
}
int check_longblob_data(TestConnections* Test, MYSQL * conn, unsigned long chunk_size, int chunks,
int rows)
{
//char *select_stmt = (char *) "SELECT id, x, b FROM long_blob_table WHERE id = ?";
char *select_stmt = (char *) "SELECT id, x, b FROM long_blob_table ";
MYSQL_STMT * stmt = mysql_stmt_init(Test->conn_rwsplit);
if (stmt == NULL)
{
Test->add_result(1, "stmt init error: %s\n", mysql_error(Test->conn_rwsplit));
}
Test->add_result(mysql_stmt_prepare(stmt, select_stmt, strlen(select_stmt)), "Error preparing stmt: %s\n",
mysql_stmt_error(stmt));
MYSQL_BIND param[1], result[3];
int id = 1;
memset(param, 0, sizeof(param));
memset(result, 0, sizeof(result));
param[0].buffer_type = MYSQL_TYPE_LONG;
param[0].buffer = &id;
unsigned long * data = (unsigned long *) malloc(chunk_size * chunks * sizeof(long int));
int r_id;
int r_x;
unsigned long l_id;
unsigned long l_x;
my_bool b_id;
my_bool b_x;
my_bool e_id;
my_bool e_x;
result[0].buffer_type = MYSQL_TYPE_LONG;
result[0].buffer = &r_id;
result[0].buffer_length = 0;
result[0].length = &l_id;
result[0].is_null = &b_id;
result[0].error = &e_id;
result[1].buffer_type = MYSQL_TYPE_LONG;
result[1].buffer = &r_x;
result[1].buffer_length = 0;
result[1].length = &l_x;
result[1].is_null = &b_x;
result[1].error = &e_x;
result[2].buffer_type = MYSQL_TYPE_LONG_BLOB;
result[2].buffer = data;
result[2].buffer_length = chunk_size * chunks * sizeof(long int);
/*
if (mysql_stmt_bind_param(stmt, param) != 0)
{
printf("Could not bind parameters\n");
return 1;
}
*/
if (mysql_stmt_bind_result(stmt, result) != 0)
{
printf("Could not bind results\n");
return 1;
}
if (mysql_stmt_execute(stmt) != 0)
{
Test->tprintf("Error executing stmt %s\n", mysql_error(Test->conn_rwsplit));
}
if (mysql_stmt_store_result(stmt) != 0)
{
printf("Could not buffer result set\n");
return 1;
}
int row = 0;
while (!mysql_stmt_fetch(stmt))
{
Test->tprintf("id=%d\tx=%d\n", r_id, r_x);
if (r_id != row + 1)
{
Test->add_result(1, "id field is wrong! Expected %d, but it is %d\n", row + 1, r_id);
}
for (int y = 0; y < chunk_size * chunks; y++)
{
if (data[y] != y)
{
Test->add_result(1, "Data is wrong!\n");
}
//printf("y = %d \t%lu\tid=%d\tx=%d\n", y, data[y], r_id, r_x);
}
row++;
}
if (row != rows)
{
Test->add_result(1, "Wrong number of rows in the table! Expected %d, but it is %d\n", rows, row);
}
mysql_stmt_free_result(stmt);
mysql_stmt_close(stmt);
}

View File

@ -0,0 +1,32 @@
#ifndef BLOB_TEST_H
#define BLOB_TEST_H
#include "testconnections.h"
/**
* @brief test_longblob INSERT big amount of data into lobg_blob_table
* @param Test TestConnection object
* @param conn MYSQL connection handler
* @param blob_name blob type (LONGBLOB; MEDIUMBLOB or BLOB)
* @param chunk_size size of one data chunk (in sizeof(long usingned))
* @param chunks number of chunks to INSERT
* @param rows number of rows to INSERT (executes INSERT stetament 'rows' times)
* @return 0 in case of success
*/
int test_longblob(TestConnections* Test, MYSQL * conn, char * blob_name, unsigned long chunk_size, int chunks,
int rows);
/**
* @brief check_longblob_data Does SELECT against table created by test_longblob() and cheks that data are correct
* @param Test TestConnection object
* @param conn MYSQL connection handler
* @param chunk_size size of one data chunk (in sizeof(long usingned))
* @param chunks number of chunks in the table
* @param rows number of rows in the table
* @return 0 in case of success
*/
int check_longblob_data(TestConnections* Test, MYSQL * conn, unsigned long chunk_size, int chunks,
int rows);
#endif // BLOB_TEST_H

View File

@ -0,0 +1,68 @@
/**
* @file bug143.cpp bug143 regression case (MaxScale ignores host in user authentication)
*
* - create user@'non_existing_host1', user@'%', user@'non_existing_host2' identified by different passwords.
* - try to connect using RWSplit. First and third are expected to fail, second should succeed.
*/
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->tprintf("Creating user 'user' with 3 different passwords for different hosts\n");
Test->connect_maxscale();
execute_query(Test->conn_rwsplit, "CREATE USER 'user'@'non_existing_host1' IDENTIFIED BY 'pass1'");
execute_query(Test->conn_rwsplit, "CREATE USER 'user'@'%%' IDENTIFIED BY 'pass2'");
execute_query(Test->conn_rwsplit, "CREATE USER 'user'@'non_existing_host2' IDENTIFIED BY 'pass3'");
execute_query(Test->conn_rwsplit, "GRANT ALL PRIVILEGES ON *.* TO 'user'@'non_existing_host1'");
execute_query(Test->conn_rwsplit, "GRANT ALL PRIVILEGES ON *.* TO 'user'@'%%'");
execute_query(Test->conn_rwsplit, "GRANT ALL PRIVILEGES ON *.* TO 'user'@'non_existing_host2'");
Test->tprintf("Synchronizing slaves");
Test->set_timeout(50);
Test->repl->sync_slaves();
Test->tprintf("Trying first hostname, expecting failure");
Test->set_timeout(15);
MYSQL * conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "user", (char *) "pass1", Test->ssl);
if (mysql_errno(conn) == 0)
{
Test->add_result(1, "MaxScale ignores host in authentication\n");
}
if (conn != NULL)
{
mysql_close(conn);
}
Test->tprintf("Trying second hostname, expecting success");
Test->set_timeout(15);
conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "user", (char *) "pass2", Test->ssl);
Test->add_result(mysql_errno(conn), "MaxScale can't connect: %s\n", mysql_error(conn));
if (conn != NULL)
{
mysql_close(conn);
}
Test->tprintf("Trying third hostname, expecting failure");
Test->set_timeout(15);
conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "user", (char *) "pass3", Test->ssl);
if (mysql_errno(conn) == 0)
{
Test->add_result(1, "MaxScale ignores host in authentication\n");
}
if (conn != NULL)
{
mysql_close(conn);
}
execute_query(Test->conn_rwsplit, "DROP USER 'user'@'non_existing_host1'");
execute_query(Test->conn_rwsplit, "DROP USER 'user'@'%%'");
execute_query(Test->conn_rwsplit, "DROP USER 'user'@'non_existing_host2'");
Test->close_maxscale_connections();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,51 @@
/**
* @file bug359.cpp bug359 regression case (router_options in readwritesplit causes errors in error log)
*
* - Maxscale.cnf contains RWSplit router definition with router_option=slave.
* - error is expected in the log. Maxscale should not start.
*/
/*
Massimiliano 2013-11-22 09:45:13 UTC
Setting router_options=slave in readwritesplit causes:
in the error log
2013 11/22 10:35:43 Error : Couldn't find suitable Master from 3 candidates.
2013 11/22 10:35:43 Error : Failed to create router client session. Freeing allocated resources.
If no options are allowed here, it could be better to log this and/or unload the module
This is something could happen doing copy paste from readconnrouter as an example
Comment 1 Mark Riddoch 2014-02-05 11:35:57 UTC
I makes no sense for the read/write splitter to look at the slave and master router options.
Vilho Raatikka 2014-05-22 07:02:50 UTC
Added check for router option 'synced' which accepts only that, and warns the user of other unsupported options ('master'|'slave' for example). If router option is specified for read write split router, only a node in 'joined' state will be accepted as eligible backend candidate.
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->check_log_err((char *) "Unsupported router option \"slave\"", true);
Test->check_log_err((char *) "Failed to start all MaxScale services. Exiting", true);
Test->check_log_err((char *) "Couldn't find suitable Master", false);
//Test->check_maxscale_alive();
Test->check_maxscale_processes(0);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,122 @@
/**
* @file bug422.cpp bug422 regression case ( Executing '\s' doesn't always produce complete result set)
*
* Test executes "show status" 1000 times against all Maxscale services and checks Maxscale is alive after it.
*/
/*
Vilho Raatikka 2014-04-15 07:03:03 UTC
Read/write split router
-------------------------
Login to MaxScale & read/write split router, for example
mysql --host=127.0.0.1 -P 4006 -u maxuser -pmaxpwd
Complete result :
MySQL [(none)]> \s
--------------
mysql Ver 15.1 Distrib 5.5.33-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 4051
Current database:
Current user: maxuser@localhost
SSL: Not in use
Current pager: less
Using outfile: ''
Using delimiter: ;
Server: MySQL
Server version: MaxScale 0.5.0 Source distribution
Protocol version: 10
Connection: 127.0.0.1 via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: latin1
Conn. characterset: latin1
TCP port: 4006
Uptime: 34 min 23 sec
Threads: 5 Questions: 206 Slow queries: 0 Opens: 0 Flush tables: 2 Open tables: 26 Queries per second avg: 0.099
--------------
By running same a few time in a row, an incomplete result set arrives, like the following:
MySQL [(none)]> \s
--------------
mysql Ver 15.1 Distrib 5.5.33-MariaDB, for Linux (x86_64) using readline 5.1
Connection id: 4051
Current database:
Current user: maxuser@localhost
SSL: Not in use
Current pager: less
Using outfile: ''
Using delimiter: ;
Server: MySQL
Server version: MaxScale 0.5.0 Source distribution
Protocol version: 10
Connection: 127.0.0.1 via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: latin1
Conn. characterset: latin1
TCP port: 4006
--------------
MySQL [(none)]>
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
int i;
int iterations = 1000;
if (Test->smoke)
{
iterations = 100;
}
Test->set_timeout(10);
Test->tprintf("Connecting to all MaxScale services\n");
Test->add_result(Test->connect_maxscale(), "Can not connect to Maxscale\n");
Test->tprintf("executing show status %d times\n", iterations);
for (i = 0; i < iterations; i++)
{
Test->set_timeout(5);
Test->add_result(execute_query(Test->conn_rwsplit, (char *) "show status"),
"Query %d agains RWSplit failed\n", i);
}
for (i = 0; i < iterations; i++)
{
Test->set_timeout(5);
Test->add_result(execute_query(Test->conn_slave, (char *) "show status"),
"Query %d agains ReadConn Slave failed\n", i);
}
for (i = 0; i < iterations; i++)
{
Test->set_timeout(5);
Test->add_result(execute_query(Test->conn_master, (char *) "show status"),
"Query %d agains ReadConn Master failed\n", i);
}
Test->set_timeout(10);
Test->close_maxscale_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,71 @@
/**
* @file bug448.cpp bug448 regression case ("Wildcard in host column of mysql.user table don't work properly")
*
* Test creates user1@xxx.%.%.% and tries to use it to connect
*/
#include <iostream>
#include "testconnections.h"
#include "get_my_ip.h"
int main(int argc, char *argv[])
{
char my_ip[1024];
char my_ip_db[1024];
char sql[1024];
char * first_dot;
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(20);
Test->repl->connect();
get_my_ip(Test->maxscale_IP, my_ip);
Test->tprintf("Test machine IP (got via network request) %s\n", my_ip);
Test->add_result(Test->get_client_ip(my_ip_db), "Unable to get IP using connection to DB\n");
Test->tprintf("Test machine IP (got via Show processlist) %s\n", my_ip);
first_dot = strstr(my_ip, ".");
strcpy(first_dot, ".%.%.%");
Test->tprintf("Test machine IP with %% %s\n", my_ip);
Test->tprintf("Connecting to Maxscale\n");
Test->add_result(Test->connect_maxscale(), "Error connecting to Maxscale\n");
Test->tprintf("Creating user 'user1' for %s host\n", my_ip);
Test->set_timeout(30);
Test->add_result(execute_query(Test->conn_rwsplit, "CREATE USER user1@'%s';", my_ip),
"Failed to create user");
Test->add_result(execute_query(Test->conn_rwsplit,
"GRANT ALL PRIVILEGES ON *.* TO user1@'%s' identified by 'pass1'; FLUSH PRIVILEGES;", my_ip),
"Failed to grant privileges.");
Test->tprintf("Trying to open connection using user1\n");
MYSQL * conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "user1", (char *) "pass1",
Test->ssl);
if (mysql_errno(conn) != 0)
{
Test->add_result(1, "TEST_FAILED! Authentification failed! error: %s\n", mysql_error(conn));
}
else
{
Test->tprintf("Authentification for user@'%s' is ok", my_ip);
if (conn != NULL)
{
mysql_close(conn);
}
}
Test->add_result(execute_query(Test->conn_rwsplit, "DROP USER user1@'%s'; FLUSH PRIVILEGES;", my_ip),
"Query Failed\n");
Test->close_maxscale_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,34 @@
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
int global_result = 0;
Test->ReadEnv();
Test->PrintIP();
Test->ConnectMaxscale();
execute_query(Test->conn_rwsplit, (char *) "select @@server_id; -- max_slave_replication_lag=120");
Test->CloseMaxscaleConn();
global_result += CheckMaxscaleAlive();
Test->Copy_all_logs();
return global_result;
}

View File

@ -0,0 +1,89 @@
/**
* @file bug469 bug469 regression test case ("rwsplit counts every connection twice in master - counnection counts leak")
* - use maxadmin command "show server server1" and check "Current no. of conns" and "Number of connections" - both should be 0
* - execute simple query against RWSplit
* - use maxadmin command "show server server1" and check "Current no. of conns" (should be 0) and "Number of connections" (should be 1)
*/
/*
Vilho Raatikka 2014-08-05 12:28:21 UTC
Every connection is counted twice in master and decremented only once. As a result master seems always to have active connections after first connection is established.
Server 0x21706e0 (server1)
Server: 127.0.0.1
Status: Master, Running
Protocol: MySQLBackend
Port: 3000
Server Version: 5.5.37-MariaDB-debug-log
Node Id: 3000
Master Id: -1
Slave Ids: 3001, 3002 , 3003
Repl Depth: 0
Number of connections: 6
Current no. of conns: 3
Current no. of operations: 0
Server 0x21705e0 (server2)
Server: 127.0.0.1
Status: Slave, Running
Protocol: MySQLBackend
Port: 3001
Server Version: 5.5.37-MariaDB-debug-log
Node Id: 3001
Master Id: 3000
Slave Ids:
Repl Depth: 1
Number of connections: 3
Current no. of conns: 0
Current no. of operations: 0
*/
#include <iostream>
#include "testconnections.h"
#include "maxadmin_operations.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
char res[1024];
int res_d;
Test->set_timeout(10);
Test->get_maxadmin_param((char *) "show server server1", (char *) "Current no. of conns:", res);
sscanf(res, "%d", &res_d);
Test->tprintf("Before: Current num of conn %d\n", res_d);
Test->add_result(res_d, "curr num of conn is not 0\n");
Test->get_maxadmin_param((char *) "show server server1", (char *) "Number of connections:", res);
sscanf(res, "%d", &res_d);
Test->tprintf("Before: num of conn %d\n", res_d);
Test->add_result(res_d, "num of conn is not 0");
Test->connect_rwsplit();
Test->try_query(Test->conn_rwsplit, (char *) "select 1");
Test->close_rwsplit();
Test->stop_timeout();
sleep(10);
Test->set_timeout(10);
Test->get_maxadmin_param((char *) "show server server1", (char *) "Current no. of conns:", res);
sscanf(res, "%d", &res_d);
Test->tprintf("After: Current num of conn %d\n", res_d);
Test->add_result(res_d, "curr num of conn is not 0\n");
Test->get_maxadmin_param((char *) "show server server1", (char *) "Number of connections:", res);
sscanf(res, "%d", &res_d);
Test->tprintf("After: num of conn %d\n", res_d);
if (res_d != 1)
{
Test->add_result(1, "num of conn is not 1");
}
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,193 @@
/**
* @file bug471.cpp bug471 regression case ( Routing Hints route to server sometimes doesn't work )
*
* - try "select @@server_id; -- maxscale route to server server%d" (where %d - server number) and compares result
* with "select @@server_id;" sent directly to backend node.
* - do it 25 times.
*/
/*
Massimiliano 2014-08-06 13:27:05 UTC
I found using basic routing hints such as:
select @@server_id; -- maxscale route to server server4
select @@server_id; -- maxscale route to server server3
select @@server_id; -- maxscale route to server server2
server3 is the current master
and server4 server_id is 4
server3 server_id is 3
server2 server_id is 2
sometimes I cannot get the expected results that are:
4
3
2
Sometimes I got:
2
3
2
or
4
3
4
In maxScale configuration 5 servers defined:
server1 is not monitored but listed in [RW Split Service]
server5 is always stopped
MaxScale configuration:
[gateway]
threads=4
[RW Split Service]
#Please note server1 is not monitored n MySQL Monitor section
type=service
router=readwritesplit
servers=server1,server2,server3,server5,server4
max_slave_connections=100%
max_slave_replication_lag=21
user=massi
passwd=massi
enable_root_user=0
filters=Hint
# Definition of the servers
[server1]
#not monitored
type=server
address=127.0.0.1
port=3306
protocol=MySQLBackend
[server2]
type=server
address=127.0.0.1
port=3307
protocol=MySQLBackend
[server3]
type=server
address=127.0.0.1
port=3308
protocol=MySQLBackend
[server4]
type=server
address=127.0.0.1
port=3309
protocol=MySQLBackend
[server5]
#always stopped
type=server
address=127.0.0.1
port=3310
protocol=MySQLBackend
[RW Split Listener]
type=listener
service=RW Split Service
protocol=MySQLClient
port=4606
[Hint]
type=filter
module=hintfilter
[MySQL Monitor]
# Please note server1 is not monitored
type=monitor
module=mysqlmon
servers=server4,server2,server3,server5
user=massi
passwd=massi
detect_replication_lag=1
monitor_interval=10001
Removing server1 from the service section gives right results for server_id selection
# mysql -c -h 127.0.0.1 -P 4606 -umassi -pmassi
MariaDB> select @@server_id; -- maxscale route to server server4
Please not -c option that allows comments to be sent
Vilho Raatikka 2014-08-08 08:13:42 UTC
After further consideration we decided that the behavior is invalid. Routing hints should be followed if they don't violate database consistency nor cluster setup.
Comment 11 Vilho Raatikka 2014-08-08 17:26:25 UTC
Pushed fix in commit d4de582e1622908cc95396f57878f8691289c35b to Z2.
Replication lag is not checked if routing hint is used.
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->repl->connect();
Test->add_result(Test->connect_maxscale(), "Failed to connect to MaxScale\n");
char server_id[256];
char server_id_d[256];
char hint_sql[64];
for (int i = 1; i < 25; i++)
{
for (int j = 0; j < Test->repl->N; j++)
{
if (j != 1 )
{
Test->set_timeout(5);
sprintf(hint_sql, "select @@server_id; -- maxscale route to server server%d", j + 1);
find_field(Test->conn_rwsplit, hint_sql, (char *) "@@server_id", &server_id[0]);
find_field(Test->repl->nodes[j], (char *) "select @@server_id;", (char *) "@@server_id", &server_id_d[0]);
Test->tprintf("server%d ID from Maxscale: \t%s\n", j + 1, server_id);
Test->tprintf("server%d ID directly from node: \t%s\n", j + 1, server_id_d);
Test->add_result(strcmp(server_id, server_id_d), "Hints does not work!\n");
}
}
}
Test->set_timeout(10);
Test->close_maxscale_connections();
Test->repl->close_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,98 @@
/**
* @file bug473.cpp bug470, 472, 473 regression cases ( malformed hints cause crash )
*
* Test tries different hints with syntax errors (see source for details)
*/
/*
Markus Mäkelä 2014-08-07 09:21:44 UTC
All of the following queries cause a segmentation fault:
select @@server_id; -- maxscale route to server =(
select @@server_id; -- maxscale route to server =)
select @@server_id; -- maxscale route to server =:
select @@server_id; -- maxscale route to server =a
select @@server_id; -- maxscale route to server = a
Most likely all variatios with the equals sign and a character after it cause the crash.
Call stack:
#0 __strncasecmp_l_sse2 () at ../sysdeps/x86_64/strcmp.S:209
#1 0x00007fffdd0e9d0d in get_route_target (qtype=QUERY_TYPE_READ, trx_active=false, hint=0x74b830) at readwritesplit.c:1116
#2 0x00007fffdd0ea494 in routeQuery (instance=0x72f960, router_session=0x73dbf0, querybuf=0x74b7a0) at readwritesplit.c:1346
#3 0x00007fffd7191ed8 in routeQuery (instance=0x74b670, session=0x74b6b0, queue=0x74b7a0) at hintfilter.c:236
#4 0x00007fffdc2a0b3d in route_by_statement (session=0x744ae0, readbuf=0x0) at mysql_client.c:1442
#5 0x00007fffdc29f22c in gw_read_client_event (dcb=0x7446b0) at mysql_client.c:786
#6 0x00000000004165da in poll_waitevents (arg=0x0) at poll.c:424
#7 0x000000000040a72c in main (argc=4, argv=0x7fffffffe2e8) at gateway.c:1379
Failing point:
1114 else if (hint->type == HINT_PARAMETER)
1115 {
1116 if (strncasecmp(
1117 (char *)hint->data,
1118 "max_slave_replication_lag",
1119 strlen("max_slave_replication_lag")) == 0)
1120 {
Value of hint:
$6 = {type = HINT_PARAMETER, data = 0x0, value = 0x743a60, dsize = 0, next = 0x0}
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->add_result(Test->connect_maxscale(), "Can not connect to Maxscale\n");
Test->tprintf("Trying queries that caused crashes before fix: bug473\n");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale route to server =(");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale route to server =)");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale route to server =:");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale route to server =a");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale route to server = a");
Test->try_query(Test->conn_rwsplit,
(char *) "select @@server_id; -- maxscale route to server = кириллица åäö");
// bug472
Test->tprintf("Trying queries that caused crashes before fix: bug472\n");
Test->try_query(Test->conn_rwsplit,
(char *) "select @@server_id; -- maxscale s1 begin route to server server3");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale end");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale s1 begin");
// bug470
Test->tprintf("Trying queries that caused crashes before fix: bug470\n");
fflush(stdout);
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id; -- maxscale named begin route to master");
Test->try_query(Test->conn_rwsplit, (char *) "select @@server_id;");
Test->try_query(Test->conn_rwsplit,
(char *) "select @@server_id; -- maxscale named begin route to master; select @@server_id;");
Test->close_maxscale_connections();
Test->tprintf("Checking if Maxscale is alive\n");
fflush(stdout);
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,51 @@
/**
* @file bug475.cpp regression case for bug 475 (The end comment tag in hints isn't properly detected)
*
* Test tries different hints with comments syntax and then checks log and checks if MaxScale is alive
*/
//
//Markus Mäkelä 2014-08-08 10:09:48 UTC
//The closing tag isn't properly detected when using inline comments.
//Multiple commands cause this behaviour. The following commands cause these messages in the error log:
//select /* maxscale hintname prepare route to master */ @@server_id;
//2014 08/08 13:01:09 Error : Syntax error in hint. Expected 'master', 'slave', or 'server' instead of '*/'. Hint ignored.
//select /* maxscale hintname begin */ @@server_id;
//2014 08/08 13:02:45 Error : Syntax error in hint. Expected '=', 'prepare', or 'start' instead of '@@server_id'. Hint ignored.
//The following only happens when no whitespace is used after 'master' and '*/':
//select /* maxscale route to master*/ @@server_id;
//2014 08/08 13:04:38 Error : Syntax error in hint. Expected 'master', 'slave', or 'server' instead of 'master*/'. Hint ignored.
//All other forms of '/* maxscale route to [slave|server <server name>]*/' work even without the whitespace before the closing tag.
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->connect_maxscale();
Test->try_query(Test->conn_rwsplit,
(char *) "select /* maxscale hintname prepare route to master */ @@server_id;");
Test->try_query(Test->conn_rwsplit, (char *) "select /* maxscale hintname begin */ @@server_id;");
Test->try_query(Test->conn_rwsplit, (char *) "select /* maxscale route to master*/ @@server_id;");
Test->check_log_err((char *) "Syntax error in hint", false);
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,35 @@
/**
* @file bug479.cpp regression case for bug 479 ( Undefined filter reference in MaxScale.cnf causes a crash)
*
* - Maxscale.cnf with "filters=non existing filter | не существуюший фильтер", cheks error log for warnings and
* - check if Maxscale is alive
*/
/*
Markus Mäkelä 2014-08-15 17:38:06 UTC
Undefined filters in services cause a crash when the service is accessed.
How to reproduce:
Define a service with a filter not defined in the MaxScale.cnf file, start MaxScale and access the service.
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->check_log_err((char *) "Unable to find filter 'non existing filter", true);
//global_result =Test->check_log_err((char *) "не существуюший фильтер", true);
//global_result +=Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,125 @@
/**
* @file bug488.cpp regression case for bug 488 ("SHOW VARIABLES randomly failing with "Lost connection to MySQL server")
*
* - try "SHOW VARIABLES;" 100 times against all Maxscale services
* First round: 100 iterations for RWSplit, then ReadConn Master, then ReadConn Slave
* Second round: 100 iteration and in every iterations all three Maxscale services are in use.
* - check if Maxscale is alive.
*/
/*
Kolbe Kegel 2014-08-27 18:37:14 UTC
Created attachment 138 [details]
good.txt and bad.txt
Sending "SHOW VARIABLES" to MaxScale seems to sometimes result in "ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query". It appears to be random. It seems to be sending the query to the same backend server, so I'm not sure what is happening. I'm including the debug log for both the "good" and "bad" queries.
Comment 1 Vilho Raatikka 2014-08-27 18:41:25 UTC
Seems to happen exactly every second time with rwsplit router. Didn't experience it with read connection router.
Comment 2 Kolbe Kegel 2014-08-27 18:47:13 UTC
Not exactly every 2nd time.
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
$ mysql -h max1 -P 4006 -u maxuser -pmaxpwd -e 'show variables' >/dev/null
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
Comment 3 Vilho Raatikka 2014-08-28 10:48:39 UTC
SHOW VARIABLES is session write command - which is unnecessary because those could be read from any server - and what causes client to return 'lost connection' message to the user is duplicated response packet from MaxScale to the client.
SHOW VARIABLES response should start like this:
T 127.0.0.1:59776 -> 127.0.0.1:4006 [AP]
0f 00 00 00 03 73 68 6f 77 20 76 61 72 69 61 62 .....show variab
6c 65 73 les
T 127.0.0.1:4006 -> 127.0.0.1:59776 [AP]
01 00 00 01 02 .....
T 127.0.0.1:4006 -> 127.0.0.1:59776 [AP]
54 00 00 02 03 64 65 66 12 69 6e 66 6f 72 6d 61 T....def.informa
74 69 6f 6e 5f 73 63 68 65 6d 61 09 56 41 52 49 tion_schema.VARI
41 42 4c 45 53 09 56 41 52 49 41 42 4c 45 53 0d ABLES.VARIABLES.
56 61 72 69 61 62 6c 65 5f 6e 61 6d 65 0d 56 41 Variable_name.VA
52 49 41 42 4c 45 5f 4e 41 4d 45 0c 08 00 40 00 RIABLE_NAME...@.
00 00 fd 01 00 00 00 00 ........
While in the failing case the initial packet is followed something like this:
T 127.0.0.1:59776 -> 127.0.0.1:4006 [AP]
0f 00 00 00 03 73 68 6f 77 20 76 61 72 69 61 62 .....show variab
6c 65 73 les
T 127.0.0.1:4006 -> 127.0.0.1:59776 [AP]
1d 00 00 d5 18 69 6e 6e 6f 64 62 5f 75 73 65 5f .....innodb_use_
61 74 6f 6d 69 63 5f 77 72 69 74 65 73 03 4f 46 atomic_writes.OF
46 F
T 127.0.0.1:4006 -> 127.0.0.1:59776 [AP]
19 00 00 d6 14 69 6e 6e 6f 64 62 5f 75 73 65 5f .....innodb_use_
66 61 6c 6c 6f 63 61 74 65 03 4f 46 46 fallocate.OFF
- where those innodb related packets are duplicates from the previous response.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
int i;
Test->repl->connect();
Test->connect_maxscale();
Test->tprintf("Trying SHOW VARIABLES to different Maxscale services\n");
fflush(stdout);
Test->tprintf("RWSplit\n");
for (i = 0; i < 100; i++)
{
Test->set_timeout(5);
Test->try_query(Test->conn_rwsplit, (char *) "SHOW VARIABLES;");
}
Test->tprintf("ReadConn master\n");
for (i = 0; i < 100; i++)
{
Test->set_timeout(5);
Test->try_query(Test->conn_master, (char *) "SHOW VARIABLES;");
}
Test->tprintf("ReadConn slave\n");
for (i = 0; i < 100; i++)
{
Test->set_timeout(5);
Test->try_query(Test->conn_slave, (char *) "SHOW VARIABLES;");
}
Test->tprintf("All in one loop\n");
for (i = 0; i < 100; i++)
{
Test->set_timeout(5);
Test->try_query(Test->conn_rwsplit, (char *) "SHOW VARIABLES;");
Test->try_query(Test->conn_master, (char *) "SHOW VARIABLES;");
Test->try_query(Test->conn_slave, (char *) "SHOW VARIABLES;");
}
Test->set_timeout(10);
Test->close_maxscale_connections();
Test->repl->close_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,90 @@
/**
* @file bug493.cpp regression case for bug 493 ( Can have same section name multiple times without warning)
*
* - Maxscale.cnf in which 'server2' is defined twice and tests checks error log for proper error message.
* - check if Maxscale is alive
*/
/*
Hartmut Holzgraefe 2014-08-31 21:01:06 UTC
Due to a copy/paste error I ended up with two [server2] sections instead of having [server2] and [server3].
There were no error or warning messages about this in skygw_err1.log or skygw_msg1.log but only the second [server2] was actually used.
Configuration file:
---8<------------------
[maxscale]
threads=1
[CLI]
type=service
router=cli
[CLI Listener]
type=listener
service=CLI
protocol=maxscaled
address=localhost
port=6603
[server1]
type=server
address=127.0.0.1
port=3000
protocol=MySQLBackend
[server2]
type=server
address=127.0.0.1
port=3001
protocol=MySQLBackend
[server2]
type=server
address=127.0.0.1
port=3002
protocol=MySQLBackend
-------->8---
maxadmin results:
---8<--------------------
MaxScale> list servers
Servers.
-------------------+-----------------+-------+----------------------+------------
Server | Address | Port | Status | Connections
-------------------+-----------------+-------+----------------------+------------
server1 | 127.0.0.1 | 3000 | Running | 0
server2 | 127.0.0.1 | 3002 | Running | 0
-------------------+-----------------+-------+----------------------+------------
------------->8---
So no entry for the first (actually correct) [server2] on port 3001,
but only for the duplicate 2nd [server2] with port set to 3002 ...
Comment 1 Mark Riddoch 2014-09-01 16:17:51 UTC
The ini file parser we use allows multiple sections with the same name and will combine the section contains. Within this restriction we now have added code that will detect the same parameter being set twice and will warn the user.
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->check_log_err((char *) "Duplicate section found: server2", true);
Test->check_log_err((char *)
"Failed to open, read or process the MaxScale configuration file /etc/maxscale.cnf. Exiting", true);
//Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,43 @@
/**
* @file bug495.cpp regression case for bug 495 ( Referring to a nonexisting server in servers=... doesn't even raise a warning )
*
* - Maxscale.cnf with "servers= server1, server2,server3 ,server4,server5"
* but 'server5' is not defined. Test checks error log for proper error message.
* - check if Maxscale is alive
*/
/*
Description Hartmut Holzgraefe 2014-08-31 21:32:09 UTC
Only [server1] and [server2] are defined,
service [test_service] and monitor [MySQL monitor]
refer to a third server "server3" in their servers=...
list though ...
Nothing in the err or msg log hints towards a problem ...
(which originally was caused by a copy/paste error that
also lead to the "duplicate section name" error reported
earlier ... and which would have been easy to track down
if either of these problems would at least have raised a
warning - took me almost an hour to track down the actual
problem ... :(
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->check_log_err((char *) "Unable to find server", true);
Test->check_log_err((char *) "errors were encountered while processing the configuration", true);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,126 @@
/**
* @file bug507.cpp regression case for bug 507 ( "rw-split router does not send last_insert_id() to master" )
*
* - "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));",
* - do INSERT using RWsplit
* - do "select last_insert_id(), @@server_id" using RWSplit and directly to Master, compare @@server_id
*
*/
/*
Kolbe Kegel 2014-09-01 14:45:56 UTC
After inserting a row via the rw-split router, a call to last_insert_id() can go to a slave, producing bad results.
mariadb> select * from t1;
+----+
| id |
+----+
| 1 |
| 4 |
+----+
2 rows in set (0.00 sec)
mariadb> insert into t1 values ();
Query OK, 1 row affected (0.00 sec)
mariadb> select * from t1;
+----+
| id |
+----+
| 1 |
| 4 |
| 7 |
+----+
3 rows in set (0.00 sec)
mariadb> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 0 |
+------------------+
1 row in set (0.00 sec)
mariadb> select @@wsrep_node_address, last_insert_id();
+----------------------+------------------+
| @@wsrep_node_address | last_insert_id() |
+----------------------+------------------+
| 192.168.30.31 | 7 |
+----------------------+------------------+
1 row in set (0.00 sec)
Comment 1 Vilho Raatikka 2014-09-01 17:51:45 UTC
last_inserted_id() belongs to UNKNOWN_FUNC class to which many read-only system functions belong too. Thus last_inserted_id() was routed to any slave.
Unfortunately I can't confirm wrong behavior since running the same sequence generates same output when connected directly to MariaDB backend. Perhaps there is something required for the table t1 which is not included here?
Comment 2 Vilho Raatikka 2014-09-01 20:01:35 UTC
An autoincrement attribute was missing.
*/
#include <iostream>
#include "testconnections.h"
const char * sel1 = "select last_insert_id(), @@server_id";
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->repl->connect();
Test->connect_maxscale();
if (Test->repl->N < 3)
{
Test->tprintf("There is not enoght nodes for test\n");
delete Test;
exit(1);
}
Test->tprintf("Creating table\n");
fflush(stdout);
Test->try_query(Test->conn_rwsplit, (char *) "DROP TABLE IF EXISTS t2");
Test->try_query(Test->conn_rwsplit,
(char *) "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));");
Test->tprintf("Doing INSERTs\n");
fflush(stdout);
Test->try_query(Test->conn_rwsplit, (char *) "insert into t2 (x) values (1);");
Test->stop_timeout();
Test->repl->sync_slaves();
Test->set_timeout(20);
Test->tprintf("Trying \n");
char last_insert_id1[1024];
char last_insert_id2[1024];
if ( (
find_field(
Test->conn_rwsplit, sel1,
"@@server_id", &last_insert_id1[0])
!= 0 ) || (
find_field(
Test->repl->nodes[0], sel1,
"@@server_id", &last_insert_id2[0])
!= 0 ))
{
Test->tprintf("@@server_id fied not found!!\n");
delete Test;
exit(1);
}
else
{
Test->tprintf("'%s' to RWSplit gave @@server_id %s\n", sel1, last_insert_id1);
Test->tprintf("'%s' directly to master gave @@server_id %s\n", sel1, last_insert_id2);
Test->add_result(strcmp(last_insert_id1, last_insert_id2),
"last_insert_id() are different depending in which order terms are in SELECT\n");
}
Test->close_maxscale_connections();
Test->repl->close_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,144 @@
/**
* @file bug509.cpp regression case for bug 509 and 507 ( "Referring to a nonexisting server in servers=... doesn't even raise a warning"
* and "rw-split router does not send last_insert_id() to master" )
*
* - "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));",
* - do a number of INSERTs first using RWsplit, then directly Galera nodes.
* - do "select @@wsrep_node_address, last_insert_id();" and "select last_insert_id(), @@wsrep_node_address;" and compares results.
* - do "insert into t2 (x) values (i);" 1000 times and compares results of
* "select @@wsrep_node_address, last_insert_id();" and "select last_insert_id(), @@wsrep_node_address;"
*
* Test fails if results are different (after 5 seconds of waiting after last INSERT)
*/
/*
Kolbe Kegel 2014-09-01 14:48:12 UTC
For some reason, the order of terms in the field list of a SELECT statement influences how the rw-split router decides where to send a statement.
mariadb> select @@wsrep_node_address, last_insert_id();
+----------------------+------------------+
| @@wsrep_node_address | last_insert_id() |
+----------------------+------------------+
| 192.168.30.31 | 7 |
+----------------------+------------------+
1 row in set (0.00 sec)
mariadb> select last_insert_id(), @@wsrep_node_address;
+------------------+----------------------+
| last_insert_id() | @@wsrep_node_address |
+------------------+----------------------+
| 0 | 192.168.30.33 |
+------------------+----------------------+
1 row in set (0.00 sec)
Comment 1 Vilho Raatikka 2014-09-03 20:44:17 UTC
Added code to detect last_insert_id() function and now both types of elements are routed to master and their order of appearance doesn't matter.
*/
#include <iostream>
#include "testconnections.h"
const char * sel1 = "select @@wsrep_node_address, last_insert_id();";
const char * sel2 = "select last_insert_id(), @@wsrep_node_address;";
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(60);
Test->galera->connect();
Test->connect_maxscale();
if (Test->galera->N < 3)
{
Test->tprintf("There is not enoght nodes for test\n");
delete Test;
exit(1);
}
Test->tprintf("Creating table\n");
Test->try_query(Test->conn_rwsplit, (char *) "DROP TABLE IF EXISTS t2;");
Test->try_query(Test->conn_rwsplit,
(char *) "CREATE TABLE t2 (id INT(10) NOT NULL AUTO_INCREMENT, x int, PRIMARY KEY (id));");
Test->tprintf("Doing INSERTs\n");
Test->try_query(Test->conn_rwsplit, (char *) "insert into t2 (x) values (1);");
Test->try_query(Test->galera->nodes[0], (char *) "insert into t2 (x) values (2);");
Test->try_query(Test->galera->nodes[0], (char *) "insert into t2 (x) values (3);");
Test->try_query(Test->galera->nodes[1], (char *) "insert into t2 (x) values (4);");
Test->try_query(Test->galera->nodes[1], (char *) "insert into t2 (x) values (5);");
Test->try_query(Test->galera->nodes[1], (char *) "insert into t2 (x) values (6);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (7);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (8);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (9);");
Test->try_query(Test->galera->nodes[2], (char *) "insert into t2 (x) values (10);");
Test->stop_timeout();
Test->repl->sync_slaves();
Test->tprintf("Trying \n");
char last_insert_id1[1024];
char last_insert_id2[1024];
if ( (
find_field(
Test->conn_rwsplit, sel1,
"last_insert_id()", &last_insert_id1[0])
!= 0 ) || (
find_field(
Test->conn_rwsplit, sel2,
"last_insert_id()", &last_insert_id2[0])
!= 0 ))
{
Test->tprintf("last_insert_id() fied not found!!\n");
delete Test;
exit(1);
}
else
{
Test->tprintf("'%s' gave last_insert_id() %s\n", sel1, last_insert_id1);
Test->tprintf("'%s' gave last_insert_id() %s\n", sel2, last_insert_id2);
Test->add_result(strcmp(last_insert_id1, last_insert_id2),
"last_insert_id() are different depending in which order terms are in SELECT\n");
}
char id_str[1024];
char str1[1024];
int iterations = 150;
for (int i = 100; i < iterations; i++)
{
Test->set_timeout(50);
Test->add_result(execute_query(Test->conn_rwsplit, "insert into t2 (x) values (%d);", i), "Query failed");
sprintf(str1, "select * from t2 where x=%d;", i);
find_field(Test->conn_rwsplit, sel1, "last_insert_id()", &last_insert_id1[0]);
find_field(Test->conn_rwsplit, str1, "id", &id_str[0]);
int n = 0;
while (strcmp(last_insert_id1, id_str) != 0 && n < 5)
{
Test->tprintf("Replication is lagging");
sleep(1);
find_field(Test->conn_rwsplit, str1, "id", &id_str[0]);
n++;
}
Test->add_result(strcmp(last_insert_id1, id_str),
"last_insert_id is not equal to id even after waiting 5 seconds");
if (i % 10 == 0)
{
Test->tprintf("last_insert_id is %s, id is %s", last_insert_id1, id_str);
}
}
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,152 @@
/**
* @file bug519.cpp - Jira task is MAX-345
* - fill t1 with data
* - execute SELECT * INTO OUTFILE '/tmp/t1.csv' FROM t1; against all routers
* - DROP TABLE t1
* - LOAD DATA LOCAL INFILE 't1.csv' INTO TABLE t1; using RWSplit
* - check if t1 contains right data
* - DROP t1 again and repeat LOAD DATA LOCAL INFILE 't1.csv' INTO TABLE t1; using ReadConn master
*/
/*
It seems that LOAD DATA LOCAL INFILE is not handled by readwritesplit? Maybe it's a bigger problem elsewhere in MaxScale?
I can execute the command, it looks like it is getting sent to the master, but ... no data is actually loaded. Does/can MaxScale handle LOAD DATA LOCAL INFILE?
Comment 1 Kolbe Kegel 2014-09-03 02:39:47 UTC
The LOAD DATA LOCAL INFILE statement is stuck in "Reading from net" until some timeout is hit:
| 22 | maxuser | 192.168.30.38:59996 | test | Query | 10 | Reading from net | load data local infile '/Users/kolbe/Devel/seattleparking/Street_Parking_Signs.csv' into table parki | 0.000 |
The client never sees the statement end, though, even after the server has long ago killed its connection...
When I start a *new* connection to MaxScale and I try to execute the LOAD DATA LOCAL INFILE statement again, I have some problems:
mysql 5.5.38-MariaDB (maxuser) [test]> source /Users/kolbe/Devel/seattleparking/loaddata.sql
ERROR 2013 (HY000) at line 1 in file: '/Users/kolbe/Devel/seattleparking/loaddata.sql': Lost connection to MySQL server during query
mysql 5.5.38-MariaDB (maxuser) [test]> select @@wsrep_node_address;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 1709
Current database: test
+----------------------+
| @@wsrep_node_address |
+----------------------+
| 192.168.30.32 |
+----------------------+
1 row in set (0.01 sec)
mysql 5.5.38-MariaDB (maxuser) [test]> source /Users/kolbe/Devel/seattleparking/loaddata.sql
ERROR 2013 (HY000) at line 1 in file: '/Users/kolbe/Devel/seattleparking/loaddata.sql': Lost connection to MySQL server during query
mysql 5.5.38-MariaDB (maxuser) [test]> select @@wsrep_node_address;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 1709
Current database: test
+----------------------+
| @@wsrep_node_address |
+----------------------+
| 192.168.30.32 |
+----------------------+
1 row in set (0.01 sec)
mysql 5.5.38-MariaDB (maxuser) [test]> source /Users/kolbe/Devel/seattleparking/loaddata.sql
ERROR 2013 (HY000) at line 1 in file: '/Users/kolbe/Devel/seattleparking/loaddata.sql': Lost connection to MySQL server during query
mysql 5.5.38-MariaDB (maxuser) [test]> Bye
*/
#include <iostream>
#include "testconnections.h"
#include "sql_t1.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
int N = 4;
int iterations = 2;
if (Test->smoke)
{
iterations = 1;
}
char str[1024];
Test->set_timeout(10);
Test->connect_maxscale();
Test->repl->connect();
Test->tprintf("Create t1\n");
create_t1(Test->conn_rwsplit);
Test->tprintf("Insert data into t1\n");
Test->set_timeout(60);
insert_into_t1(Test->conn_rwsplit, N);
Test->stop_timeout();
Test->repl->sync_slaves();
Test->set_timeout(200);
sprintf(str, "%s rm -f /tmp/t*.csv; %s chmod 777 /tmp", Test->repl->access_sudo[0],
Test->repl->access_sudo[0]);
Test->tprintf("%s\n", str);
for (int k = 0; k < Test->repl->N; k++)
{
Test->repl->ssh_node(k, str, false);
}
//system(str);
Test->tprintf("Copying data from t1 to file...\n");
Test->tprintf("using RWSplit: SELECT * INTO OUTFILE '/tmp/t1.csv' FROM t1;\n");
Test->try_query(Test->conn_rwsplit, (char *) "SELECT * INTO OUTFILE '/tmp/t1.csv' FROM t1;");
Test->tprintf("using ReadConn master: SELECT * INTO OUTFILE '/tmp/t2.csv' FROM t1;\n");
Test->try_query(Test->conn_master, (char *) "SELECT * INTO OUTFILE '/tmp/t2.csv' FROM t1;");
Test->tprintf("using ReadConn slave: SELECT * INTO OUTFILE '/tmp/t3.csv' FROM t1;\n");
Test->try_query(Test->conn_slave, (char *) "SELECT * INTO OUTFILE '/tmp/t3.csv' FROM t1;");
Test->tprintf("Copying t1.cvs from Maxscale machine:\n");
Test->copy_from_maxscale((char *) "/tmp/t1.csv", (char *) "./");
/*sprintf(str,
"scp -i %s -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o LogLevel=quiet %s@%s:/tmp/t1.csv ./",
Test->repl->sshkey[0], Test->repl->access_user[0], Test->repl->IP[0]);
Test->tprintf("%s\n", str);
system(str);*/
MYSQL *srv[2];
srv[0] = Test->conn_rwsplit;
srv[1] = Test->conn_master;
for (int i = 0; i < iterations; i++)
{
Test->set_timeout(100);
Test->tprintf("Dropping t1 \n");
Test->try_query(Test->conn_rwsplit, (char *) "DROP TABLE t1;");
Test->stop_timeout();
Test->repl->sync_slaves();
Test->set_timeout(100);
Test->tprintf("Create t1\n");
create_t1(Test->conn_rwsplit);
Test->tprintf("Loading data to t1 from file\n");
Test->try_query(srv[i], (char *) "LOAD DATA LOCAL INFILE 't1.csv' INTO TABLE t1;");
Test->stop_timeout();
Test->repl->sync_slaves();
Test->set_timeout(100);
Test->tprintf("SELECT: rwsplitter\n");
Test->add_result(select_from_t1(Test->conn_rwsplit, N), "Wrong data in 't1'");
Test->tprintf("SELECT: master\n");
Test->add_result(select_from_t1(Test->conn_master, N), "Wrong data in 't1'");
Test->tprintf("SELECT: slave\n");
Test->add_result(select_from_t1(Test->conn_slave, N), "Wrong data in 't1'");
}
Test->repl->close_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,69 @@
/**
* @file bug526.cpp regression case for bug 526 ( " Wrong module name crashes maxscale on connect" )
*
* - Maxscale.cnf with "filters=QLA|testfilter" for RWSplit router service, 'testfilter' is not defined.
* - check error log for proper error messages and checks if ReadConn services are alive
*/
/*
Hartmut Holzgraefe 2014-09-08 13:08:46 UTC
I mistyped a module name (for a filter in this case)
[testfilter]
type=filter
module=foobar
There were no warnings about this on startup at all, but at the first time trying to connect to a service this filter was used in maxscale crashed with a segmentation fault after writing the following error log entries:
2014 09/08 15:00:53 Error : Unable to find library for module: foobar.
2014 09/08 15:00:53 Failed to create filter 'testfilter' for service 'testrouter'.
2014 09/08 15:00:53 Error : Failed to create Read Connection Router session.
2014 09/08 15:00:53 Error : Invalid authentication message from backend. Error : 28000, Msg : Access denied for user 'maxuser'@'localhost' (using password: YES)
2014 09/08 15:00:53 Error : Backend server didn't accept authentication for user denied for user 'maxuser'@'localhost' (using password: YES).
Two problems here:
1) can't check up front that my configuration is valid / without errors without connecting to each defined service
2) maxscale crashes instead of handling this situation gracefully (e.g. ignoring the misconfigured filter, or disabling the service that refers to it alltogether)
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
#include "maxadmin_operations.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(20);
if (Test->connect_rwsplit() == 0)
{
Test->add_result(1, "Filter config is broken, but service is started\n");
}
if (Test->connect_readconn_master() == 0)
{
Test->add_result(1, "Filter config is broken, but Maxscale is started\n");
}
if (Test->connect_readconn_slave() == 0)
{
Test->add_result(1, "Filter config is broken, but Maxscale is started\n");
}
//sleep(5);
Test->execute_maxadmin_command((char*) "sync logs");
Test->check_log_err((char *) "Unable to find library for module: foobar", true);
Test->check_log_err((char *) "Failed to load filter module 'foobar'", true);
Test->check_log_err((char *) "Failed to load filter 'testfilter' for service 'RW Split Router'", true);
Test->check_log_err((char *)
"Failed to open, read or process the MaxScale configuration file /etc/maxscale.cnf. Exiting", true);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,315 @@
/**
* @file bug529.cpp regression case for bug 529 ( "'Current no. of conns' not going down" )
*
* - create table, opens 50 connections for every router, fill table with data using these connections.
* - check number of connections to Master - failure if there are more then 100 connections to master.
* - close RWSptit and ReadConn master connections and check connections to master again.
* - create 50 ReadConn slave connection in parallel threads, execute "SELECT * FROM t1" ones for every connections, then
* start using one of connections to create "SELECT" load.
* - check number of connections to Master again, wait 5 seconds and check number of connections to
* master ones more time: now expecting 0 connections to master (fail if there is a least one connection to master).
* - close and reopens all ReadConn slave connections in the main thread and check connections to master again
* - close all connection in all threads, close parallel thread
* - do final 'connections to master' check
*/
/*
lisu87 2014-09-08 16:50:29 UTC
After starting maxscale and putting some traffic to it, the number of current connections to master server are still going up:
Server 0x29e6330 (carlsberg)
Server: xxx.xxx.xxx.xxx
Status: Master, Running
Protocol: MySQLBackend
Port: 3306
Node Id: -1
Master Id: -1
Repl Depth: -1
Number of connections: 58
Current no. of conns: 29
Current no. of operations: 0
Server 0x2948f60 (psy-carslave-1)
Server: xxx.xxx.xxx.xxx
Status: Slave, Running
Protocol: MySQLBackend
Port: 3306
Node Id: -1
Master Id: -1
Repl Depth: -1
Number of connections: 0
Current no. of conns: 0
Current no. of operations: 0
Server 0x2948e60 (psy-carslave-2)
Server: xxx.xxx.xxx.xxx
Status: Slave, Running
Protocol: MySQLBackend
Port: 3306
Node Id: -1
Master Id: -1
Repl Depth: -1
Number of connections: 29
Current no. of conns: 0
Current no. of operations: 0
Comment 1 Vilho Raatikka 2014-09-09 06:53:56 UTC
Is the version release-1.0beta?
Does any load cause this or does it require multiple parallel clients, for example?
Comment 2 lisu87 2014-09-09 07:53:18 UTC
The version is release-1.0beta.
Even when just one short connection is made the counter of "Current no. of conns" goes up.
Interesting thing is that the amount of current connections for my slave is always exactly two times smaller than "Number of connections":
Server 0x1f51330 (carlsberg)
Server: 172.16.76.8
Status: Master, Running
Protocol: MySQLBackend
Port: 3306
Node Id: -1
Master Id: -1
Repl Depth: -1
Number of connections: 3278
Current no. of conns: 1639
Current no. of operations: 0
Comment 3 lisu87 2014-09-11 09:54:34 UTC
Any update on this one?
Comment 4 Vilho Raatikka 2014-09-11 10:34:20 UTC
The problem can't be reproduced with the code I'm working currently, and which will be the one where beta release will be refresed from. Thus, I'd wait till beta refresh is done and see if the problem still exists.
Comment 5 lisu87 2014-09-11 10:47:32 UTC
Thank you.
And one more question: is it normal that even if SELECT query has been performed on skave the "Number of connections" counter for master increases too?
Comment 6 Vilho Raatikka 2014-09-11 11:02:08 UTC
(In reply to comment #5)
> Thank you.
>
> And one more question: is it normal that even if SELECT query has been
> performed on skave the "Number of connections" counter for master increases
> too?
When rwsplit listens port 3333 and when a command like :
mysql -h 127.0.0.1 -P 3333 -u maxscaleuser -ppwd -e "select count(user) from mysql.user"
is executed client connects to MaxScale:3333, and MaxScale connects to master and slave(s). So connection count increases in each of those backends despite of query type.
If you already have a rwsplit session, no new connections should be created when new queries are executed.
Comment 7 Vilho Raatikka 2014-09-11 12:34:26 UTC
I built MaxScale from releaes-1.0beta-refresh branch and tested by running 5000 prepared statements in one session to MaxScale/RWSplit and executing 'show servers' in another window. During the run the number of current connections was 1 in each server and after the run all 'current' counters show 0.
If you want me to try with some other use case, describe it and I'll give it a try.
Comment 8 lisu87 2014-09-11 12:45:37 UTC
Thanks, Vilho.
I'm building maxscale from that branch now and will retest shortly.
Comment 9 lisu87 2014-09-11 14:45:26 UTC
Confirmed. It works fine with 1.0beta-refresh.
Thank you!
Comment 10 Vilho Raatikka 2014-09-22 10:11:06 UTC
The problem reappeared later and was eventually fixed in release-1.0beta-refresh commit a41a8d6060c7b60e09686bea8124803f047d85ad
*/
// counting connection to all services
#include <iostream>
#include "testconnections.h"
#include "sql_t1.h"
using namespace std;
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int exit_flag = 0;
int conn_N = 50;
TestConnections * Test ;
void *parall_traffic( void *ptr );
int main(int argc, char *argv[])
{
Test = new TestConnections(argc, argv);
Test->set_timeout(120);
int i;
int num_conn = 0;
char sql[100];
pthread_t parall_traffic1;
int check_iret;
MYSQL * conn;
MYSQL * rwsplit_conn[conn_N];
MYSQL * master_conn[conn_N];
MYSQL * slave_conn[conn_N];
Test->repl->connect();
conn = Test->open_rwsplit_connection();
execute_query(conn, (char *) "DROP DATABASE IF EXISTS test");
execute_query(conn, (char *) "CREATE DATABASE test");
execute_query(conn, (char *) "USE test;");
create_t1(conn);
mysql_close(conn);
Test->tprintf("Table t1 is created\n");
for (i = 0; i < conn_N; i++)
{
Test->set_timeout(60);
rwsplit_conn[i] = Test->open_rwsplit_connection();
master_conn[i] = Test->open_readconn_master_connection();
slave_conn[i] = Test->open_readconn_slave_connection();
sprintf(sql, "INSERT INTO t1 (x1, fl) VALUES(%d, 1);", i);
execute_query(rwsplit_conn[i], sql);
sprintf(sql, "INSERT INTO t1 (x1, fl) VALUES(%d, 2);", i);
execute_query(master_conn[i], sql);
fflush(stdout);
}
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(60);
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
Test->tprintf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn > 2 * conn_N))
{
Test->add_result(1, "too many connections to master\n");
}
}
Test->tprintf("Closing RWSptit and ReadConn master connections\n");
for (i = 0; i < conn_N; i++)
{
mysql_close(rwsplit_conn[i]);
mysql_close(master_conn[i]);
}
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(60);
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
printf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn > 2 * conn_N))
{
Test->add_result(1, "too many connections to master\n");
}
}
Test->tprintf("Opening more connection to ReadConn slave in parallel thread\n");
check_iret = pthread_create( &parall_traffic1, NULL, parall_traffic, NULL);
for (i = 0; i < Test->repl->N; i++)
{
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
printf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn > 2 * conn_N))
{
Test->add_result(1, "too many connections to master\n");
}
}
Test->stop_timeout();
Test->tprintf("Sleeping 15 seconds\n");
sleep(15);
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(60);
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
printf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn != 0))
{
Test->add_result(1, "there are still connections to master\n");
}
}
printf("Closing ReadConn slave connections\n");
for (i = 0; i < conn_N; i++)
{
mysql_close(slave_conn[i]);
}
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(60);
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
Test->tprintf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn != 0))
{
Test->add_result(1, "there are still connections to master\n");
}
}
Test->tprintf("Opening ReadConn slave connections again\n");
for (i = 0; i < conn_N; i++)
{
Test->set_timeout(60);
slave_conn[i] = Test->open_readconn_slave_connection();
sprintf(sql, "SELECT * FROM t1");
execute_query(slave_conn[i], sql);
fflush(stdout);
}
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(60);
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
Test->tprintf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn != 0))
{
Test->add_result(1, "there are still connections to master\n");
}
}
Test->tprintf("Closing ReadConn slave connections\n");
for (i = 0; i < conn_N; i++)
{
Test->set_timeout(20);
mysql_close(slave_conn[i]);
}
exit_flag = 1;
for (i = 0; i < Test->repl->N; i++)
{
Test->set_timeout(60);
num_conn = get_conn_num(Test->repl->nodes[i], Test->maxscale_IP, Test->maxscale_hostname, (char *) "test");
Test->tprintf("Connections to node %d (%s): %d\n", i, Test->repl->IP[i], num_conn);
if ((i == 0) && (num_conn != 0))
{
Test->add_result(1, "there are still connections to master\n");
}
}
int rval = Test->global_result;
delete Test;
return rval;
}
void *parall_traffic( void *ptr )
{
MYSQL * slave_conn1[conn_N];
int i;
for (i = 0; i < conn_N; i++)
{
slave_conn1[i] = Test->open_readconn_slave_connection();
execute_query(slave_conn1[i], "SELECT * FROM t1");
}
while (exit_flag == 0)
{
execute_query(slave_conn1[0], "SELECT * FROM t1");
}
for (i = 0; i < conn_N; i++)
{
mysql_close(slave_conn1[i]);
}
return NULL;
}

View File

@ -0,0 +1,56 @@
/**
* @file bug539.cpp regression case for bug539 ("MaxScale crashes in session_setup_filters")
* using maxadmin execute "fail backendfd"
* try quries against all services
* using maxadmin execute "fail clientfd"
* try quries against all services
* check if MaxScale alive
*/
#include "testconnections.h"
#include "maxadmin_operations.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(20);
int i, j;
MYSQL * conn;
int N_cmd = 2;
char * fail_cmd[N_cmd - 1];
int N_ports = 3;
int ports[N_ports];
fail_cmd[0] = (char *) "fail backendfd";
fail_cmd[1] = (char *) "fail clientfd";
ports[0] = Test->rwsplit_port;
ports[1] = Test->readconn_master_port;
ports[2] = Test->readconn_slave_port;
for (i = 0; i < N_cmd; i++)
{
for (j = 0; j < N_ports; j++)
{
Test->tprintf("Executing MaxAdmin command '%s'\n", fail_cmd[i]);
if (execute_maxadmin_command(Test->maxscale_IP, (char *) "admin", Test->maxadmin_password, fail_cmd[i]) != 0)
{
Test->add_result(1, "MaxAdmin command failed\n");
}
else
{
printf("Trying query against %d\n", ports[j]);
conn = open_conn(ports[j], Test->maxscale_IP, Test->maxscale_user, Test->maxscale_user, Test->ssl);
Test->try_query(conn, (char *) "show processlist;");
}
}
}
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,72 @@
/**
* @file bug547.cpp regression case for bug 547 and bug 594 ( "get_dcb fails if slaves are not available" and "Maxscale fails to start without anything in the logs if there is no slave available" )
* Behaviour has been changed and this test check only for crash
* - block all slaves
* - try some queries (create table, do INSERT using RWSplit router)
* - check there is no crash
*/
/*
Vilho Raatikka 2014-09-16 07:43:54 UTC
get_dcb function returns the backend descriptor for router. Some merge has broken the logic and in case of non-existent slave the router simply fails to find a backend server although master would be available.
Comment 1 Vilho Raatikka 2014-09-16 09:40:14 UTC
get_dcb now searches master if slaves are not available.
*/
// also relates to bug594
// all slaves in MaxScale config have wrong IP
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
int i;
for (i = 1; i < Test->repl->N; i++)
{
Test->set_timeout(20);
Test->repl->block_node(i);
}
Test->set_timeout(30);
sleep(15);
Test->set_timeout(30);
Test->tprintf("Connecting to all MaxScale services, expecting error\n");
Test->connect_maxscale();
Test->set_timeout(30);
Test->tprintf("Trying some queries, expecting failure, but not a crash\n");
execute_query(Test->conn_rwsplit, (char *) "DROP TABLE IF EXISTS t1");
execute_query(Test->conn_rwsplit, (char *) "CREATE TABLE t1 (x INT)");
execute_query(Test->conn_rwsplit, (char *) "INSERT INTO t1 (x) VALUES (1)");
execute_query(Test->conn_rwsplit, (char *) "select * from t1");
execute_query(Test->conn_master, (char *) "select * from t1");
execute_query(Test->conn_slave, (char *) "select * from t1");
Test->set_timeout(10);
Test->close_maxscale_connections();
Test->set_timeout(30);
Test->repl->unblock_all_nodes();
Test->stop_timeout();
sleep(15);
Test->check_log_err((char *) "fatal signal 11", false);
Test->check_log_err((char *) "Failed to create new router session for service 'RW-Split-Router'", true);
Test->check_log_err((char *)
"Failed to create new router session for service 'Read-Connection-Router-Master'", true);
Test->check_log_err((char *) "Failed to create new router session for service 'Read-Connection-Router-Slave'",
true);
int rval = Test->global_result;
delete Test;
return rval;
}

73
maxscale-system-test/bug561.sh Executable file
View File

@ -0,0 +1,73 @@
#!/bin/bash
###
## @file bug561.sh Regression case for the bug "Different error messages from MariaDB and Maxscale"
## - try to connect to non existing DB directly to MariaDB server and via Maxscale
## - compare error messages
## - repeat for RWSplit, ReadConn
rp=`realpath $0`
export test_dir=`dirname $rp`
export test_name=`basename $rp`
$test_dir/non_native_setup $test_name
if [ $? -ne 0 ] ; then
echo "configuring maxscale failed"
exit 1
fi
export ssl_options="--ssl-cert=$test_dir/ssl-cert/client-cert.pem --ssl-key=$test_dir/ssl-cert/client-key.pem"
#echo "Waiting for 15 seconds"
#sleep 15
mariadb_err=`mysql -u$node_user -p$node_password -h $node_000_network $ssl_options --socket=$node_000_socket -P $node_000_port non_existing_db 2>&1`
maxscale_err=`mysql -u$node_user -p$node_password -h $maxscale_IP -P 4006 $ssl_options non_existing_db 2>&1`
maxscale_err1=`mysql -u$node_user -p$node_password -h $maxscale_IP -P 4008 $ssl_options non_existing_db 2>&1`
maxscale_err2=`mysql -u$node_user -p$node_password -h $maxscale_IP -P 4009 $ssl_options non_existing_db 2>&1`
echo "MariaDB message"
echo "$mariadb_err"
echo " "
echo "Maxscale message from RWSplit"
echo "$maxscale_err"
echo "Maxscale message from ReadConn master"
echo "$maxscale_err1"
echo "Maxscale message from ReadConn slave"
echo "$maxscale_err2"
res=0
#echo "$maxscale_err" | grep "$mariadb_err"
if [ "$maxscale_err" != "$mariadb_err" ] ; then
echo "Messages are different!"
echo "MaxScale: $maxscale_err"
echo "Server: $mariadb_err"
res=1
else
echo "Messages are same"
fi
if [ "$maxscale_err1" != "$mariadb_err" ] ; then
echo "Messages are different!"
echo "MaxScale: $maxscale_err1"
echo "Server: $mariadb_err"
res=1
else
echo "Messages are same"
fi
if [ "$maxscale_err2" != "$mariadb_err" ] ; then
echo "Messages are different!"
echo "MaxScale: $maxscale_err2"
echo "Server: $mariadb_err"
res=1
else
echo "Messages are same"
fi
$test_dir/copy_logs.sh bug561
exit $res

42
maxscale-system-test/bug562.sh Executable file
View File

@ -0,0 +1,42 @@
#!/bin/bash
###
## @file bug562.sh Regression case for the bug "Wrong error message for Access denied error"
## - try to connect with bad credestials directly to MariaDB server and via Maxscale
## - compare error messages
rp=`realpath $0`
export test_dir=`dirname $rp`
export test_name=`basename $rp`
$test_dir/non_native_setup $test_name
if [ $? -ne 0 ] ; then
echo "configuring maxscale failed"
exit 1
fi
export ssl_options="--ssl-cert=$test_dir/ssl-cert/client-cert.pem --ssl-key=$test_dir/ssl-cert/client-key.pem"
mariadb_err=`mysql -u no_such_user -psome_pwd -h $node_001_network $ssl_option --socket=$node_000_socket test 2>&1`
maxscale_err=`mysql -u no_such_user -psome_pwd -h $maxscale_IP -P 4006 $ssl_options test 2>&1`
echo "MariaDB message"
echo "$mariadb_err"
echo " "
echo "Maxscale message"
echo "$maxscale_err"
res=0
#echo "$maxscale_err" | grep "$mariadb_err"
echo "$maxscale_err" |grep "ERROR 1045 (28000): Access denied for user 'no_such_user'@'"
if [ "$?" != 0 ]; then
echo "Maxscale message is not ok!"
echo "Message: $maxscale_err"
res=1
else
echo "Messages are same"
res=0
fi
$test_dir/copy_logs.sh bug562
exit $res

44
maxscale-system-test/bug564.sh Executable file
View File

@ -0,0 +1,44 @@
#!/bin/bash
###
## @file bug564.sh Regression case for the bug "Wrong charset settings"
## - call MariaDB client with different --default-character-set= settings
## - check output of SHOW VARIABLES LIKE 'char%'
rp=`realpath $0`
export test_dir=`dirname $rp`
export test_name=`basename $rp`
$test_dir/non_native_setup $test_name
if [ $? -ne 0 ] ; then
echo "configuring maxscale failed"
exit 1
fi
export ssl_options="--ssl-cert=$test_dir/ssl-cert/client-cert.pem --ssl-key=$test_dir/ssl-cert/client-key.pem"
for char_set in "latin1" "latin2"
do
line1=`mysql -u$node_user -p$node_password -h $maxscale_IP -P 4006 $ssl_options --default-character-set="$char_set" -e "SHOW VARIABLES LIKE 'char%'" | grep "character_set_client"`
line2=`mysql -u$node_user -p$node_password -h $maxscale_IP -P 4006 $ssl_options --default-character-set="$char_set" -e "SHOW VARIABLES LIKE 'char%'" | grep "character_set_connection"`
line3=`mysql -u$node_user -p$node_password -h $maxscale_IP -P 4006 $ssl_options --default-character-set="$char_set" -e "SHOW VARIABLES LIKE 'char%'" | grep "character_set_results"`
echo $line1 | grep "$char_set"
res1=$?
echo $line2 | grep "$char_set"
res2=$?
echo $line3 | grep "$char_set"
res3=$?
if [[ $res1 != 0 ]] || [[ $res2 != 0 ]] || [[ $res3 != 0 ]] ; then
echo "charset is ignored"
mysql -u$node_user -p$node_password -h $maxscale_IP -P 4006 $ssl_options --default-character-set="latin2" -e "SHOW VARIABLES LIKE 'char%'"
$test_dir/copy_logs.sh bug564
exit 1
fi
done
$test_dir/copy_logs.sh bug564
exit 0

View File

@ -0,0 +1,106 @@
/**
* @file bug565.cpp regression case for bug 565 ( "Clients CLIENT_FOUND_ROWS setting is ignored by maxscale" ) MAX-311
*
* - open connection with CLIENT_FOUND_ROWS flag
* - CREATE TABLE t1(id INT PRIMARY KEY, val INT, msg VARCHAR(100))
* - INSERT INTO t1 VALUES (1, 1, 'foo'), (2, 1, 'bar'), (3, 2, 'baz'), (4, 2, 'abc')"
* - check 'affected_rows' for folloing UPDATES:
* + UPDATE t1 SET msg='xyz' WHERE val=2" (expect 2)
* + UPDATE t1 SET msg='xyz' WHERE val=2 (expect 0)
* + UPDATE t1 SET msg='xyz' WHERE val=2 (expect 2)
*/
/*
Hartmut Holzgraefe 2014-10-02 14:27:18 UTC
Created attachment 155 [details]
test for mysql_affected_rows() with/without CLIENT_FOUND_ROWS connection flag
Even worse: connections via maxscale always behave as if CLIENT_FOUND_ROWS is set even though the default is NOT having it set.
When doing the same update two times in a row without CLIENT_FOUND_ROWS
mysql_affected_rows() should return the number of rows actually changed
by the last query, while with CLIENT_FOUND_ROWS connection flag set the
number of matching rows is returned, even if the UPDATE didn't change
any column values.
With a direct connection to mysqld this works as expected,
through readconnroute(master) I'm always getting the number of matching
rows (as if CLIENT_FOUND_ROWS was set), and not the number of actually
changed rows when CLIENT_FOUND_ROWS is not set (which is the default
behaviour when not setting connection options)
Attaching PHP mysqli test script, result with direct mysqld connection is
update #1: 2
update #2: 0
update #3: 2
while through maxscale it is
update #1: 2
update #2: 2
update #3: 2
I also verified this using the C API directly to rule out that this is
a PHP specific problem
Comment 1 Vilho Raatikka 2014-10-08 14:11:38 UTC
Client flags are not passed to backend server properly.
Comment 2 Vilho Raatikka 2014-10-08 19:35:58 UTC
Pushed initial fix to MAX-311. Waiting for validation for the fix.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(30);
MYSQL * conn_found_rows;
my_ulonglong rows;
Test->repl->connect();
Test->connect_maxscale();
conn_found_rows = open_conn_db_flags(Test->rwsplit_port, Test->maxscale_IP, (char *) "test",
Test->maxscale_user, Test->maxscale_password, CLIENT_FOUND_ROWS, Test->ssl);
Test->set_timeout(30);
execute_query(Test->conn_rwsplit, "DROP TABLE IF EXISTS t1");
execute_query(Test->conn_rwsplit, "CREATE TABLE t1(id INT PRIMARY KEY, val INT, msg VARCHAR(100))");
execute_query(Test->conn_rwsplit,
"INSERT INTO t1 VALUES (1, 1, 'foo'), (2, 1, 'bar'), (3, 2, 'baz'), (4, 2, 'abc')");
Test->set_timeout(30);
execute_query_affected_rows(Test->conn_rwsplit, "UPDATE t1 SET msg='xyz' WHERE val=2", &rows);
Test->tprintf("update #1: %ld (expeced value is 2)\n", (long) rows);
if (rows != 2)
{
Test->add_result(1, "Affected rows is not 2\n");
}
Test->set_timeout(30);
execute_query_affected_rows(Test->conn_rwsplit, "UPDATE t1 SET msg='xyz' WHERE val=2", &rows);
Test->tprintf("update #2: %ld (expeced value is 0)\n", (long) rows);
if (rows != 0)
{
Test->add_result(1, "Affected rows is not 0\n");
}
Test->set_timeout(30);
execute_query_affected_rows(conn_found_rows, "UPDATE t1 SET msg='xyz' WHERE val=2", &rows);
Test->tprintf("update #3: %ld (expeced value is 2)\n", (long) rows);
if (rows != 2)
{
Test->add_result(1, "Affected rows is not 2\n");
}
Test->close_maxscale_connections();
int rval = Test->global_result;
delete Test;
return rval;
}

34
maxscale-system-test/bug567.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash
###
## @file bug567.sh Regression case for the bug "Crash if files from /dev/shm/ removed"
## - try to remove everythign from /dev/shm/$maxscale_pid
## check if Maxscale is alive
rp=`realpath $0`
export test_dir=`dirname $rp`
export test_name=`basename $rp`
$test_dir/non_native_setup $test_name
if [ $? -ne 0 ] ; then
echo "configuring maxscale failed"
exit 1
fi
export ssl_options="--ssl-cert=$test_dir/ssl-cert/client-cert.pem --ssl-key=$test_dir/ssl-cert/client-key.pem"
#pid=`ssh -i $maxscale_sshkey -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $maxscale_access_user@$maxscale_IP "pgrep maxscale"`
#echo "Maxscale pid is $pid"
echo "removing log directory from /dev/shm/"
if [ $maxscale_IP != "127.0.0.1" ] ; then
ssh -i $maxscale_sshkey -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $maxscale_access_user@$maxscale_IP "sudo rm -rf /dev/shm/maxscale/*"
else
sudo rm -rf /dev/shm/maxscale/*
fi
sleep 1
echo "checking if Maxscale is alive"
echo "show databases;" | mysql -u$node_user -p$node_password -h $maxscale_IP -P 4006 $ssl_options
res=$?
$test_dir/copy_logs.sh bug567
exit $res

View File

@ -0,0 +1,141 @@
/**
* @file bug571.cpp regression case for bug 571 and bug 585 ( "Using regex filter hangs MaxScale" and "modutil_extract_SQL doesn't work with multiple GWBUF buffers" )
*
* - Maxscale.cnf
* @verbatim
[regex]
type=filter
module=regexfilter
match=[Ff][Oo0][rR][mM]
replace=FROM
[r2]
type=filter
module=regexfilter
match=fetch
replace=select
[hints]
type=filter
module=hintfilter
[RW Split Router]
type=service
router= readwritesplit
servers=server1, server2, server3,server4
user=skysql
passwd=skysql
max_slave_connections=100%
use_sql_variables_in=all
router_options=slave_selection_criteria=LEAST_BEHIND_MASTER
filters=hints|regex|r2
@endverbatim
* for bug585:
* @verbatim
[regex]
type=filter
module=regexfilter
match=fetch
replace=select
[typo]
type=filter
module=regexfilter
match=[Ff][Oo0][Rr][Mm]
replace=from
[RW Split Router]
type=service
router= readwritesplit
servers=server1, server2, server3,server4
user=skysql
passwd=skysql
max_slave_connections=100%
use_sql_variables_in=all
router_options=slave_selection_criteria=LEAST_BEHIND_MASTER
filters=regex|typo
@endverbatim
* - fetch * from mysql.user;
* - fetch count(*) form mysql.user;
* - check if Maxscale is alive
*/
/*
Vilho Raatikka 2014-10-10 11:09:19 UTC
Branch:release-1.0.1beta
Executing :
fetch * from mysql.user
with this config hangs MaxScale
[regex]
type=filter
module=regexfilter
match=[Ff][Oo0][rR][mM]
replace=FROM
[r2]
type=filter
module=regexfilter
match=fetch
replace=select
[hints]
type=filter
module=hintfilter
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
max_slave_connections=100%
use_sql_variables_in=all
router_options=slave_selection_criteria=LEAST_BEHIND_MASTER
user=maxuser
passwd=maxpwd
filters=hints|regex|r2
Comment 1 Vilho Raatikka 2014-10-11 18:55:23 UTC
If we look at the rewrite function we see that query lacks one character.
T 127.0.0.1:37858 -> 127.0.0.1:4006 [AP]
16 00 00 00 03 66 65 74 63 68 20 69 64 20 66 72 .....fetch id fr
6f 6d 20 74 65 73 74 2e 74 31 om test.t1
T 127.0.0.1:44591 -> 127.0.0.1:3000 [AP]
17 00 00 00 03 73 65 6c 65 63 74 20 69 64 20 66 .....select id f
72 6f 6d 20 74 65 73 74 2e 74 rom test.t
*/
// the same code is used for bug585
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->tprintf("Connecting to all MaxScale services\n");
Test->set_timeout(10);
Test->add_result(Test->connect_maxscale(), "Error connectiong to Maxscale\n");
Test->tprintf("executing fetch * from mysql.user \n");
Test->set_timeout(10);
Test->try_query(Test->conn_rwsplit, (char *) "fetch * from mysql.user;");
Test->set_timeout(10);
Test->try_query(Test->conn_rwsplit, (char *) "fetch count(*) form mysql.user;");
Test->set_timeout(10);
Test->close_maxscale_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,46 @@
/**
* @file bug572.cpp regression case for bug 572 ( " If reading a user from users table fails, MaxScale fails" )
*
* - try GRANT with wrong IP using all Maxscale services:
* + GRANT ALL PRIVILEGES ON *.* TO 'foo'@'*.foo.notexists' IDENTIFIED BY 'foo';
* + GRANT ALL PRIVILEGES ON *.* TO 'bar'@'127.0.0.*' IDENTIFIED BY 'bar'
* + DROP USER 'foo'@'*.foo.notexists'
* + DROP USER 'bar'@'127.0.0.*'
* - do "select * from mysql.user" using RWSplit to check if Maxsclae crashed
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
void create_drop_bad_user(MYSQL * conn, TestConnections * Test)
{
Test->try_query(conn, (char *)
"GRANT ALL PRIVILEGES ON *.* TO 'foo'@'*.foo.notexists' IDENTIFIED BY 'foo';");
Test->try_query(conn, (char *) "GRANT ALL PRIVILEGES ON *.* TO 'bar'@'127.0.0.*' IDENTIFIED BY 'bar'");
Test->try_query(conn, (char *) "DROP USER 'foo'@'*.foo.notexists'");
Test->try_query(conn, (char *) "DROP USER 'bar'@'127.0.0.*'");
}
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->repl->connect();
Test->connect_maxscale();
Test->tprintf("Trying GRANT for with bad IP: RWSplit\n");
create_drop_bad_user(Test->conn_rwsplit, Test);
Test->tprintf("Trying SELECT to check if Maxscale hangs\n");
Test->try_query(Test->conn_rwsplit, (char *) "select * from mysql.user");
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,110 @@
/**
* @file bug587.cpp regression case for the bug 587 ( "Hint filter don't work if listed before regex filter in configuration file" )
*
* - Maxscale.cnf
* @verbatim
[hints]
type=filter
module=hintfilter
[regex]
type=filter
module=regexfilter
match=fetch
replace=select
[RW Split Router]
type=service
router= readwritesplit
servers=server1, server2, server3,server4
user=skysql
passwd=skysql
max_slave_connections=100%
use_sql_variables_in=all
router_options=slave_selection_criteria=LEAST_BEHIND_MASTER
filters=hints|regex
@endverbatim
* - second test (bug587_1) is executed with "filters=regex|hints" (dffeent order of filters)
* - check if hints filter working by executing and comparing results:
* + via RWSPLIT: "select @@server_id; -- maxscale route to server server%d" (%d - node number)
* + directly to backend node "select @@server_id;"
* - do the same test with "filters=regex|hints" "filters=hints|regex"
*/
/*
Vilho Raatikka 2014-10-21 19:12:33 UTC
If filters and rwsplit are configured as follows, hints don't work.
[hints]
type=filter
module=hintfilter
[regex]
type=filter
module=regexfilter
match=fetch
replace=select
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
max_slave_connections=100%
use_sql_variables_in=all
user=maxuser
passwd=maxpwd
filters=hints|regex
Changing filters=regex|hints makes it work. This is due to processing order. Regex filter drops hint off.
Comment 1 Vilho Raatikka 2014-10-23 18:08:07 UTC
buffer.c:gwbuf_make_contiguous: hint wasn't duplicated to new GWBUF struct. As a result hints were lost if query rewriting resulted in longer query than the original.
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->repl->connect();
Test->connect_maxscale();
char server_id[256];
char server_id_d[256];
char hint_sql[64];
for (int i = 1; i < 25; i++)
{
for (int j = 0; j < Test->repl->N; j++)
{
Test->set_timeout(10);
sprintf(hint_sql, "select @@server_id; -- maxscale route to server server%d", j + 1);
Test->tprintf("%s\n", hint_sql);
find_field(Test->conn_rwsplit, hint_sql, (char *) "@@server_id", &server_id[0]);
find_field(Test->repl->nodes[j], (char *) "select @@server_id;", (char *) "@@server_id", &server_id_d[0]);
Test->tprintf("server%d ID from Maxscale: \t%s\n", j + 1, server_id);
Test->tprintf("server%d ID directly from node: \t%s\n", j + 1, server_id_d);
Test->add_result(strcmp(server_id, server_id_d), "Hints does not work!\n");
}
}
Test->close_maxscale_connections();
Test->repl->close_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,129 @@
/**
* @file bug592.cpp regression case for bug 592 ( "slave in "Running" state breaks authorization" ) MXS-326
*
* - stop all slaves: "stop slave;" directly to every node (now they are in "Running" state, not in "Russning, Slave")
* - via RWSplit "CREATE USER 'test_user'@'%' IDENTIFIED BY 'pass'"
* - try to connect using 'test_user' (expecting success)
* - start all slaves: "start slave;" directly to every node
* - via RWSplit: "DROP USER 'test_user'@'%'"
*/
/*
Timofey Turenko 2014-10-24 09:35:35 UTC
1. setup: Master/Slave replication
2. reboot slaves
3. create user usinf connection to RWSplit
4. try to use this user to connect to Maxscale
expected result:
Authentication is ok
actual result:
Access denied for user 'user'@'192.168.122.1' (using password: YES)
Th issue was discovered with following setup state:
MaxScale> show servers
Server 0x3428260 (server1)
Server: 192.168.122.106
Status: Master, Running
Protocol: MySQLBackend
Port: 3306
Server Version: 5.5.40-MariaDB-log
Node Id: 106
Master Id: -1
Slave Ids: 107, 108 , 109
Repl Depth: 0
Number of connections: 0
Current no. of conns: 0
Current no. of operations: 0
Server 0x3428160 (server2)
Server: 192.168.122.107
Status: Slave, Running
Protocol: MySQLBackend
Port: 3306
Server Version: 5.5.40-MariaDB-log
Node Id: 107
Master Id: 106
Slave Ids:
Repl Depth: 1
Number of connections: 0
Current no. of conns: 0
Current no. of operations: 0
Server 0x3428060 (server3)
Server: 192.168.122.108
Status: Running
Protocol: MySQLBackend
Port: 3306
Server Version: 5.5.40-MariaDB-log
Node Id: 108
Master Id: 106
Slave Ids:
Repl Depth: 1
Number of connections: 0
Current no. of conns: 0
Current no. of operations: 0
Server 0x338c3f0 (server4)
Server: 192.168.122.109
Status: Running
Protocol: MySQLBackend
Port: 3306
Server Version: 5.5.40-MariaDB-log
Node Id: 109
Master Id: 106
Slave Ids:
Repl Depth: 1
Number of connections: 0
Current no. of conns: 0
Current no. of operations: 0
Maxscale read mysql.user table from server4 which was not properly replicated
Comment 1 Mark Riddoch 2014-11-05 09:55:07 UTC
In the reload users routine, if there is a master available then use that rather than the first.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
int i;
Test->repl->connect();
Test->connect_maxscale();
for (i = 1; i < Test->repl->N; i++)
{
execute_query(Test->repl->nodes[i], (char *) "stop slave;");
}
execute_query(Test->conn_rwsplit, (char *) "CREATE USER 'test_user'@'%%' IDENTIFIED BY 'pass'");
MYSQL * conn = open_conn_no_db(Test->rwsplit_port, Test->maxscale_IP, (char *) "test_user", (char *) "pass",
Test->ssl);
if (conn == NULL)
{
Test->add_result(1, "Connections error\n");
}
for (i = 1; i < Test->repl->N; i++)
{
execute_query(Test->repl->nodes[i], (char *) "start slave;");
}
execute_query(Test->conn_rwsplit, (char *) "DROP USER 'test_user'@'%%'");
Test->repl->close_connections();
Test->close_maxscale_connections();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,128 @@
/**
* @file bug601.cpp regression case for bug 601 ("COM_CHANGE_USER fails with correct user/pwd if executed during authentication")
* - configure Maxscale.cnf to use only one thread
* - in 100 parallel threads start to open/close session
* - do change_user 2000 times
* - check all change_user are ok
* - check Mascale is alive
*/
/*
Vilho Raatikka 2014-10-30 14:30:57 UTC
If COM_CHANGE_USER is executed while backend protocol's state is not yet MYSQL_AUTH_RECV it will fail in the backend.
If MaxScale uses multiple worked threads this occurs rarely and it would be possible to easily suspend execution of COM_CHANGE_USER.
If MaxScale uses one worker thread then there's currently no way to suspend execution. It would require thread to put current task on hold, complete authentication task and return to COM_CHANGE_USER execution.
In theory it is possible to add an event to client's DCB and let it become notified in the same way than events that occur in sockets. It would have to be added first (not last) and ensure that no other command is executed before it.
Since this is the only case known where this would be necessary, it could be enough to add a "pending auth change" pointer in client's protocol object which would be checked before thread returns to epoll_wait after completing the authentication.
Comment 1 Massimiliano 2014-11-07 17:01:29 UTC
Current code in develop branch let COM_CHANGE_USER work fine.
I noticed sometime a failed authentication issue using only.
This because backend protocol's state is not yet MYSQL_AUTH_RECV and necessary data for succesfull backend change user (such as scramble data from handshake) may be not available.
I put a query before change_user and the issue doesn't appear: that's another proof.
Comment 2 Vilho Raatikka 2014-11-13 15:54:15 UTC
In gw_change_user->gw_send_change_user_to_backend authentication message was sent to backend server before backend had its scramble data. That caused authentication to fail.
Comment 3 Vilho Raatikka 2014-11-13 15:58:34 UTC
if (func.auth ==)gw_change_user->gw_send_change_user_to_backend is called before backend has its scramble, auth packet is set to backend's delauqueue instead of writing it to backend. When backend_write_delayqueue is called COM_CHANGE_USER packets are rewritten with backend's current data.
*/
#include <iostream>
#include "testconnections.h"
using namespace std;
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int exit_flag = 0;
TestConnections * Test ;
void *parall_traffic( void *ptr );
int main(int argc, char *argv[])
{
int iterations = 1000;
Test = new TestConnections(argc, argv);
if (Test->smoke)
{
iterations = 100;
}
pthread_t parall_traffic1[100];
int check_iret[100];
Test->set_timeout(60);
Test->repl->connect();
Test->repl->execute_query_all_nodes((char *) "set global max_connect_errors=1000;");
Test->repl->execute_query_all_nodes((char *) "set global max_connections=1000;");
Test->connect_maxscale();
Test->tprintf("Creating one user 'user@%%'");
execute_query_silent(Test->conn_rwsplit, (char *) "DROP USER user@'%'");
Test->try_query(Test->conn_rwsplit, (char *) "CREATE USER user@'%%' identified by 'pass2'");
Test->try_query(Test->conn_rwsplit, (char *) "GRANT SELECT ON test.* TO user@'%%';");
Test->try_query(Test->conn_rwsplit, (char *) "FLUSH PRIVILEGES;");
Test->tprintf("Starting parallel thread which opens/closes session in the loop");
for (int j = 0; j < 25; j++)
{
check_iret[j] = pthread_create(&parall_traffic1[j], NULL, parall_traffic, NULL);
}
Test->tprintf("Doing change_user in the loop");
for (int i = 0; i < iterations; i++)
{
Test->set_timeout(15);
Test->add_result(mysql_change_user(Test->conn_rwsplit, "user", "pass2", (char *) "test"),
"change_user failed! %", mysql_error(Test->conn_rwsplit));
Test->add_result(mysql_change_user(Test->conn_rwsplit, Test->maxscale_user, Test->maxscale_password,
(char *) "test"), "change_user failed! %s", mysql_error(Test->conn_rwsplit));
}
Test->tprintf("Waiting for all threads to finish");
exit_flag = 1;
for (int j = 0; j < 25; j++)
{
Test->set_timeout(30);
pthread_join(parall_traffic1[j], NULL);
}
Test->tprintf("All threads are finished");
Test->repl->flush_hosts();
Test->tprintf("Change user to '%s' in order to be able to DROP user", Test->maxscale_user);
Test->set_timeout(30);
mysql_change_user(Test->conn_rwsplit, Test->maxscale_user, Test->maxscale_password, NULL);
Test->tprintf("Dropping user", Test->maxscale_user);
Test->try_query(Test->conn_rwsplit, (char *) "DROP USER user@'%%';");
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}
void *parall_traffic( void *ptr )
{
MYSQL * conn;
while (exit_flag == 0)
{
conn = Test->open_rwsplit_connection();
mysql_close(conn);
if (Test->backend_ssl)
{
sleep(1);
}
}
return NULL;
}

View File

@ -0,0 +1,268 @@
/**
* @file bug620.cpp bug620 regression case ("enable_root_user=true generates errors to error log")
*
* - Maxscale.cnf contains RWSplit router definition with enable_root_user=true
* - GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'skysqlroot';
* - try to connect using 'root' user and execute some query
* - errors are not expected in the log. All Maxscale services should be alive.
*/
/*
Vilho Raatikka 2014-11-14 09:03:59 UTC
Enabling use of root user in MaxScale causes the following being printed to error log. Disabling the setting enable_root_user prevents these errors.
2014-11-14 11:02:47 Error : getaddrinfo failed for [linux-yxkl.site] due [Name or service not known]
2014-11-14 11:02:47 140635119954176 [mysql_users_add()] Failed adding user root@linux-yxkl.site for service [RW Split Router]
2014-11-14 11:02:47 Error : getaddrinfo failed for [::1] due [Address family for hostname not supported]
2014-11-14 11:02:47 140635119954176 [mysql_users_add()] Failed adding user root@::1 for service [RW Split Router]
2014-11-14 11:02:47 140635119954176 [mysql_users_add()] Failed adding user root@127.0.0.1 for service [RW Split Router]
Comment 1 Vilho Raatikka 2014-11-14 09:04:40 UTC
This appears with binary built from develop branch 14.11.14
Comment 2 Massimiliano 2014-11-14 09:15:27 UTC
The messages appear in the log because root user has an invalid hostname: linux-yxkl.site
The second message root@127.0.0.1 may be related to a previous root@localhost entry.
Names are resolved to IPs and added into maxscale hashtable: localhost and 127.0.0.1 result in a duplicated entry
A standard root@localhost only entry doesn't cause any logged message
Comment 3 Vilho Raatikka 2014-11-14 09:24:56 UTC
Problem is that they seem critical errors but MaxScale still works like nothing had happened. If the default hostname of the server host is not good, what does it mean for MaxScale? Doest it still accept root user or not? Why it only causes trouble for root user but not for others?
If the error has no effect in practice, then log entries could be better in debug log.
Thread ids are suitable in debug log but not anywhere else.
Comment 4 Massimiliano 2014-11-14 09:32:27 UTC
The 'enable_root_user' option only allows selecting 'root' user from backend databases.
The error messages are printed for all users and report that
specific_user@specific_host is not loaded but
Example:
2014-11-14 11:02:47 Error : getaddrinfo failed for [linux-yxkl.site] due [Name or service not known]
2014-11-14 11:02:47 140635119954176 [mysql_users_add()] Failed adding user root@linux-yxkl.site for service [RW Split Router]
2014-11-14 04:19:23 Error : getaddrinfo failed for [ftp.*.fi] due [Name or service not known]
2014-11-14 04:19:23 67322400 [mysql_users_add()] Failed adding user foo@ftp.*.fi for service [Master Service]
In the examples foo@%.funet.fi and root@linux-yxkl.site are not loaded.
foo@localhost and root@localhost are loaded
Comment 5 Vilho Raatikka 2014-11-14 10:55:35 UTC
(In reply to comment #4)
> The 'enable_root_user' option only allows selecting 'root' user from backend
> databases.
I think that enable_root_user means : MaxScale user can use her 'root' account also with MaxScale.
Technically your explanation may be correct and I'm not against that. What I mean is that the user may not want to worry about what is 'loaded' or 'selected' under the cover.
She simply wants to use root user. If it is not possible then that should be written to error log clearly. For example, "Use of 'root' disabled due to unreachable hostname" or something equally clear.
Reporting several lines of errors may confuse the user especially if the root account still works perfectly.
>
>
> The error messages are printed for all users and report that
>
> specific_user@specific_host is not loaded but
>
>
> Example:
>
> 2014-11-14 11:02:47 Error : getaddrinfo failed for [linux-yxkl.site] due
> [Name or service not known]
> 2014-11-14 11:02:47 140635119954176 [mysql_users_add()] Failed adding user
> root@linux-yxkl.site for service [RW Split Router]
>
> 2014-11-14 04:19:23 Error : getaddrinfo failed for [ftp.*.fi] due [Name or
> service not known]
> 2014-11-14 04:19:23 67322400 [mysql_users_add()] Failed adding user
> foo@ftp.*.fi for service [Master Service]
>
>
>
> In the examples foo@%.funet.fi and root@linux-yxkl.site are not loaded.
>
>
> foo@localhost and root@localhost are loaded
Comment 6 Massimiliano 2014-11-14 11:00:04 UTC
MaxScale MySQL authentication is based on user@host
You may have such situation:
foo@localhost [OK]
foo@x-y-z.notexists [KO]
user 'foo@localhost' is loaded the latter isn't
For root user is the same.
Allowing selection of root user means selecting all the rows from mysql.user table where user='root'
if there is any row (root@xxxx) that cannot be loaded the message appears.
In a standard setup we don't expect any log messages
Comment 7 Timofey Turenko 2014-12-10 16:02:36 UTC
I tried following:
via RWSplit:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'skysqlroot';
and try to connect to RWSplit using 'root' and 'skysqlroot' and try some simple query:
2014-12-10 17:35:43 Error : getaddrinfo failed for [::1] due [Address family for hostname not supported]
2014-12-10 17:35:43 Warning: Failed to add user root@::1 for service [RW Split Router]. This user will be unavailable via MaxScale.
2014-12-10 17:35:43 Warning: Failed to add user root@127.0.0.1 for service [RW Split Router]. This user will be unavailable via MaxScale.
2014-12-10 17:35:43 Error : Failed to start router for service 'HTTPD Router'.
2014-12-10 17:35:43 Error : Failed to start service 'HTTPD Router'.
2014-12-10 17:36:08 Error : getaddrinfo failed for [::1] due [Address family for hostname not supported]
2014-12-10 17:36:08 Warning: Failed to add user root@::1 for service [RW Split Router]. This user will be unavailable via MaxScale.
2014-12-10 17:36:08 Warning: Failed to add user root@127.0.0.1 for service [RW Split Router]. This user will be unavailable via MaxScale.
Is it expected?
Comment 8 Massimiliano 2014-12-10 16:09:23 UTC
root@::1 could not be loaded because it's for IPv6
root@127.0.0.1 may be not loaded if root@localhost was found before
As names are translated to IPv4 addresses localhost->127.0.0.1 and that'a duplicate
2014-12-10 17:35:43 Error : Failed to start router for service 'HTTPD Router'.
2014-12-10 17:35:43 Error : Failed to start service 'HTTPD Router'.
Those messages are not part of mysql users load phase.
when you have auth errors users are reload (in the allowed time window) and you see the messages again
With admin interface you can check:
show dbusers RW Split Router
and you should see root@% you added with the grant
Comment 9 Timofey Turenko 2014-12-12 21:59:30 UTC
Following is present in the error log just after MaxScale start:
2014-12-12 23:49:07 Error : getaddrinfo failed for [::1] due [Address family for hostname not supported]
2014-12-12 23:49:07 Warning: Failed to add user root@::1 for service [RW Split Router]. This user will be unavailable via MaxScale.
2014-12-12 23:49:07 Warning: Failed to add user root@127.0.0.1 for service [RW Split Router]. This user will be unavailable via MaxScale.
first two line are clear: no support for IPv6, but would it be better to print 'warning' instead of 'error'?
"Failed to add user root@127.0.0.1" - is it correct?
direct connection to backend gives:
MariaDB [(none)]> select User, host from mysql.user;
+---------+-----------+
| User | host |
+---------+-----------+
| maxuser | % |
| repl | % |
| skysql | % |
| root | 127.0.0.1 |
| root | ::1 |
| | localhost |
| maxuser | localhost |
| root | localhost |
| skysql | localhost |
| | node1 |
| root | node1 |
+---------+-----------+
admin interface gives:
MaxScale> show dbusers "RW Split Router"
Users table data
Hashtable: 0x7f6b64000c30, size 52
No. of entries: 7
Average chain length: 0.1
Longest chain length: 1
User names: root@192.168.122.106, repl@%, skysql@%, maxuser@127.0.0.1, skysql@127.0.0.1, root@127.0.0.1, maxuser@%
So, root@127.0.0.1 is present in the list.
Comment 10 Mark Riddoch 2015-01-05 13:03:34 UTC
The message "Failed to add user root@127.0.0.1" is because the two entries root@localhsot and root@127.0.0.1 are seen as duplicates in MaxScale. This is a result of MaxScale resolving hostnames at the time it reads the database rather than at connect time. So a duplicate is detected and the second one causes the error to be displayed.
Comment 11 Timofey Turenko 2015-01-09 19:26:35 UTC
works as expected, closing.
Check for lack of "Error : getaddrinfo failed" added (just in case) and for warning about 'skysql'
*/
#include <iostream>
#include <unistd.h>
#include "testconnections.h"
using namespace std;
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(30);
Test->connect_maxscale();
Test->tprintf("Creating 'root'@'%%'\n");
//global_result += execute_query(Test->conn_rwsplit, (char *) "CREATE USER 'root'@'%'; SET PASSWORD FOR 'root'@'%' = PASSWORD('skysqlroot');");
Test->try_query(Test->conn_rwsplit,
(char *) "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%%' IDENTIFIED BY 'skysqlroot';");
Test->try_query(Test->conn_rwsplit,
(char *) "GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'skysqlroot';");
sleep(10);
MYSQL * conn;
Test->tprintf("Connecting using 'root'@'%%'\n");
conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "root", (char *) "skysqlroot", Test->ssl);
if (mysql_errno(conn) != 0)
{
Test->add_result(1, "Connection using 'root' user failed, error: %s\n", mysql_error(conn));
}
else
{
Test->tprintf("Simple query...\n");
Test->try_query(conn, (char *) "SELECT * from mysql.user");
Test->try_query(conn,
(char *) "set password for 'root'@'localhost' = PASSWORD('');");
}
if (conn != NULL)
{
mysql_close(conn);
}
Test->tprintf("Dropping 'root'@'%%'\n");
Test->try_query(Test->conn_rwsplit, (char *) "DROP USER 'root'@'%%';");
Test->close_maxscale_connections();
Test->check_log_err((char *) "Failed to add user skysql", false);
Test->check_log_err((char *) "getaddrinfo failed", false);
Test->check_log_err((char *) "Couldn't find suitable Master", false);
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,181 @@
/**
* @file bug626.cpp regression case for bug 626 ("Crash when user define with old password style (before 4.1 protocol)"), also checks error message in the log for bug428 ("Pre MySQL 4.1 encrypted passwords cause authorization failure")
*
* - CREATE USER 'old'@'%' IDENTIFIED BY 'old';
* - SET PASSWORD FOR 'old'@'%' = OLD_PASSWORD('old');
* - try to connect using user 'old'
* - check log for "MaxScale does not support these old passwords" warning
* - DROP USER 'old'@'%'
* - check MaxScale is alive
*/
/*
Stephane VAROQUI 2014-11-25 17:37:58 UTC
2014-11-21 16:24:03 Error : Invalid authentication message from backend. Error code: 1129, Msg : Host '192.168.42.172' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
2014-11-21 16:24:03 Error : access for secrets file [/usr/local/maxscale/maxscale-1.0.1-beta/etc/.secrets] failed. Error 2, No such file or directory.
2014-11-21 16:24:03 Error : Unable to get user data from backend database for service RW Split Router. Missing server information.
2014-11-21 16:24:03 Error : Unable to write to backend due to authentication failure.
2014-11-21 16:24:03 Error : Invalid authentication message from backend. Error code: 1129, Msg : Host '192.168.42.172' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'
2014-11-21 16:24:03 Error : access for secrets file [/usr/local/maxscale/maxscale-1.0.1-beta/etc/.secrets] failed. Error 2, No such file or directory.
2014-11-21 16:24:03 Error : Unable to get user data from backend database for service RW Split Router. Missing server information.
2014-11-21 16:24:03 Error : Unable to write to backend due to authentication failure.
2014-11-21 16:24:03 Fatal: MaxScale received fatal signal 11. Attempting backtrace.
2014-11-21 16:24:03 ./maxscale() [0x53ad1c]
2014-11-21 16:24:03 /usr/lib64/libpthread.so.0(+0xf6d0) [0x7fd8039756d0]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libreadwritesplit.so(is_read_tmp_table+0x64) [0x7fd7ec0f9d25]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libreadwritesplit.so(+0x5577) [0x7fd7ec0fa577]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libMySQLClient.so(+0x5821) [0x7fd7ea1a1821]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libMySQLClient.so(+0x49df) [0x7fd7ea1a09df]
2014-11-21 16:24:03 ./maxscale() [0x547093]
2014-11-21 16:24:03 ./maxscale(poll_waitevents+0xbd) [0x546858]
2014-11-21 16:24:03 ./maxscale(main+0x12b2) [0x53cfd2]
2014-11-21 16:24:03 /usr/lib64/libc.so.6(__libc_start_main+0xf5) [0x7fd8035c9d65]
2014-11-21 16:24:03 ./maxscale() [0x539fdd]
Comment 1 Mark Riddoch 2014-11-25 17:57:20 UTC
Vilho,
looks like multiple issues here, the missing authentication data is one problem, but the SEGFAULT appears to occur in the Read/Write Splitter
2014-11-21 16:24:03 Fatal: MaxScale received fatal signal 11. Attempting backtrace.
2014-11-21 16:24:03 ./maxscale() [0x53ad1c]
2014-11-21 16:24:03 /usr/lib64/libpthread.so.0(+0xf6d0) [0x7fd8039756d0]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libreadwritesplit.so(is_read_tmp_table+0x64) [0x7fd7ec0f9d25]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libreadwritesplit.so(+0x5577) [0x7fd7ec0fa577]
2014-11-21 16:24:03 /usr/local/maxscale/maxscale-1.0.1-beta/modules/libMySQLClient.so(+0x5821) [0x7fd7ea1a1821]
Massimiliano 2014-12-01 17:29:26 UTC
I have found an easy way to produce the "Host xxxx is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'" error
Connect directly to mysql backend(s):
# mysql -h 127.0.0.1 -P 3310
MariaDB [(none)]> set global max_connect_errors=1;
Query OK, 0 rows affected (0.00 sec)
...
# nc 127.0.0.1 3310
]
5.5.5-10.0.11-MariaDB-log??A[(SHQ>$???6$PEI"ilc+L{mysql_native_password
Ctrl-C
Next attempt results in:
# nc 127.0.0.1 3310
j?iHost '151.20.6.153' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'[root@mcentos62 ~]
Then I restored error count:
# mysqladmin -h 127.0.0.1 -P 3310 flush-hosts
I launched a mysqlslap test against MaxScale, and after a few seconds I caused the error as described above and ...
[root@mcentos62 ~]# mysqlslap -h 127.0.0.1 -P 4008 -umassi -pmassi --query="select 1" --concurrency=16 --iterations=200
mysqlslap: Cannot run query select 1 ERROR : Authentication with backend failed. Session will be closed.
But no crash at all, this with GA branch and maxscale-1.0.1-beta RPMs.
Some details about the error itself.
http://dev.mysql.com/doc/refman/5.0/en/blocked-host.html
B.5.2.6 Host 'host_name' is blocked
If the following error occurs, it means that mysqld has received many connection requests from the given host that were interrupted in the middle:
...
By default, mysqld blocks a host after 10 connection errors.
------------------------------------
I also tried with with gdb and MaxScale binary, with a breakpoint set to the gw_create_backend_connection routine.
Once the breakpoint is reached I did Ctrl-C int the mysql client (connected to MaxScale) and this caused the error too in the next connection.
As the client stopped running, MaxScale cannot continue with async backend connection and this may increase the error counter: this may be a good example looking for any possible incomplete backend authentication due to a potential bug.
Note, using a value as high as 10000 for max_connect_errors doesn't result in any issue of course.
BTW, in my today setup even having backends with max_connect_errors=1 doesn't result in any issue at all.
I run a test with MaxScale on a Virtual CentOS 6.2 on my laptop and backends in a Digital Ocean server, so with the Internet in the middle.
Comment 9 Massimiliano 2014-12-03 10:04:49 UTC
Reported segfault is related to is_read_tmp_table() routine.
"many connection errors" not spotted yet during MaxScale tests
A new setup is highly desiderable, it should happen in a few days.
Comment 10 Massimiliano 2014-12-03 15:48:55 UTC
No issues/crea found with user and old_password style.
Message is logged into the error log where there is such case.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(20);
printf("Creating user with old style password\n");
Test->repl->connect();
execute_query(Test->repl->nodes[0], "CREATE USER 'old'@'%%' IDENTIFIED BY 'old';");
execute_query(Test->repl->nodes[0], "SET PASSWORD FOR 'old'@'%%' = OLD_PASSWORD('old');");
Test->stop_timeout();
Test->repl->sync_slaves();
Test->set_timeout(20);
printf("Trying to connect using user with old style password\n");
MYSQL * conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "old", (char *) "old", Test->ssl);
if ( mysql_errno(conn) != 0)
{
Test->tprintf("Connections is not open as expected\n");
}
else
{
Test->add_result(1, "Connections is open for the user with old style password.\n");
}
if (conn != NULL)
{
mysql_close(conn);
}
execute_query(Test->repl->nodes[0], "DROP USER 'old'@'%%'");
Test->check_log_err((char *) "MaxScale does not support these old passwords", true);
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,42 @@
/**
* @file bug634.cpp regression case for bug 634 ("SHOW SLAVE STATUS in RW SPLITTER is send to master")
*
* - execute SHOW SLAVE STATUS and check resut
*/
/*
Description Stephane VAROQUI 2014-12-03 10:41:30 UTC
SHOW SLAVE STATUS in RW SPLITTER is send to master ? That could break some monitoring scripts for generic proxy abstraction .
Comment 1 Vilho Raatikka 2014-12-03 11:10:12 UTC
COM_SHOW_SLAVE_STAT was unknown to query classifier. Being fixed.
Comment 2 Vilho Raatikka 2014-12-03 11:26:17 UTC
COM_SHOW_SLAVE_STAT wasn't classified but it was treated as 'unknown' and thus routed to master.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(5);
char master_ip[100];
Test->connect_maxscale();
for (int i = 0; i < 100; i++)
{
Test->set_timeout(5);
Test->add_result(find_field(Test->conn_rwsplit, (char *) "SHOW SLAVE STATUS", (char *) "Master_Host",
master_ip), "Master_host files is not found in the SHOW SLAVE STATUS reply, probably query went to master\n");
Test->add_result(strcmp(master_ip, Test->repl->IP_private[0]), "Master IP is wrong\n");
}
Test->close_maxscale_connections();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,64 @@
/**
* @file bug643.cpp regression case for bugs 643 ("Hints, RWSplit: MaxScale goes into infinite loop and crashes") and bug645
* - setup RWSplit in the following way for bug643
* @verbatim
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
max_slave_connections=100%
use_sql_variables_in=all
user=skysql
passwd=skysql
filters=duplicate
[duplicate]
type=filter
module=tee
service=RW Split Router
@endverbatim
* - try to connect
* - try simple query using ReadConn router (both, master and slave)
* - check warnig in the log "RW Split Router: Recursive use of tee filter in service"
*/
/*
Mark Riddoch 2014-12-11 11:59:19 UTC
There is a recursive use of the tee filter in the configuration.
The "RW Split Router" uses the"duplicate" filter that will then duplicate all traffic to the original destination and another copy of the "RW Split Router", which again will duplicate all traffic to the original destination and another copy of the "RW Split Router"...
Really this needs to be trapped as a configuration error.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->tprintf("Trying to connect to all Maxscale services\n");
fflush(stdout);
Test->connect_maxscale();
Test->tprintf("Trying to send query to ReadConn master\n");
fflush(stdout);
Test->try_query(Test->conn_master, (char *) "show processlist");
Test->tprintf("Trying to send query to ReadConn slave\n");
fflush(stdout);
Test->try_query(Test->conn_slave, (char *) "show processlist");
Test->tprintf("Trying to send query to RWSplit, expecting failure\n");
fflush(stdout);
if (execute_query(Test->conn_rwsplit, (char *) "show processlist") == 0)
{
Test->add_result(1, "FAIL: Query to broken service succeeded!\n");
}
Test->close_maxscale_connections();
Test->check_log_err((char *) "RW-Split-Router: Recursive use of tee filter in service", true);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,96 @@
/**
* @file bug643.cpp regression case for bugs 643 ("Hints, RWSplit: MaxScale goes into infinite loop and crashes") and bug645
* - setup RWSplit in the following way for bug643
* @verbatim
[hints]
type=filter
module=hintfilter
[regex]
type=filter
module=regexfilter
match=fetch
replace=select
[typo]
type=filter
module=regexfilter
match=[Ff][Oo0][Rr][Mm]
replace=from
[qla]
type=filter
module=qlafilter
options=/tmp/QueryLog
[duplicate]
type=filter
module=tee
service=RW Split2
[testfilter]
type=filter
module=foobar
[RW Split Router]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
#servers=server1,server2
max_slave_connections=100%
use_sql_variables_in=all
#use_sql_variables_in=master
user=skysql
passwd=skysql
#filters=typo|qla|regex|hints|regex|hints
#enable_root_user=1
filters=duplicate
[RW Split2]
type=service
router=readwritesplit
servers=server1,server2,server3,server4
max_slave_connections=100%
use_sql_variables_in=all
user=skysql
passwd=skysql
filters=qla|tests|hints
@endverbatim
* - try to connect
* - try simple query using all services
* - check warnig in the log "Failed to start service 'RW Split2"
* - check if Maxscale still alive
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->tprintf("Trying to connect to all Maxscale services\n");
fflush(stdout);
Test->connect_maxscale();
Test->tprintf("Trying to send query to RWSplit\n");
fflush(stdout);
execute_query(Test->conn_rwsplit, (char *) "show processlist");
Test->tprintf("Trying to send query to ReadConn master\n");
fflush(stdout);
execute_query(Test->conn_master, (char *) "show processlist");
Test->tprintf("Trying to send query to ReadConn slave\n");
fflush(stdout);
execute_query(Test->conn_slave, (char *) "show processlist");
Test->close_maxscale_connections();
Test->check_log_err((char *) "Unable to find filter 'tests' for service 'RW Split2'", true);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,213 @@
/**
* @file bug643.cpp regression case for bugs 645 ("Tee filter with readwritesplit service hangs MaxScale")
* - setup RWSplit in the following way
* @verbatim
[RW_Router]
type=service
router=readconnroute
servers=server1
user=skysql
passwd=skysql
version_string=5.1-OLD-Bored-Mysql
filters=DuplicaFilter
[RW_Split]
type=service
router=readwritesplit
servers=server1, server3,server2
user=skysql
passwd=skysql
[DuplicaFilter]
type=filter
module=tee
service=RW_Split
[RW_Listener]
type=listener
service=RW_Router
protocol=MySQLClient
port=4006
[RW_Split_list]
type=listener
service=RW_Split
protocol=MySQLClient
port=4016
@endverbatim
* - try to connect
* - try simple query
* - check MaxScale is alive
*/
/*
Massimiliano 2014-12-11 14:19:51 UTC
When tee filter is used with a readwritesplit service MaxScale hangs (each service including admin interface)or there is a failed assetion in Debug mode:
debug assert /source/GA/server/modules/routing/readwritesplit/readwritesplit.c:1825
maxscale: /source/GA/server/modules/routing/readwritesplit/readwritesplit.c:1825: routeQuery: Assertion `!(querybuf->gwbuf_type == 0)' failed.
Configuration:
[RW_Router]
type=service
router=readconnroute
servers=server1
user=massi
passwd=massi
version_string=5.1-OLD-Bored-Mysql
filters=DuplicaFilter
[RW_Split]
type=service
router=readwritesplit
servers=server3,server2
user=massi
passwd=massi
[DuplicaFilter]
type=filter
module=tee
service=RW_Split
[RW_Listener]
type=listener
service=RW_Router
protocol=MySQLClient
port=4606
Accessing the RW_listener:
mysql -h 127.0.0.1 -P 4606 -umassi -pmassi
Debug version:
2014-12-11 08:48:48 Fatal: MaxScale received fatal signal 6. Attempting backtrace.
2014-12-11 08:48:48 ./maxscale() [0x53c80e]
2014-12-11 08:48:48 /lib64/libpthread.so.0(+0xf710) [0x7fd418a62710]
2014-12-11 08:48:48 /lib64/libc.so.6(gsignal+0x35) [0x7fd417318925]
2014-12-11 08:48:48 /lib64/libc.so.6(abort+0x175) [0x7fd41731a105]
2014-12-11 08:48:48 /lib64/libc.so.6(+0x2ba4e) [0x7fd417311a4e]
2014-12-11 08:48:48 /lib64/libc.so.6(__assert_perror_fail+0) [0x7fd417311b10]
2014-12-11 08:48:48 /usr/local/skysql/maxscale/modules/libreadwritesplit.so(+0x69ca) [0x7fd4142789ca]
2014-12-11 08:48:48 /usr/local/skysql/maxscale/modules/libtee.so(+0x3707) [0x7fd3fc2db707]
2014-12-11 08:48:48 /usr/local/skysql/maxscale/modules/libMySQLClient.so(+0x595d) [0x7fd3fe34b95d]
2014-12-11 08:48:48 ./maxscale() [0x54d3ec]
2014-12-11 08:48:48 ./maxscale(poll_waitevents+0x63d) [0x54ca8a]
2014-12-11 08:48:48 ./maxscale(main+0x1acc) [0x53f616]
2014-12-11 08:48:48 /lib64/libc.so.6(__libc_start_main+0xfd) [0x7fd417304d1d]
2014-12-11 08:48:48 ./maxscale() [0x53a92d]
Without debug:
we got mysql prompt but then maxscale is stucked
or
when don't have the prompt, it hangs after few welcome messages
Comment 1 Vilho Raatikka 2014-12-11 15:14:50 UTC
The assertion occurs because query is is not statement - but packet type. That is, it was sent to read connection router which doesn't examine MySQL packets except the header. Thus, the type of query is not set in mysql_client.c:gw_read_client_event:
>>>
if (cap == 0 || (cap == RCAP_TYPE_PACKET_INPUT))
{
stmt_input = false;
}
else if (cap == RCAP_TYPE_STMT_INPUT)
{
stmt_input = true;
gwbuf_set_type(read_buffer, GWBUF_TYPE_MYSQL);
}
>>>
Comment 2 Massimiliano 2014-12-11 16:00:52 UTC
Using readconnroute (with router_options=master) instead seems fine.
I found that "USE dbname" is not passed via tee filter:
4606 is the listener to a service with tee filter
root@maxscale-02 build]# mysql -h 127.0.0.1 -P 4606 -u massi -pmassi
USE test; SELECT DATABASE()
client to maxscale:
T 127.0.0.1:40440 -> 127.0.0.1:4606 [AP]
05 00 00 00 02 74 65 73 74 .....test
T 127.0.0.1:4606 -> 127.0.0.1:40440 [AP]
07 00 00 01 00 00 00 02 00 00 00 ...........
T 127.0.0.1:40440 -> 127.0.0.1:4606 [AP]
12 00 00 00 03 53 45 4c 45 43 54 20 44 41 54 41 .....SELECT DATA
42 41 53 45 28 29 BASE()
T 127.0.0.1:4606 -> 127.0.0.1:40440 [AP]
01 00 00 01 01 20 00 00 02 03 64 65 66 00 00 00 ..... ....def...
0a 44 41 54 41 42 41 53 45 28 29 00 0c 08 00 22 .DATABASE()...."
00 00 00 fd 00 00 1f 00 00 05 00 00 03 fe 00 00 ................
02 00 05 00 00 04 04 74 65 73 74 05 00 00 05 fe .......test.....
00 00 02 00 ....
maxscale to backend:
T 127.0.0.1:56578 -> 127.0.0.1:3308 [AP]
12 00 00 00 03 53 45 4c 45 43 54 20 44 41 54 41 .....SELECT DATA
42 41 53 45 28 29 BASE()
T 127.0.0.1:3308 -> 127.0.0.1:56578 [AP]
01 00 00 01 01 20 00 00 02 03 64 65 66 00 00 00 ..... ....def...
0a 44 41 54 41 42 41 53 45 28 29 00 0c 08 00 22 .DATABASE()...."
00 00 00 fd 00 00 1f 00 00 05 00 00 03 fe 00 00 ................
02 00 01 00 00 04 fb 05 00 00 05 fe 00 00 02 00 ................
USE test was not sent
May be a similar issue is present with readwritesplit but I cannot test it
Comment 3 Vilho Raatikka 2014-12-11 16:35:46 UTC
(In reply to comment #2)
> Using readconnroute (with router_options=master) instead seems fine.
Using readconnroute _where_? in tee?
Comment 4 Vilho Raatikka 2014-12-12 08:27:41 UTC
gwbuf_type is not set and that is the immediate cause for assertion with Debug version.
Reason why the type is not set is in the way the packets are first processed in mysql_client.c client protocol module and then passed optionally to filters and router. There is a bug because it is assumed that when client protocol module reads incoming packet it can resolve which router will handle the packet processing. The code doesn't take into account that same packet can be processed by many different routers, like in the case of readconnrouter->tee->readwritesplit.
Another problem is in readwritesplit where it is assumed that it is the first and the only router that will process tha data. So it includes checks that the buffer has correct type.
Required changes are:
- readwritesplit should check if buffer has no type and in that case, insted of asserting, merge incoming MySQL packet fragments into a single contiguous buffer.
- remove checks which enforce rules which are based on false assumption.
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->connect_maxscale();
Test->try_query(Test->conn_master, (char *) "show processlist");
Test->try_query(Test->conn_slave, (char *) "show processlist");
Test->try_query(Test->conn_rwsplit, (char *) "show processlist");
Test->close_maxscale_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,104 @@
/**
* @file bug643.cpp regression case for bugs 645 ("Tee filter with readwritesplit service hangs MaxScale")
* - setup RWSplit in the following way
* @verbatim
[RW_Router]
type=service
router=readconnroute
servers=server1
user=skysql
passwd=skysql
version_string=5.1-OLD-Bored-Mysql
filters=DuplicaFilter
[RW_Split]
type=service
router=readwritesplit
servers=server3,server2
user=skysql
passwd=skysql
[DuplicaFilter]
type=filter
module=tee
service=RW_Split
[RW_Listener]
type=listener
service=RW_Router
protocol=MySQLClient
port=4006
[RW_Split_list]
type=listener
service=RW_Split
protocol=MySQLClient
port=4016
[Read Connection Router Slave]
type=service
router=readconnroute
router_options= slave
servers=server1,server2,server3,server4
user=skysql
passwd=skysql
filters=QLA
[Read Connection Router Master]
type=service
router=readconnroute
router_options=master
servers=server1,server2,server3,server4
user=skysql
passwd=skysql
filters=QLA
[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
@endverbatim
* - try to connect to all services except 4016
* - try simple query
* - check ReadConn is ok
* - check log for presens of "Couldn't find suitable Master from 2 candidates" errors
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(10);
Test->connect_maxscale();
Test->tprintf("trying query to RWSplit, expecting failure\n");
if (execute_query(Test->conn_rwsplit, (char *) "show processlist") == 0)
{
Test->add_result(1, "Query is ok, but failue is expected\n");
}
Test->tprintf("Trying query to ReadConn router master\n");
Test->try_query(Test->conn_master, (char *) "show processlist");
Test->tprintf("Trying query to ReadConn router slave\n");
Test->try_query(Test->conn_slave, (char *) "show processlist");
Test->close_maxscale_connections();
Test->check_log_err((char *) "Couldn't find suitable Master from 2 candidates", true);
Test->check_log_err((char *) "Creating client session for Tee filter failed. Terminating session.", true);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,156 @@
/**
* @file bug649.cpp regression case for bug 649 ("Segfault using RW Splitter")
* @verbatim
[RW_Router]
type=service
router=readconnroute
servers=server1
user=skysql
passwd=skysql
version_string=5.1-OLD-Bored-Mysql
filters=DuplicaFilter
[RW_Split]
type=service
router=readwritesplit
servers=server1,server3,server2
user=skysql
passwd=skysql
[DuplicaFilter]
type=filter
module=tee
service=RW_Split
@endverbatim
* - Connect to RWSplit
* - create load on RWSplit (25 threads doing long INSERTs in the loop)
* - block Mariadb server on Master node by Firewall
* - unblock Mariadb server
* - check if Maxscale is alive
* - reconnect and check if query execution is ok
*/
#include <iostream>
#include "testconnections.h"
#include "sql_t1.h"
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int exit_flag = 0;
TestConnections * Test ;
char sql[1000000];
void *parall_traffic( void *ptr );
int main(int argc, char *argv[])
{
int threads_num = 20;
pthread_t parall_traffic1[threads_num];
int check_iret[threads_num];
Test = new TestConnections(argc, argv);
int time_to_run = (Test->smoke) ? 10 : 30;
Test->set_timeout(10);
Test->tprintf("Connecting to RWSplit %s\n", Test->maxscale_IP);
Test->connect_rwsplit();
Test->repl->connect();
Test->tprintf("Drop t1 if exists\n");
execute_query(Test->repl->nodes[0], "DROP TABLE IF EXISTS t1;");
Test->tprintf("Create t1\n");
Test->add_result(create_t1(Test->repl->nodes[0]), "t1 creation Failed\n");
Test->repl->close_connections();
Test->stop_timeout();
sleep(5);
create_insert_string(sql, 65000, 1);
Test->tprintf("Creating query threads\n", time_to_run);
for (int j = 0; j < threads_num; j++)
{
Test->set_timeout(20);
check_iret[j] = pthread_create(&parall_traffic1[j], NULL, parall_traffic, NULL);
}
Test->stop_timeout();
Test->tprintf("Waiting %d seconds\n", time_to_run);
sleep(time_to_run);
Test->tprintf("Setup firewall to block mysql on master\n");
Test->repl->block_node(0);
fflush(stdout);
Test->tprintf("Waiting %d seconds\n", time_to_run);
sleep(time_to_run);
Test->set_timeout(30);
Test->tprintf("Trying query to RWSplit, expecting failure, but not a crash\n");
if (execute_query_silent(Test->conn_rwsplit, (char *) "show processlist;") == 0)
{
Test->add_result(1, "Failure is expected, but query is ok\n");
}
Test->stop_timeout();
sleep(time_to_run);
Test->tprintf("Setup firewall back to allow mysql\n");
Test->repl->unblock_node(0);
fflush(stdout);
Test->stop_timeout();
sleep(time_to_run);
exit_flag = 1;
for (int i = 0; i < threads_num; i++)
{
Test->set_timeout(30);
pthread_join(parall_traffic1[i], NULL);
Test->tprintf("exit %d\n", i);
}
Test->stop_timeout();
sleep(5);
Test->set_timeout(20);
Test->tprintf("Checking Maxscale is alive\n");
Test->check_maxscale_alive();
Test->set_timeout(20);
Test->tprintf("Reconnecting to RWSplit ...\n");
Test->connect_rwsplit();
Test->tprintf(" ... and trying query\n");
Test->try_query(Test->conn_rwsplit, (char *) "show processlist;");
Test->close_rwsplit();
int rval = Test->global_result;
delete Test;
return rval;
}
void *parall_traffic( void *ptr )
{
MYSQL * conn;
mysql_thread_init();
conn = Test->open_rwsplit_connection();
if ((conn != NULL) && (mysql_errno(conn) == 0))
{
while (exit_flag == 0)
{
execute_query_silent(conn, sql);
fflush(stdout);
}
}
else
{
Test->tprintf("Error opening connection");
}
if (conn != NULL )
{
mysql_close(conn);
}
return NULL;
}

View File

@ -0,0 +1,84 @@
/**
* @file bug650.cpp regression case for bug 650 ("Hints, RWSplit: MaxScale goes into infinite loop and crashes") and bug645
* - setup RWSplit in the following way
* @verbatim
[RW_Router]
type=service
router=readconnroute
servers=server1
user=skysql
passwd=skysql
version_string=5.1-OLD-Bored-Mysql
filters=DuplicaFilter
[RW_Split]
type=service
router=readwritesplit
servers=server3,server2
user=skysql
passwd=skysql
[DuplicaFilter]
type=filter
module=tee
service=RW_Split
[RW_Listener]
type=listener
service=RW_Router
protocol=MySQLClient
port=4006
[RW_Split_list]
type=listener
service=RW_Split
protocol=MySQLClient
port=4016
@endverbatim
* - try to connect
* - try simple query using ReadConn router (both, master and slave)
* - check errors in the log
@verbatim
Couldn't find suitable Master from 2 candidates
Failed to create RW_Split session.
Creating client session for Tee filter failed. Terminating session.
Failed to create filter 'DuplicaFilter' for service 'RW_Router'
Setting up filters failed. Terminating session RW_Router
@endverbatim
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(20);
Test->connect_maxscale();
Test->tprintf("Trying query to ReadConn master\n");
Test->try_query(Test->conn_master, (char *) "show processlist");
Test->tprintf("Trying query to ReadConn slave\n");
Test->try_query(Test->conn_slave, (char *) "show processlist");
Test->tprintf("Trying query to RWSplit, expecting failure\n");
if (execute_query(Test->conn_rwsplit, (char *) "show processlist") == 0)
{
Test->add_result(1, "Query is ok, but failure is expected\n");
}
Test->close_maxscale_connections();
Test->tprintf("Checking logs\n");
Test->check_log_err((char *) "Couldn't find suitable Master from 2 candidates", true);
Test->check_log_err((char *) "Failed to create new router session for service 'RW_Split'", true);
Test->check_log_err((char *) "Creating client session for Tee filter failed. Terminating session.", true);
Test->check_log_err((char *) "Failed to create filter 'DuplicaFilter' for service 'RW_Router'", true);
Test->check_log_err((char *) "Setting up filters failed. Terminating session RW_Router", true);
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,80 @@
/**
* @file bug653.cpp regression case for bug 653 ("Memory corruption when users with long hostnames that can no the resolved are loaded into MaxScale")
*
* - CREATE USER 'user_with_very_long_hostname'@'very_long_hostname_that_can_not_be_resolved_and_it_probably_caused_crash.com.net.org' IDENTIFIED BY 'old';
* - try to connect using user 'user_with_very_long_hostname'
* - DROP USER 'user_with_very_long_hostname'@'very_long_hostname_that_can_not_be_resolved_and_it_probably_caused_crash.com.net.org'
* - check MaxScale is alive
*/
/*
Mark Riddoch 2014-12-16 13:17:25 UTC
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff49385ac in free () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.47.el6_2.12.x86_64 keyutils-libs-1.4-4.el6.x86_64 krb5-libs-1.10.3-10.el6_4.2.x86_64 libaio-0.3.107-10.el6.x86_64 libcom_err-1.41.12-14.el6.x86_64 libgcc-4.4.7-4.el6.x86_64 libselinux-2.0.94-5.3.el6_4.1.x86_64 libstdc++-4.4.7-4.el6.x86_64 nss-pam-ldapd-0.7.5-14.el6_2.1.x86_64 nss-softokn-freebl-3.14.3-10.el6_5.x86_64 openssl-1.0.1e-16.el6_5.15.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) where
#0 0x00007ffff49385ac in free () from /lib64/libc.so.6
#1 0x000000000041d421 in add_mysql_users_with_host_ipv4 (users=0x72c4c0,
user=0x739030 "u3", host=0x739033 "aver.log.hostname.to.overflow.the.buffer",
passwd=0x73905c "", anydb=0x739089 "Y", db=0x0) at dbusers.c:291
#2 0x000000000041e302 in getUsers (service=0x728ef0, users=0x72c4c0)
at dbusers.c:742
#3 0x000000000041cf97 in load_mysql_users (service=0x728ef0) at dbusers.c:99
#4 0x00000000004128c7 in serviceStartPort (service=0x728ef0, port=0x729b70)
at service.c:227
#5 0x0000000000412e27 in serviceStart (service=0x728ef0) at service.c:365
#6 0x0000000000412f00 in serviceStartAll () at service.c:413
#7 0x000000000040b592 in main (argc=2, argv=0x7fffffffe108) at gateway.c:1750
Comment 1 Mark Riddoch 2014-12-16 13:18:09 UTC
The problem is a buffer overrun in normalise_hostname. Fix underway.
Comment 2 Mark Riddoch 2014-12-16 15:45:59 UTC
Increased buffer size to prevent overrun issue
Comment 3 Timofey Turenko 2014-12-22 15:39:32 UTC
I'm not sure I understand the bug correctly.
But 60-chars long host name does not cause problem (longer is not possible "String 'very_long_hostname_that_can_not_be_resolved_and_it_probably_caused_cra' is too long for host name (should be no longer than 60)"
*/
#include <iostream>
#include "testconnections.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(50);
Test->connect_maxscale();
Test->tprintf("Creating user with old style password\n");
Test->try_query(Test->conn_rwsplit,
(char *) "CREATE USER 'user_long_host11'@'very_long_hostname_that_probably_caused_crashhh.com.net.org' IDENTIFIED BY 'old'");
Test->try_query(Test->conn_rwsplit,
(char *) "GRANT ALL PRIVILEGES ON *.* TO 'user_long_host11'@'very_long_hostname_that_probably_caused_crashhh.com.net.org' WITH GRANT OPTION");
sleep(10);
Test->tprintf("Trying to connect using user with old style password\n");
MYSQL * conn = open_conn(Test->rwsplit_port, Test->maxscale_IP, (char *) "user_long_host11", (char *) "old",
Test->ssl);
if ( mysql_errno(conn) != 0 )
{
Test->tprintf("Connections is not open as expected\n");
}
else
{
Test->add_result(1, "Connections is open for the user with bad host\n");
}
if (conn != NULL)
{
mysql_close(conn);
}
Test->try_query(Test->conn_rwsplit,
(char *) "DROP USER 'user_long_host11'@'very_long_hostname_that_probably_caused_crashhh.com.net.org'");
Test->close_maxscale_connections();
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

View File

@ -0,0 +1,202 @@
/**
* @file bug654.cpp regression case for bug654 abd 698 ("maxadm: show dbusers <two-part service name without quotation> causes SEGFAULT", "Using invalid parameter in many maxadmin commands causes MaxScale to fail")
*
* - execute maxadmin command show dbusers RW Split Router and show dbusers "RW Split Router"
* . execute different maxadmin commands with wrong parameters
* - check MaxScale is alive
*/
/*
Vilho Raatikka 2014-12-16 13:54:36 UTC
MaxScale> show services
Service 0x1af7eb0
Service: RW Split Router
Router: readwritesplit (0x7fffdf501440)
Number of router sessions: 0
Current no. of router sessions: 0
Number of queries forwarded: 0
Number of queries forwarded to master: 0
Number of queries forwarded to slave: 0
Number of queries forwarded to all: 0
Started: Tue Dec 16 15:51:54 2014
Root user access: Disabled
Filter chain: duplicate
Backend databases
127.0.0.1:3003 Protocol: MySQLBackend
127.0.0.1:3002 Protocol: MySQLBackend
127.0.0.1:3001 Protocol: MySQLBackend
127.0.0.1:3000 Protocol: MySQLBackend
Users data: 0x1aea000
Total connections: 1
Currently connected: 1
...
MaxScale> show dbusers RW Split Router
(gdb) bt
#0 0x00007fffdfb4950a in execute_cmd (cli=0x7fffc0000c70) at /home/raatikka/src/git/MaxScale/server/modules/routing/debugcmd.c:805
#1 0x00007fffdfb48ef8 in execute (instance=0x1b0f7b0, router_session=0x7fffc0000c70, queue=0x0) at /home/raatikka/src/git/MaxScale/server/modules/routing/cli.c:279
#2 0x00007ffff46ae934 in maxscaled_read_event (dcb=0x7fffc00009c0) at /home/raatikka/src/git/MaxScale/server/modules/protocol/maxscaled.c:177
#3 0x000000000058b145 in process_pollq (thread_id=2) at /home/raatikka/src/git/MaxScale/server/core/poll.c:858
#4 0x000000000058a7df in poll_waitevents (arg=0x2) at /home/raatikka/src/git/MaxScale/server/core/poll.c:608
#5 0x00007ffff7527e0f in start_thread () from /lib64/libpthread.so.0
#6 0x00007ffff5e0e0dd in clone () from /lib64/libc.so.6
(gdb)
Comment 1 Vilho Raatikka 2014-12-16 13:58:37 UTC
805 for (i = 0; args[i] && *args[i]; i++)
Off-by-one if there are more arguments than expected.
Comment 2 Vilho Raatikka 2014-12-23 16:11:12 UTC
NULL-terminated argument list in case where there are given more arguments than expected.
*/
#include "testconnections.h"
#include "maxadmin_operations.h"
int main(int argc, char *argv[])
{
TestConnections * Test = new TestConnections(argc, argv);
Test->set_timeout(30);
char result[1024];
Test->get_maxadmin_param((char *) "show dbusers RW Split Router", (char *) "Incorrect number of arguments:",
result);
Test->tprintf("result %s\n", result);
if (strstr(result, "show dbusers expects 1 argument") == NULL)
{
Test->add_result(1, "there is NO \"show dbusers expects 1 argument\" message");
}
Test->set_timeout(30);
Test->get_maxadmin_param((char *) "show dbusers \"RW Split Router\"", (char *) "User names:", result);
Test->tprintf("result %s\n", result);
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "reload dbusers 0x232fed0");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "reload dbusers Хрен");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "reload dbusers Хрен моржовый");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "Хрен моржовый");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "khren morzhovyj");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show Хрен");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show Хрен моржовый");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show khren morzhovyj");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show dcb Хрен");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show dcb Хрен моржовый");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show dcb khren morzhovyj");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show server Хрен");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show server Хрен моржовый");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show server khren morzhovyj");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show service Хрен");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show service Хрен моржовый");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show service khren morzhovyj");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "show service khren morzhovyj");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "list listeners");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "restart monitor");
Test->set_timeout(30);
Test->execute_maxadmin_command((char *) "restart service");
if (!Test->smoke)
{
int N = 28;
const char * cmd[N];
int Ng = 6;
const char * garbage[Ng];
garbage[0] = "qwerty";
garbage[1] = "khren morzhovyj";
garbage[2] = "Хрен";
garbage[3] = "Хрен моржовый";
garbage[4] =
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
garbage[5] =
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Хрен моржовый Хрен моржовый ";
cmd[0] = "enable disable heartbeat ";
cmd[1] = "disable heartbeat ";
cmd[2] = "reload dbusers ";
cmd[3] = "set server server1 master ";
cmd[4] = "set pollsleep ";
cmd[5] = "set nbpolls ";
cmd[6] = "show dcb ";
cmd[7] = "show eventq ";
cmd[8] = "show eventstats ";
cmd[9] = "show filter ";
cmd[10] = "show monitor ";
cmd[11] = "show server ";
cmd[12] = "show service ";
cmd[13] = "show session ";
cmd[14] = "show filters ";
cmd[15] = "show modules ";
cmd[16] = "show monitors ";
cmd[17] = "show servers ";
cmd[18] = "show services ";
cmd[19] = "show sessions ";
cmd[20] = "show tasks ";
cmd[21] = "show threads ";
cmd[22] = "show users ";
cmd[23] = "shutdown monitor ";
cmd[24] = "shutdown service ";
cmd[25] = "shutdown maxscale ";
cmd[26] = "enable root ";
cmd[27] = "disable root ";
char str1[4096];
int i1, i2;
for (i1 = 0; i1 < N; i1++)
{
for (i2 = 0; i2 < Ng; i2++)
{
Test->set_timeout(30);
sprintf(str1, "%s %s", cmd[i1], garbage[i2]);
Test->tprintf("Trying '%s'\n", str1);
Test->execute_maxadmin_command(str1);
sprintf(str1, "%s %s%s%s%s %s ", cmd[i1], garbage[i2], garbage[i2], garbage[i2], garbage[i2], garbage[i2]);
Test->tprintf("Trying '%s'\n", str1);
Test->execute_maxadmin_command(str1);
}
}
}
Test->check_maxscale_alive();
int rval = Test->global_result;
delete Test;
return rval;
}

Some files were not shown because too many files have changed in this diff Show More