diff options
Diffstat (limited to 'mysql-test/lib/v1/mysql-test-run.pl')
-rwxr-xr-x | mysql-test/lib/v1/mysql-test-run.pl | 4324 |
1 files changed, 4324 insertions, 0 deletions
diff --git a/mysql-test/lib/v1/mysql-test-run.pl b/mysql-test/lib/v1/mysql-test-run.pl new file mode 100755 index 00000000..aabe3d75 --- /dev/null +++ b/mysql-test/lib/v1/mysql-test-run.pl @@ -0,0 +1,4324 @@ +#!/usr/bin/env perl +# -*- cperl -*- + +# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. +# +# 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; version 2 of the License. +# +# 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 St, Fifth Floor, Boston, MA 02110-1335 USA + +############################################################################## +# +# mysql-test-run.pl +# +# Tool used for executing a suite of .test file +# +# See the "MySQL Test framework manual" for more information +# https://mariadb.com/kb/en/library/mysqltest/ +# +# Please keep the test framework tools identical in all versions! +# +############################################################################## +# +# Coding style directions for this perl script +# +# - To make this Perl script easy to alter even for those that not +# code Perl that often, keeep the coding style as close as possible to +# the C/C++ MySQL coding standard. +# +# - All lists of arguments to send to commands are Perl lists/arrays, +# not strings we append args to. Within reason, most string +# concatenation for arguments should be avoided. +# +# - Functions defined in the main program are not to be prefixed, +# functions in "library files" are to be prefixed with "mtr_" (for +# Mysql-Test-Run). There are some exceptions, code that fits best in +# the main program, but are put into separate files to avoid +# clutter, may be without prefix. +# +# - All stat/opendir/-f/ is to be kept in collect_test_cases(). It +# will create a struct that the rest of the program can use to get +# the information. This separates the "find information" from the +# "do the work" and makes the program more easy to maintain. +# +# - The rule when it comes to the logic of this program is +# +# command_line_setup() - is to handle the logic between flags +# collect_test_cases() - is to do its best to select what tests +# to run, dig out options, if needs restart etc. +# run_testcase() - is to run a single testcase, and follow the +# logic set in both above. No, or rare file +# system operations. If a test seems complex, +# it should probably not be here. +# +# A nice way to trace the execution of this script while debugging +# is to use the Devel::Trace package found at +# "http://www.plover.com/~mjd/perl/Trace/" and run this script like +# "perl -d:Trace mysql-test-run.pl" +# + + +use lib "lib/v1/"; + +$Devel::Trace::TRACE= 0; # Don't trace boring init stuff + +#require 5.6.1; +use File::Path; +use File::Basename; +use File::Copy; +use File::Temp qw /tempdir/; +use File::Spec::Functions qw /splitdir/; +use Cwd; +use Getopt::Long; +use IO::Socket; +use IO::Socket::INET; +use strict; +use warnings; + +select(STDOUT); +$| = 1; # Automatically flush STDOUT + +our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl +our $glob_cygwin_perl= ($^O eq "cygwin"); # Cygwin Perl +our $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); + +require "lib/v1/mtr_cases.pl"; +require "lib/v1/mtr_process.pl"; +require "lib/v1/mtr_timer.pl"; +require "lib/v1/mtr_io.pl"; +require "lib/v1/mtr_gcov.pl"; +require "lib/v1/mtr_gprof.pl"; +require "lib/v1/mtr_report.pl"; +require "lib/v1/mtr_match.pl"; +require "lib/v1/mtr_misc.pl"; +require "lib/v1/mtr_stress.pl"; +require "lib/v1/mtr_unique.pl"; + +$Devel::Trace::TRACE= 1; + +############################################################################## +# +# Default settings +# +############################################################################## + +# Misc global variables +our $mysql_version_id; +our $glob_mysql_test_dir= undef; +our $glob_mysql_bench_dir= undef; +our $glob_scriptname= undef; +our $glob_timers= undef; +our $glob_use_embedded_server= 0; +our @glob_test_mode; + +our $glob_basedir; +our $glob_bindir; + +our $path_charsetsdir; +our $path_client_bindir; +our $path_client_libdir; +our $path_share; +our $path_language; +our $path_timefile; +our $path_snapshot; +our $path_mysqltest_log; +our $path_current_test_log; + +our $opt_vardir; # A path but set directly on cmd line +our $path_vardir_trace; # unix formatted opt_vardir for trace files +our $opt_tmpdir; # A path but set directly on cmd line + +# Visual Studio produces executables in different sub-directories based on the +# configuration used to build them. To make life easier, an environment +# variable or command-line option may be specified to control which set of +# executables will be used by the test suite. +our $multiconfig = $ENV{'MTR_VS_CONFIG'}; + +our $default_vardir; + +our $opt_usage; +our $opt_list_options; +our $opt_suites; +our $opt_suites_default= "main,binlog,rpl,maria"; # Default suites to run +our $opt_script_debug= 0; # Script debugging, enable with --script-debug +our $opt_verbose= 0; # Verbose output, enable with --verbose + +our $exe_master_mysqld; +our $exe_mysql; +our $exe_mysqladmin; +our $exe_mysql_upgrade; +our $exe_mysqlbinlog; +our $exe_mysql_client_test; +our $exe_bug25714; +our $exe_mysqld; +our $exe_mysqlcheck; +our $exe_mysqldump; +our $exe_mysqlslap; +our $exe_mysqlimport; +our $exe_mysqlshow; +our $file_mysql_fix_privilege_tables; +our $exe_mysqltest; +our $exe_slave_mysqld; +our $exe_my_print_defaults; +our $exe_perror; +our $lib_udf_example; +our $lib_example_plugin; +our $exe_libtool; + +our $opt_bench= 0; +our $opt_small_bench= 0; +our $opt_big_test= 0; + +our @opt_combinations; +our $opt_skip_combination; + +our @opt_extra_mysqld_opt; +our @opt_extra_mysqltest_opt; + +our $opt_compress; +our $opt_ssl; +our $opt_skip_ssl; +our $opt_ssl_supported; +our $opt_ps_protocol; +our $opt_sp_protocol; +our $opt_cursor_protocol; +our $opt_view_protocol; + +our $opt_debug; +our $opt_do_test; +our @opt_cases; # The test cases names in argv +our $opt_embedded_server; + +our $opt_extern= 0; +our $opt_socket; + +our $opt_fast; +our $opt_force; +our $opt_reorder= 0; +our $opt_enable_disabled; +our $opt_mem= $ENV{'MTR_MEM'}; + +our $opt_gcov; +our $opt_gcov_err; +our $opt_gcov_msg; + +our $glob_debugger= 0; +our $opt_gdb; +our $opt_client_gdb; +our $opt_ddd; +our $opt_client_ddd; +our $opt_manual_gdb; +our $opt_manual_ddd; +our $opt_manual_debug; +our $opt_mtr_build_thread=0; +our $opt_debugger; +our $opt_client_debugger; + +our $opt_gprof; +our $opt_gprof_dir; +our $opt_gprof_master; +our $opt_gprof_slave; + +our $master; +our $slave; + +our $opt_master_myport; +our $opt_slave_myport; + +our $opt_record; +my $opt_report_features; +our $opt_check_testcases; +our $opt_mark_progress; + +our $opt_skip_rpl; +our $max_slave_num= 0; +our $max_master_num= 1; +our $use_innodb; +our $opt_skip_test; + +our $opt_sleep; + +our $opt_testcase_timeout; +our $opt_suite_timeout; +my $default_testcase_timeout= 15; # 15 min max +my $default_suite_timeout= 300; # 5 hours max + +our $opt_start_and_exit; +our $opt_start_dirty; +our $opt_start_from; + +our $opt_strace_client; + +our $opt_timer= 1; + +our $opt_user; + +my $opt_valgrind= 0; +my $opt_valgrind_mysqld= 0; +my $opt_valgrind_mysqltest= 0; +my @default_valgrind_args= ("--show-reachable=yes"); +my @valgrind_args; +my $opt_valgrind_path; +my $opt_callgrind; + +our $opt_stress= ""; +our $opt_stress_suite= "main"; +our $opt_stress_mode= "random"; +our $opt_stress_threads= 5; +our $opt_stress_test_count= 0; +our $opt_stress_loop_count= 0; +our $opt_stress_test_duration= 0; +our $opt_stress_init_file= ""; +our $opt_stress_test_file= ""; + +our $opt_warnings; + +our $opt_skip_master_binlog= 0; +our $opt_skip_slave_binlog= 0; + +our $path_sql_dir; + +our @data_dir_lst; + +our $used_binlog_format; +our $used_default_engine; +our $debug_compiled_binaries; + +our %mysqld_variables; + +my $source_dist= 0; + +our $opt_max_save_core= 5; +my $num_saved_cores= 0; # Number of core files saved in vardir/log/ so far. + +###################################################################### +# +# Function declarations +# +###################################################################### + +sub main (); +sub initial_setup (); +sub command_line_setup (); +sub set_mtr_build_thread_ports($); +sub datadir_list_setup (); +sub executable_setup (); +sub environment_setup (); +sub kill_running_servers (); +sub remove_stale_vardir (); +sub setup_vardir (); +sub check_ssl_support ($); +sub check_running_as_root(); +sub mysqld_wait_started($); +sub run_benchmarks ($); +sub initialize_servers (); +sub mysql_install_db (); +sub install_db ($$); +sub copy_install_db ($$); +sub run_testcase ($); +sub run_testcase_stop_servers ($$$); +sub run_testcase_start_servers ($); +sub run_testcase_check_skip_test($); +sub report_failure_and_restart ($); +sub do_before_start_master ($); +sub do_before_start_slave ($); +sub mysqld_start ($$$); +sub mysqld_arguments ($$$$); +sub stop_all_servers (); +sub run_mysqltest ($); +sub usage ($); + + +###################################################################### +# +# Main program +# +###################################################################### + +main(); + +sub main () { + + command_line_setup(); + + check_ssl_support(\%mysqld_variables); + check_debug_support(\%mysqld_variables); + + executable_setup(); + + environment_setup(); + signal_setup(); + + if ( $opt_gcov ) + { + gcov_prepare(); + } + + if ( $opt_gprof ) + { + gprof_prepare(); + } + + if ( $opt_bench ) + { + initialize_servers(); + run_benchmarks(shift); # Shift what? Extra arguments?! + } + elsif ( $opt_stress ) + { + initialize_servers(); + run_stress_test() + } + else + { + # Figure out which tests we are going to run + if (!$opt_suites) + { + $opt_suites= $opt_suites_default; + } + + my $tests= collect_test_cases($opt_suites); + + my ($need_debug); + foreach my $test (@$tests) + { + next if $test->{skip}; + + if (!$opt_extern) + { + $need_debug||=$test->{need_debug}; + + # Count max number of slaves used by a test case + if ( $test->{slave_num} > $max_slave_num) { + $max_slave_num= $test->{slave_num}; + mtr_error("Too many slaves") if $max_slave_num > 3; + } + + # Count max number of masters used by a test case + if ( $test->{master_num} > $max_master_num) { + $max_master_num= $test->{master_num}; + mtr_error("Too many masters") if $max_master_num > 2; + mtr_error("Too few masters") if $max_master_num < 1; + } + } + $use_innodb||= $test->{'innodb_test'}; + } + + if ( !$need_debug && !$opt_debug) + { + $opt_debug=0; + } + + initialize_servers(); + + if ( $opt_report_features ) { + run_report_features(); + } + + run_tests($tests); + } + + mtr_exit(0); +} + +############################################################################## +# +# Default settings +# +############################################################################## + +# +# When an option is no longer used by this program, it must be explicitly +# ignored or else it will be passed through to mysqld. GetOptions will call +# this subroutine once for each such option on the command line. See +# Getopt::Long documentation. +# + +sub warn_about_removed_option { + my ($option, $value, $hash_value) = @_; + + warn "WARNING: This option is no longer used, and is ignored: --$option\n"; +} + +sub command_line_setup () { + + # These are defaults for things that are set on the command line + + my $opt_comment; + + # Magic number -69.4 results in traditional test ports starting from 9306. + set_mtr_build_thread_ports(-69.4); + + # If so requested, we try to avail ourselves of a unique build thread number. + if ( $ENV{'MTR_BUILD_THREAD'} ) { + if ( lc($ENV{'MTR_BUILD_THREAD'}) eq 'auto' ) { + print "Requesting build thread... "; + $ENV{'MTR_BUILD_THREAD'} = mtr_require_unique_id_and_wait("/tmp/mysql-test-ports", 200, 299); + print "got ".$ENV{'MTR_BUILD_THREAD'}."\n"; + } + } + + if ( $ENV{'MTR_BUILD_THREAD'} ) + { + set_mtr_build_thread_ports($ENV{'MTR_BUILD_THREAD'}); + } + + # This is needed for test log evaluation in "gen-build-status-page" + # in all cases where the calling tool does not log the commands + # directly before it executes them, like "make test-force-pl" in RPM builds. + print "Logging: $0 ", join(" ", @ARGV), "\n"; + + # Read the command line + # Note: Keep list, and the order, in sync with usage at end of this file + + # Options that are no longer used must still be processed, because all + # unprocessed options are passed directly to mysqld. The user will be + # warned that the option is being ignored. + # + # Put the complete option string here. For example, to remove the --suite + # option, remove it from GetOptions() below and put 'suite|suites=s' here. + my @removed_options = ( + ); + + Getopt::Long::Configure("pass_through"); + my %options=( + # Control what engine/variation to run + 'embedded-server' => \$opt_embedded_server, + 'ps-protocol' => \$opt_ps_protocol, + 'sp-protocol' => \$opt_sp_protocol, + 'view-protocol' => \$opt_view_protocol, + 'cursor-protocol' => \$opt_cursor_protocol, + 'ssl|with-openssl' => \$opt_ssl, + 'skip-ssl' => \$opt_skip_ssl, + 'compress' => \$opt_compress, + 'bench' => \$opt_bench, + 'small-bench' => \$opt_small_bench, + 'vs-config' => \$multiconfig, + + # Control what test suites or cases to run + 'force' => \$opt_force, + 'skip-master-binlog' => \$opt_skip_master_binlog, + 'skip-slave-binlog' => \$opt_skip_slave_binlog, + 'do-test=s' => \$opt_do_test, + 'start-from=s' => \$opt_start_from, + 'suite|suites=s' => \$opt_suites, + 'skip-rpl' => \$opt_skip_rpl, + 'skip-test=s' => \$opt_skip_test, + 'big-test' => \$opt_big_test, + 'combination=s' => \@opt_combinations, + 'skip-combination' => \$opt_skip_combination, + + # Specify ports + 'master_port=i' => \$opt_master_myport, + 'slave_port=i' => \$opt_slave_myport, + 'mtr-build-thread=i' => \$opt_mtr_build_thread, + + # Test case authoring + 'record' => \$opt_record, + 'check-testcases' => \$opt_check_testcases, + 'mark-progress' => \$opt_mark_progress, + + # Extra options used when starting mysqld + 'mysqld=s' => \@opt_extra_mysqld_opt, + + # Extra options used when starting mysqld + 'mysqltest=s' => \@opt_extra_mysqltest_opt, + + # Run test on running server + 'extern' => \$opt_extern, + + # Debugging + 'gdb' => \$opt_gdb, + 'client-gdb' => \$opt_client_gdb, + 'manual-gdb' => \$opt_manual_gdb, + 'manual-debug' => \$opt_manual_debug, + 'ddd' => \$opt_ddd, + 'client-ddd' => \$opt_client_ddd, + 'manual-ddd' => \$opt_manual_ddd, + 'debugger=s' => \$opt_debugger, + 'client-debugger=s' => \$opt_client_debugger, + 'strace-client' => \$opt_strace_client, + 'master-binary=s' => \$exe_master_mysqld, + 'slave-binary=s' => \$exe_slave_mysqld, + 'max-save-core=i' => \$opt_max_save_core, + + # Coverage, profiling etc + 'gcov' => \$opt_gcov, + 'gprof' => \$opt_gprof, + 'valgrind|valgrind-all' => \$opt_valgrind, + 'valgrind-mysqltest' => \$opt_valgrind_mysqltest, + 'valgrind-mysqld' => \$opt_valgrind_mysqld, + 'valgrind-options=s' => sub { + my ($opt, $value)= @_; + # Deprecated option unless it's what we know pushbuild uses + if ($value eq "--gen-suppressions=all --show-reachable=yes") { + push(@valgrind_args, $_) for (split(' ', $value)); + return; + } + die("--valgrind-options=s is deprecated. Use ", + "--valgrind-option=s, to be specified several", + " times if necessary"); + }, + 'valgrind-option=s' => \@valgrind_args, + 'valgrind-path=s' => \$opt_valgrind_path, + 'callgrind' => \$opt_callgrind, + + # Stress testing + 'stress' => \$opt_stress, + 'stress-suite=s' => \$opt_stress_suite, + 'stress-threads=i' => \$opt_stress_threads, + 'stress-test-file=s' => \$opt_stress_test_file, + 'stress-init-file=s' => \$opt_stress_init_file, + 'stress-mode=s' => \$opt_stress_mode, + 'stress-loop-count=i' => \$opt_stress_loop_count, + 'stress-test-count=i' => \$opt_stress_test_count, + 'stress-test-duration=i' => \$opt_stress_test_duration, + + # Directories + 'tmpdir=s' => \$opt_tmpdir, + 'vardir=s' => \$opt_vardir, + 'benchdir=s' => \$glob_mysql_bench_dir, + 'mem' => \$opt_mem, + 'client-bindir=s' => \$path_client_bindir, + 'client-libdir=s' => \$path_client_libdir, + + # Misc + 'report-features' => \$opt_report_features, + 'comment=s' => \$opt_comment, + 'debug' => \$opt_debug, + 'fast' => \$opt_fast, + 'reorder' => \$opt_reorder, + 'enable-disabled' => \$opt_enable_disabled, + 'script-debug' => \$opt_script_debug, + 'verbose' => \$opt_verbose, + 'sleep=i' => \$opt_sleep, + 'socket=s' => \$opt_socket, + 'start-dirty' => \$opt_start_dirty, + 'start-and-exit' => \$opt_start_and_exit, + 'timer!' => \$opt_timer, + 'user=s' => \$opt_user, + 'testcase-timeout=i' => \$opt_testcase_timeout, + 'suite-timeout=i' => \$opt_suite_timeout, + 'warnings|log-warnings' => \$opt_warnings, + + # Options which are no longer used + (map { $_ => \&warn_about_removed_option } @removed_options), + + 'help|h' => \$opt_usage, + 'list-options' => \$opt_list_options, + ); + + GetOptions(%options) or usage("Can't read options"); + + usage("") if $opt_usage; + list_options(\%options) if $opt_list_options; + + $glob_scriptname= basename($0); + + if ($opt_mtr_build_thread != 0) + { + set_mtr_build_thread_ports($opt_mtr_build_thread) + } + elsif ($ENV{'MTR_BUILD_THREAD'}) + { + $opt_mtr_build_thread= $ENV{'MTR_BUILD_THREAD'}; + } + + # We require that we are in the "mysql-test" directory + # to run mysql-test-run + if (! -f $glob_scriptname) + { + mtr_error("Can't find the location for the mysql-test-run script\n" . + "Go to the mysql-test directory and execute the script " . + "as follows:\n./$glob_scriptname"); + } + + if ( -d "../sql" ) + { + $source_dist= 1; + } + + # Find the absolute path to the test directory + $glob_mysql_test_dir= cwd(); + if ( $glob_cygwin_perl ) + { + # Windows programs like 'mysqld' needs Windows paths + $glob_mysql_test_dir= `cygpath -m "$glob_mysql_test_dir"`; + chomp($glob_mysql_test_dir); + } + if (defined $ENV{MTR_BINDIR}) + { + $default_vardir= "$ENV{MTR_BINDIR}/mysql-test/var"; + } + else + { + $default_vardir= "$glob_mysql_test_dir/var"; + } + + # In most cases, the base directory we find everything relative to, + # is the parent directory of the "mysql-test" directory. For source + # distributions, TAR binary distributions and some other packages. + $glob_basedir= dirname($glob_mysql_test_dir); + + $glob_bindir= $ENV{'MTR_BINDIR'} || $glob_basedir; + # In the RPM case, binaries and libraries are installed in the + # default system locations, instead of having our own private base + # directory. And we install "/usr/share/mysql-test". Moving up one + # more directory relative to "mysql-test" gives us a usable base + # directory for RPM installs. + if ( ! $source_dist and ! -d "$glob_basedir/bin" ) + { + $glob_basedir= dirname($glob_basedir); + } + + # Expect mysql-bench to be located adjacent to the source tree, by default + $glob_mysql_bench_dir= "$glob_basedir/../mysql-bench" + unless defined $glob_mysql_bench_dir; + $glob_mysql_bench_dir= undef + unless -d $glob_mysql_bench_dir; + + + $glob_timers= mtr_init_timers(); + + # -------------------------------------------------------------------------- + # Embedded server flag + # -------------------------------------------------------------------------- + if ( $opt_embedded_server ) + { + $glob_use_embedded_server= 1; + # Add the location for libmysqld.dll to the path. + if ( $glob_win32 ) + { + my $lib_mysqld= + mtr_path_exists(vs_config_dirs('libmysqld','')); + $lib_mysqld= $glob_cygwin_perl ? ":".`cygpath "$lib_mysqld"` + : ";".$lib_mysqld; + chomp($lib_mysqld); + $ENV{'PATH'}="$ENV{'PATH'}".$lib_mysqld; + } + + push(@glob_test_mode, "embedded"); + $opt_skip_rpl= 1; # We never run replication with embedded + $opt_skip_ssl= 1; # Turn off use of SSL + + # Turn off use of bin log + push(@opt_extra_mysqld_opt, "--skip-log-bin"); + + if ( $opt_extern ) + { + mtr_error("Can't use --extern with --embedded-server"); + } + } + + # + # Find the mysqld executable to be able to find the mysqld version + # number as early as possible + # + + # Look for the client binaries directory + if ($path_client_bindir) + { + # --client-bindir=path set on command line, check that the path exists + $path_client_bindir= mtr_path_exists($path_client_bindir); + } + else + { + $path_client_bindir= mtr_path_exists("$glob_bindir/client_release", + "$glob_bindir/client_debug", + vs_config_dirs('client', ''), + "$glob_bindir/client", + "$glob_bindir/bin"); + } + + # Look for language files and charsetsdir, use same share + $path_share= mtr_path_exists("$glob_bindir/share/mysql", + "$glob_bindir/sql/share", + "$glob_bindir/share"); + + $path_language= mtr_path_exists("$path_share"); + $path_charsetsdir = mtr_path_exists("$glob_basedir/share/mysql/charsets", + "$glob_basedir/sql/share/charsets", + "$glob_basedir/share/charsets"); + + if (!$opt_extern) + { + $exe_mysqld= mtr_exe_exists (vs_config_dirs('sql', 'mysqld'), + vs_config_dirs('sql', 'mysqld-debug'), + "$glob_bindir/sql/mysqld", + "$path_client_bindir/mysqld-max-nt", + "$path_client_bindir/mysqld-max", + "$path_client_bindir/mysqld-nt", + "$path_client_bindir/mysqld", + "$path_client_bindir/mysqld-debug", + "$path_client_bindir/mysqld-max", + "$glob_bindir/libexec/mysqld", + "$glob_bindir/bin/mariadbd", + "$glob_bindir/sbin/mariadbd"); + + # Use the mysqld found above to find out what features are available + collect_mysqld_features(); + } + else + { + $mysqld_variables{'port'}= 3306; + $mysqld_variables{'master-port'}= 3306; + } + + if ( $opt_comment ) + { + print "\n"; + print '#' x 78, "\n"; + print "# $opt_comment\n"; + print '#' x 78, "\n\n"; + } + + foreach my $arg ( @ARGV ) + { + if ( $arg =~ /^--skip-/ ) + { + push(@opt_extra_mysqld_opt, $arg); + } + elsif ( $arg =~ /^--$/ ) + { + # It is an effect of setting 'pass_through' in option processing + # that the lone '--' separating options from arguments survives, + # simply ignore it. + } + elsif ( $arg =~ /^-/ ) + { + usage("Invalid option \"$arg\""); + } + else + { + push(@opt_cases, $arg); + } + } + + # -------------------------------------------------------------------------- + # Find out type of logging that are being used + # -------------------------------------------------------------------------- + if (!$opt_extern && $mysql_version_id >= 50100 ) + { + foreach my $arg ( @opt_extra_mysqld_opt ) + { + if ( $arg =~ /binlog[-_]format=(\S+)/ ) + { + $used_binlog_format= $1; + } + } + if (defined $used_binlog_format) + { + mtr_report("Using binlog format '$used_binlog_format'"); + } + else + { + mtr_report("Using dynamic switching of binlog format"); + } + } + + + # -------------------------------------------------------------------------- + # Find out default storage engine being used(if any) + # -------------------------------------------------------------------------- + foreach my $arg ( @opt_extra_mysqld_opt ) + { + if ( $arg =~ /default-storage-engine=(\S+)/ ) + { + $used_default_engine= $1; + } + } + mtr_report("Using default engine '$used_default_engine'") + if defined $used_default_engine; + + if ($glob_win32 and defined $opt_mem) { + mtr_report("--mem not supported on Windows, ignored"); + $opt_mem= undef; + } + + # -------------------------------------------------------------------------- + # Check if we should speed up tests by trying to run on tmpfs + # -------------------------------------------------------------------------- + if ( defined $opt_mem ) + { + mtr_error("Can't use --mem and --vardir at the same time ") + if $opt_vardir; + mtr_error("Can't use --mem and --tmpdir at the same time ") + if $opt_tmpdir; + + # Search through list of locations that are known + # to be "fast disks" to list to find a suitable location + # Use --mem=<dir> as first location to look. + my @tmpfs_locations= ($opt_mem, "/dev/shm", "/tmp"); + + foreach my $fs (@tmpfs_locations) + { + if ( -d $fs ) + { + mtr_report("Using tmpfs in $fs"); + $opt_mem= "$fs/var"; + $opt_mem .= $opt_mtr_build_thread if $opt_mtr_build_thread; + last; + } + } + } + + # -------------------------------------------------------------------------- + # Set the "var/" directory, as it is the base for everything else + # -------------------------------------------------------------------------- + if ( ! $opt_vardir ) + { + $opt_vardir= $default_vardir; + } + elsif ( $mysql_version_id < 50000 and + $opt_vardir ne $default_vardir) + { + # Version 4.1 and --vardir was specified + # Only supported as a symlink from var/ + # by setting up $opt_mem that symlink will be created + if ( ! $glob_win32 ) + { + # Only platforms that have native symlinks can use the vardir trick + $opt_mem= $opt_vardir; + mtr_report("Using 4.1 vardir trick"); + } + + $opt_vardir= $default_vardir; + } + + $path_vardir_trace= $opt_vardir; + # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/... + $path_vardir_trace=~ s/^\w://; + + # We make the path absolute, as the server will do a chdir() before usage + unless ( $opt_vardir =~ m,^/, or + ($glob_win32 and $opt_vardir =~ m,^[a-z]:/,i) ) + { + # Make absolute path, relative test dir + $opt_vardir= "$glob_mysql_test_dir/$opt_vardir"; + } + + # -------------------------------------------------------------------------- + # Set tmpdir + # -------------------------------------------------------------------------- + $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; + $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any + + # -------------------------------------------------------------------------- + # Record flag + # -------------------------------------------------------------------------- + if ( $opt_record and ! @opt_cases ) + { + mtr_error("Will not run in record mode without a specific test case"); + } + + if ( $opt_record ) + { + $opt_skip_combination = 1; + } + + # -------------------------------------------------------------------------- + # ps protcol flag + # -------------------------------------------------------------------------- + if ( $opt_ps_protocol ) + { + push(@glob_test_mode, "ps-protocol"); + } + + # -------------------------------------------------------------------------- + # Bench flags + # -------------------------------------------------------------------------- + if ( $opt_small_bench ) + { + $opt_bench= 1; + } + + # -------------------------------------------------------------------------- + # Big test flags + # -------------------------------------------------------------------------- + if ( $opt_big_test ) + { + $ENV{'BIG_TEST'}= 1; + } + + # -------------------------------------------------------------------------- + # Gcov flag + # -------------------------------------------------------------------------- + if ( $opt_gcov and ! $source_dist ) + { + mtr_error("Coverage test needs the source - please use source dist"); + } + + # -------------------------------------------------------------------------- + # Check debug related options + # -------------------------------------------------------------------------- + if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd || + $opt_manual_gdb || $opt_manual_ddd || $opt_manual_debug || + $opt_debugger || $opt_client_debugger ) + { + # Indicate that we are using debugger + $glob_debugger= 1; + if ( $opt_extern ) + { + mtr_error("Can't use --extern when using debugger"); + } + } + + # -------------------------------------------------------------------------- + # Check if special exe was selected for master or slave + # -------------------------------------------------------------------------- + $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; + $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; + + # -------------------------------------------------------------------------- + # Check valgrind arguments + # -------------------------------------------------------------------------- + if ( $opt_valgrind or $opt_valgrind_path or @valgrind_args) + { + mtr_report("Turning on valgrind for all executables"); + $opt_valgrind= 1; + $opt_valgrind_mysqld= 1; + $opt_valgrind_mysqltest= 1; + } + elsif ( $opt_valgrind_mysqld ) + { + mtr_report("Turning on valgrind for mysqld(s) only"); + $opt_valgrind= 1; + } + elsif ( $opt_valgrind_mysqltest ) + { + mtr_report("Turning on valgrind for mysqltest and mysql_client_test only"); + $opt_valgrind= 1; + } + + if ( $opt_callgrind ) + { + mtr_report("Turning on valgrind with callgrind for mysqld(s)"); + $opt_valgrind= 1; + $opt_valgrind_mysqld= 1; + + # Set special valgrind options unless options passed on command line + push(@valgrind_args, "--trace-children=yes") + unless @valgrind_args; + } + + if ( $opt_valgrind ) + { + # Set valgrind_options to default unless already defined + push(@valgrind_args, @default_valgrind_args) + unless @valgrind_args; + + mtr_report("Running valgrind with options \"", + join(" ", @valgrind_args), "\""); + } + + if ( ! $opt_testcase_timeout ) + { + $opt_testcase_timeout= + $ENV{MTR_TESTCASE_TIMEOUT} || $default_testcase_timeout; + $opt_testcase_timeout*= 10 if $opt_valgrind; + $opt_testcase_timeout*= 10 if ($opt_debug and $glob_win32); + } + + if ( ! $opt_suite_timeout ) + { + $opt_suite_timeout= + $ENV{MTR_SUITE_TIMEOUT} || $default_suite_timeout; + $opt_suite_timeout*= 6 if $opt_valgrind; + $opt_suite_timeout*= 6 if ($opt_debug and $glob_win32); + } + + if ( ! $opt_user ) + { + if ( $opt_extern ) + { + $opt_user= "test"; + } + else + { + $opt_user= "root"; # We want to do FLUSH xxx commands + } + } + + # On QNX, /tmp/dir/master.sock and /tmp/dir//master.sock seem to be + # considered different, so avoid the extra slash (/) in the socket + # paths. + my $sockdir = $opt_tmpdir; + $sockdir =~ s|/+$||; + + # On some operating systems, there is a limit to the length of a + # UNIX domain socket's path far below PATH_MAX, so try to avoid long + # socket path names. + $sockdir = tempdir(CLEANUP => 0) if ( length($sockdir) >= 70 ); + + $master->[0]= + { + pid => 0, + type => "master", + idx => 0, + path_myddir => "$opt_vardir/master-data", + path_myerr => "$opt_vardir/log/master.err", + path_pid => "$opt_vardir/run/master.pid", + path_sock => "$sockdir/master.sock", + port => $opt_master_myport, + start_timeout => 400, # enough time create innodb tables + start_opts => [], + }; + + $master->[1]= + { + pid => 0, + type => "master", + idx => 1, + path_myddir => "$opt_vardir/master1-data", + path_myerr => "$opt_vardir/log/master1.err", + path_pid => "$opt_vardir/run/master1.pid", + path_sock => "$sockdir/master1.sock", + port => $opt_master_myport + 1, + start_timeout => 400, # enough time create innodb tables + start_opts => [], + }; + + $slave->[0]= + { + pid => 0, + type => "slave", + idx => 0, + path_myddir => "$opt_vardir/slave-data", + path_myerr => "$opt_vardir/log/slave.err", + path_pid => "$opt_vardir/run/slave.pid", + path_sock => "$sockdir/slave.sock", + port => $opt_slave_myport, + start_timeout => 400, + + start_opts => [], + }; + + $slave->[1]= + { + pid => 0, + type => "slave", + idx => 1, + path_myddir => "$opt_vardir/slave1-data", + path_myerr => "$opt_vardir/log/slave1.err", + path_pid => "$opt_vardir/run/slave1.pid", + path_sock => "$sockdir/slave1.sock", + port => $opt_slave_myport + 1, + start_timeout => 300, + start_opts => [], + }; + + $slave->[2]= + { + pid => 0, + type => "slave", + idx => 2, + path_myddir => "$opt_vardir/slave2-data", + path_myerr => "$opt_vardir/log/slave2.err", + path_pid => "$opt_vardir/run/slave2.pid", + path_sock => "$sockdir/slave2.sock", + port => $opt_slave_myport + 2, + start_timeout => 300, + start_opts => [], + }; + + # -------------------------------------------------------------------------- + # extern + # -------------------------------------------------------------------------- + if ( $opt_extern ) + { + # Turn off features not supported when running with extern server + $opt_skip_rpl= 1; + + # Setup master->[0] with the settings for the extern server + $master->[0]->{'path_sock'}= $opt_socket ? $opt_socket : "/tmp/mysql.sock"; + mtr_report("Using extern server at '$master->[0]->{path_sock}'"); + } + else + { + mtr_error("--socket can only be used in combination with --extern") + if $opt_socket; + } + + + + $path_timefile= "$opt_vardir/log/mysqltest-time"; + $path_mysqltest_log= "$opt_vardir/log/mysqltest.log"; + $path_current_test_log= "$opt_vardir/log/current_test"; + + $path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/"; +} + +# +# To make it easier for different devs to work on the same host, +# an environment variable can be used to control all ports. A small +# number is to be used, 0 - 16 or similar. +# +# Note the MASTER_MYPORT has to be set the same in all 4.x and 5.x +# versions of this script, else a 4.0 test run might conflict with a +# 5.1 test run, even if different MTR_BUILD_THREAD is used. This means +# all port numbers might not be used in this version of the script. +# +# Also note the limitation of ports we are allowed to hand out. This +# differs between operating systems and configuration, see +# http://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html +# But a fairly safe range seems to be 5001 - 32767 +# + +sub set_mtr_build_thread_ports($) { + my $mtr_build_thread= shift; + + if ( lc($mtr_build_thread) eq 'auto' ) { + print "Requesting build thread... "; + $ENV{'MTR_BUILD_THREAD'} = $mtr_build_thread = mtr_require_unique_id_and_wait("/tmp/mysql-test-ports", 200, 299); + print "got ".$mtr_build_thread."\n"; + } + + # Up to two masters, up to three slaves + # A magic value in command_line_setup depends on these equations. + $opt_master_myport= $mtr_build_thread * 10 + 10000; # and 1 + $opt_slave_myport= $opt_master_myport + 2; # and 3 4 + + if ( $opt_master_myport < 5001 or $opt_master_myport + 10 >= 32767 ) + { + mtr_error("MTR_BUILD_THREAD number results in a port", + "outside 5001 - 32767", + "($opt_master_myport - $opt_master_myport + 10)"); + } +} + + +sub datadir_list_setup () { + + # Make a list of all data_dirs + for (my $idx= 0; $idx < $max_master_num; $idx++) + { + push(@data_dir_lst, $master->[$idx]->{'path_myddir'}); + } + + for (my $idx= 0; $idx < $max_slave_num; $idx++) + { + push(@data_dir_lst, $slave->[$idx]->{'path_myddir'}); + } +} + + +############################################################################## +# +# Set paths to various executable programs +# +############################################################################## + + +sub collect_mysqld_features () { + my $found_variable_list_start= 0; + my $tmpdir; + if ( $opt_tmpdir ) { + # Use the requested tmpdir + mkpath($opt_tmpdir) if (! -d $opt_tmpdir); + $tmpdir= $opt_tmpdir; + } + else { + $tmpdir= tempdir(CLEANUP => 0); # Directory removed by this function + } + + # + # Execute "mysqld --help --verbose" to get a list + # list of all features and settings + # + # --no-defaults and --skip-grant-tables are to avoid loading + # system-wide configs and plugins + # + # --datadir must exist, mysqld will chdir into it + # + my $list= `$exe_mysqld --no-defaults --datadir=$tmpdir --lc-messages-dir=$path_language --skip-grant-tables --verbose --help`; + + foreach my $line (split('\n', $list)) + { + # First look for version + if ( !$mysql_version_id ) + { + # Look for version + my $exe_name= basename($exe_mysqld); + mtr_verbose("exe_name: $exe_name"); + if ( $line =~ /^\S*$exe_name\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) + { + #print "Major: $1 Minor: $2 Build: $3\n"; + $mysql_version_id= $1*10000 + $2*100 + $3; + #print "mysql_version_id: $mysql_version_id\n"; + mtr_report("MySQL Version $1.$2.$3"); + } + } + else + { + if (!$found_variable_list_start) + { + # Look for start of variables list + if ( $line =~ /[\-]+\s[\-]+/ ) + { + $found_variable_list_start= 1; + } + } + else + { + # Put variables into hash + if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ ) + { + # print "$1=\"$2\"\n"; + $mysqld_variables{$1}= $2; + } + else + { + # The variable list is ended with a blank line + if ( $line =~ /^[\s]*$/ ) + { + last; + } + else + { + # Send out a warning, we should fix the variables that has no + # space between variable name and it's value + # or should it be fixed width column parsing? It does not + # look like that in function my_print_variables in my_getopt.c + mtr_warning("Could not parse variable list line : $line"); + } + } + } + } + } + rmtree($tmpdir) if (!$opt_tmpdir); + mtr_error("Could not find version of MySQL") unless $mysql_version_id; + mtr_error("Could not find variabes list") unless $found_variable_list_start; + +} + + +sub run_query($$) { + my ($mysqld, $query)= @_; + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--port=%d", $mysqld->{'port'}); + mtr_add_arg($args, "--socket=%s", $mysqld->{'path_sock'}); + mtr_add_arg($args, "--silent"); # Tab separated output + mtr_add_arg($args, "-e '%s'", $query); + + my $cmd= "$exe_mysql " . join(' ', @$args); + mtr_verbose("cmd: $cmd"); + return `$cmd`; +} + + +sub collect_mysqld_features_from_running_server () +{ + my $list= run_query($master->[0], "use mysql; SHOW VARIABLES"); + + foreach my $line (split('\n', $list)) + { + # Put variables into hash + if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ ) + { + print "$1=\"$2\"\n"; + $mysqld_variables{$1}= $2; + } + } +} + +sub executable_setup () { + + # + # Check if libtool is available in this distribution/clone + # we need it when valgrinding or debugging non installed binary + # Otherwise valgrind will valgrind the libtool wrapper or bash + # and gdb will not find the real executable to debug + # + if ( -x "../libtool") + { + $exe_libtool= "../libtool"; + if ($opt_valgrind or $glob_debugger) + { + mtr_report("Using \"$exe_libtool\" when running valgrind or debugger"); + } + } + + # Look for my_print_defaults + $exe_my_print_defaults= + mtr_exe_exists(vs_config_dirs('extra', 'my_print_defaults'), + "$path_client_bindir/my_print_defaults", + "$glob_bindir/extra/my_print_defaults"); + + # Look for perror + $exe_perror= mtr_exe_exists(vs_config_dirs('extra', 'perror'), + "$glob_bindir/extra/perror", + "$path_client_bindir/perror"); + + # Look for the client binaries + $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); + $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); + $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); + $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); + $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); + $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); + $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + + if (!$opt_extern) + { + # Look for SQL scripts directory + if ( mtr_file_exists("$path_share/mysql_system_tables.sql") ne "") + { + # The SQL scripts are in path_share + $path_sql_dir= $path_share; + } + else + { + $path_sql_dir= mtr_path_exists("$glob_basedir/share", + "$glob_basedir/scripts"); + } + + if ( $mysql_version_id >= 50100 ) + { + $exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap"); + } + if ( $mysql_version_id >= 50000 and !$glob_use_embedded_server ) + { + $exe_mysql_upgrade= mtr_exe_exists("$path_client_bindir/mysql_upgrade") + } + else + { + $exe_mysql_upgrade= ""; + } + + # Look for mysql_fix_privilege_tables.sql script + $file_mysql_fix_privilege_tables= + mtr_file_exists("$glob_basedir/scripts/mysql_fix_privilege_tables.sql", + "$glob_basedir/share/mysql_fix_privilege_tables.sql", + "$glob_basedir/share/mysql/mysql_fix_privilege_tables.sql"); + + # Look for the udf_example library + $lib_udf_example= + mtr_file_exists(vs_config_dirs('sql', 'udf_example.dll'), + "$glob_bindir/sql/.libs/udf_example.so",); + + # Look for the ha_example library + $lib_example_plugin= + mtr_file_exists(vs_config_dirs('storage/example', 'ha_example.dll'), + "$glob_bindir/storage/example/.libs/ha_example.so",); + + } + + # Look for mysqltest executable + if ( $glob_use_embedded_server ) + { + $exe_mysqltest= + mtr_exe_exists(vs_config_dirs('libmysqld/examples','mysqltest_embedded'), + "$glob_bindir/libmysqld/examples/mysqltest_embedded", + "$path_client_bindir/mysqltest_embedded"); + } + else + { + $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); + } + + # Look for mysql_client_test executable which may _not_ exist in + # some versions, test using it should be skipped + if ( $glob_use_embedded_server ) + { + $exe_mysql_client_test= + mtr_exe_maybe_exists( + vs_config_dirs('libmysqld/examples', 'mysql_client_test_embedded'), + "$glob_bindir/libmysqld/examples/mysql_client_test_embedded"); + } + else + { + $exe_mysql_client_test= + mtr_exe_maybe_exists(vs_config_dirs('tests', 'mysql_client_test'), + "$glob_bindir/tests/mysql_client_test", + "$glob_bindir/bin/mysql_client_test"); + } + + # Look for bug25714 executable which may _not_ exist in + # some versions, test using it should be skipped + $exe_bug25714= + mtr_exe_maybe_exists(vs_config_dirs('tests', 'bug25714'), + "$glob_bindir/tests/bug25714"); +} + + +sub generate_cmdline_mysqldump ($) { + my($mysqld) = @_; + return + mtr_native_path($exe_mysqldump) . + " --no-defaults -uroot --debug-check " . + "--port=$mysqld->{'port'} " . + "--socket=$mysqld->{'path_sock'} --password="; +} + + +############################################################################## +# +# Set environment to be used by childs of this process for +# things that are constant duting the whole lifetime of mysql-test-run.pl +# +############################################################################## + +sub mysql_client_test_arguments() +{ + my $exe= $exe_mysql_client_test; + + my $args; + mtr_init_args(\$args); + if ( $opt_valgrind_mysqltest ) + { + valgrind_arguments($args, \$exe); + } + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--testcase"); + mtr_add_arg($args, "--user=root"); + mtr_add_arg($args, "--port=$master->[0]->{'port'}"); + mtr_add_arg($args, "--socket=$master->[0]->{'path_sock'}"); + + if ( $opt_extern || $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "--vardir=$opt_vardir") + } + + if ( $opt_debug ) + { + mtr_add_arg($args, + "--debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace"); + } + + if ( $glob_use_embedded_server ) + { + mtr_add_arg($args, + " -A --lc-messages-dir=$path_language"); + mtr_add_arg($args, + " -A --datadir=$slave->[0]->{'path_myddir'}"); + mtr_add_arg($args, + " -A --character-sets-dir=$path_charsetsdir"); + } + + return join(" ", $exe, @$args); +} + +sub mysql_upgrade_arguments() +{ + my $exe= $exe_mysql_upgrade; + + my $args; + mtr_init_args(\$args); +# if ( $opt_valgrind_mysql_ugrade ) +# { +# valgrind_arguments($args, \$exe); +# } + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=root"); + mtr_add_arg($args, "--port=$master->[0]->{'port'}"); + mtr_add_arg($args, "--socket=$master->[0]->{'path_sock'}"); + mtr_add_arg($args, "--datadir=$master->[0]->{'path_myddir'}"); + mtr_add_arg($args, "--basedir=$glob_basedir"); + mtr_add_arg($args, "--tmpdir=$opt_tmpdir"); + + if ( $opt_debug ) + { + mtr_add_arg($args, + "--debug=d:t:A,$path_vardir_trace/log/mysql_upgrade.trace"); + } + + return join(" ", $exe, @$args); +} + +# Note that some env is setup in spawn/run, in "mtr_process.pl" + +sub environment_setup () { + + umask(022); + + my @ld_library_paths; + + if ($path_client_libdir) + { + # Use the --client-libdir passed on commandline + push(@ld_library_paths, "$path_client_libdir"); + } + else + { + # Setup LD_LIBRARY_PATH so the libraries from this distro/clone + # are used in favor of the system installed ones + if ( $source_dist ) + { + push(@ld_library_paths, "$glob_bindir/libmysql/.libs/", + "$glob_bindir/libmysql_r/.libs/", + "$glob_bindir/zlib.libs/"); + } + else + { + push(@ld_library_paths, "$glob_bindir/lib"); + } + } + + # -------------------------------------------------------------------------- + # Valgrind need to be run with debug libraries otherwise it's almost + # impossible to add correct supressions, that means if "/usr/lib/debug" + # is available, it should be added to + # LD_LIBRARY_PATH + # + # But pthread is broken in libc6-dbg on Debian <= 3.1 (see Debian + # bug 399035, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=399035), + # so don't change LD_LIBRARY_PATH on that platform. + # -------------------------------------------------------------------------- + my $debug_libraries_path= "/usr/lib/debug"; + my $deb_version; + if ( $opt_valgrind and -d $debug_libraries_path and + (! -e '/etc/debian_version' or + ($deb_version= mtr_grab_file('/etc/debian_version')) !~ /^[0-9]+\.[0-9]$/ or + $deb_version > 3.1 ) ) + { + push(@ld_library_paths, $debug_libraries_path); + } + + $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths, + $ENV{'LD_LIBRARY_PATH'} ? + split(':', $ENV{'LD_LIBRARY_PATH'}) : ()); + mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}"); + + $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths, + $ENV{'DYLD_LIBRARY_PATH'} ? + split(':', $ENV{'DYLD_LIBRARY_PATH'}) : ()); + mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}"); + + # The environment variable used for shared libs on AIX + $ENV{'SHLIB_PATH'}= join(":", @ld_library_paths, + $ENV{'SHLIB_PATH'} ? + split(':', $ENV{'SHLIB_PATH'}) : ()); + mtr_debug("SHLIB_PATH: $ENV{'SHLIB_PATH'}"); + + # The environment variable used for shared libs on hp-ux + $ENV{'LIBPATH'}= join(":", @ld_library_paths, + $ENV{'LIBPATH'} ? + split(':', $ENV{'LIBPATH'}) : ()); + mtr_debug("LIBPATH: $ENV{'LIBPATH'}"); + + # -------------------------------------------------------------------------- + # Also command lines in .opt files may contain env vars + # -------------------------------------------------------------------------- + + $ENV{'CHARSETSDIR'}= $path_charsetsdir; + $ENV{'UMASK'}= "0660"; # The octal *string* + $ENV{'UMASK_DIR'}= "0770"; # The octal *string* + + # + # MySQL tests can produce output in various character sets + # (especially, ctype_xxx.test). To avoid confusing Perl + # with output which is incompatible with the current locale + # settings, we reset the current values of LC_ALL and LC_CTYPE to "C". + # For details, please see + # Bug#27636 tests fails if LC_* variables set to *_*.UTF-8 + # + $ENV{'LC_ALL'}= "C"; + $ENV{'LC_CTYPE'}= "C"; + + $ENV{'LC_COLLATE'}= "C"; + $ENV{'USE_RUNNING_SERVER'}= $opt_extern; + $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; + $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; + $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir; + $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_sock'}; + $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_sock'}; + $ENV{'MASTER_MYPORT'}= $master->[0]->{'port'}; + $ENV{'MASTER_MYPORT1'}= $master->[1]->{'port'}; + $ENV{'SLAVE_MYSOCK'}= $slave->[0]->{'path_sock'}; + $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'}; + $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'}; + $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'}; + $ENV{'MYSQL_TCP_PORT'}= $mysqld_variables{'port'}; + $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'master-port'}; + + $ENV{MTR_BUILD_THREAD}= $opt_mtr_build_thread; + + $ENV{'EXE_MYSQL'}= $exe_mysql; + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlcheck + # ---------------------------------------------------- + my $cmdline_mysqlcheck= + mtr_native_path($exe_mysqlcheck) . + " --no-defaults --debug-check -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlcheck .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlcheck.trace"; + } + $ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck; + + # ---------------------------------------------------- + # Setup env to childs can execute myqldump + # ---------------------------------------------------- + my $cmdline_mysqldump= generate_cmdline_mysqldump($master->[0]); + my $cmdline_mysqldumpslave= generate_cmdline_mysqldump($slave->[0]); + + if ( $opt_debug ) + { + $cmdline_mysqldump .= + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-master.trace"; + $cmdline_mysqldumpslave .= + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-slave.trace"; + } + $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; + $ENV{'MYSQL_DUMP_SLAVE'}= $cmdline_mysqldumpslave; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlslap + # ---------------------------------------------------- + if ( $exe_mysqlslap ) + { + my $cmdline_mysqlslap= + mtr_native_path($exe_mysqlslap) . + " -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password= "; + + if ( $opt_debug ) + { + $cmdline_mysqlslap .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; + } + $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; + } + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlimport + # ---------------------------------------------------- + my $cmdline_mysqlimport= + mtr_native_path($exe_mysqlimport) . + " -uroot --debug-check " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlimport .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlimport.trace"; + } + $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlshow + # ---------------------------------------------------- + my $cmdline_mysqlshow= + mtr_native_path($exe_mysqlshow) . + " -uroot --debug-check " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlshow .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlshow.trace"; + } + $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlbinlog + # ---------------------------------------------------- + my $cmdline_mysqlbinlog= + mtr_native_path($exe_mysqlbinlog) . + " --no-defaults --disable-force-if-open --debug-check"; + if ( !$opt_extern && $mysql_version_id >= 50000 ) + { + $cmdline_mysqlbinlog .=" --character-sets-dir=$path_charsetsdir"; + } + # Always use the given tmpdir for the LOAD files created + # by mysqlbinlog + $cmdline_mysqlbinlog .=" --local-load=$opt_tmpdir"; + + if ( $opt_debug ) + { + $cmdline_mysqlbinlog .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlbinlog.trace"; + } + $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; + + # ---------------------------------------------------- + # Setup env so childs can execute mysql + # ---------------------------------------------------- + my $cmdline_mysql= + mtr_native_path($exe_mysql) . + " --no-defaults --debug-check --host=localhost --user=root --password= " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} ". + "--character-sets-dir=$path_charsetsdir"; + + $ENV{'MYSQL'}= $cmdline_mysql; + + # ---------------------------------------------------- + # Setup env so childs can execute bug25714 + # ---------------------------------------------------- + $ENV{'MYSQL_BUG25714'}= $exe_bug25714; + + # ---------------------------------------------------- + # Setup env so childs can execute mysql_client_test + # ---------------------------------------------------- + $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); + + # ---------------------------------------------------- + # Setup env so childs can execute mysql_upgrade + # ---------------------------------------------------- + if ( !$opt_extern && $mysql_version_id >= 50000 ) + { + $ENV{'MYSQL_UPGRADE'}= mysql_upgrade_arguments(); + } + + if ( !$opt_extern ) + { + $ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}= $file_mysql_fix_privilege_tables; + } + + # ---------------------------------------------------- + # Setup env so childs can execute my_print_defaults + # ---------------------------------------------------- + $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= mtr_native_path($exe_my_print_defaults); + + # ---------------------------------------------------- + # Setup env so childs can execute mysqladmin + # ---------------------------------------------------- + $ENV{'MYSQLADMIN'}= mtr_native_path($exe_mysqladmin); + + # ---------------------------------------------------- + # Setup env so childs can execute perror + # ---------------------------------------------------- + $ENV{'MY_PERROR'}= mtr_native_path($exe_perror); + + # ---------------------------------------------------- + # Add the path where mysqld will find udf_example.so + # ---------------------------------------------------- + $ENV{'UDF_EXAMPLE_LIB'}= + ($lib_udf_example ? basename($lib_udf_example) : ""); + $ENV{'UDF_EXAMPLE_LIB_OPT'}= + ($lib_udf_example ? "--plugin_dir=" . dirname($lib_udf_example) : ""); + + # ---------------------------------------------------- + # Add the path where mysqld will find ha_example.so + # ---------------------------------------------------- + $ENV{'EXAMPLE_PLUGIN'}= + ($lib_example_plugin ? basename($lib_example_plugin) : ""); + $ENV{'EXAMPLE_PLUGIN_OPT'}= + ($lib_example_plugin ? "--plugin_dir=" . dirname($lib_example_plugin) : ""); + + # ---------------------------------------------------- + # Setup env so childs can execute myisampack and myisamchk + # ---------------------------------------------------- + $ENV{'MYISAMCHK'}= mtr_native_path(mtr_exe_exists( + vs_config_dirs('storage/myisam', 'myisamchk'), + vs_config_dirs('myisam', 'myisamchk'), + "$path_client_bindir/myisamchk", + "$glob_bindir/storage/myisam/myisamchk", + "$glob_bindir/myisam/myisamchk")); + $ENV{'MYISAMPACK'}= mtr_native_path(mtr_exe_exists( + vs_config_dirs('storage/myisam', 'myisampack'), + vs_config_dirs('myisam', 'myisampack'), + "$path_client_bindir/myisampack", + "$glob_bindir/storage/myisam/myisampack", + "$glob_bindir/myisam/myisampack")); + + # ---------------------------------------------------- + # Setup env so childs can execute aria_pack and aria_chk + # ---------------------------------------------------- + $ENV{'ARIA_CHK'}= mtr_native_path(mtr_exe_maybe_exists( + vs_config_dirs('storage/maria', 'aria_chk'), + vs_config_dirs('maria', 'aria_chk'), + "$path_client_bindir/aria_chk", + "$glob_basedir/storage/maria/aria_chk", + "$glob_basedir/maria/aria_chk")); + $ENV{'ARIA_PACK'}= mtr_native_path(mtr_exe_maybe_exists( + vs_config_dirs('storage/maria', 'aria_pack'), + vs_config_dirs('maria', 'aria_pack'), + "$path_client_bindir/aria_pack", + "$glob_basedir/storage/maria/aria_pack", + "$glob_basedir/maria/aria_pack")); + + # ---------------------------------------------------- + # We are nice and report a bit about our settings + # ---------------------------------------------------- + if (!$opt_extern) + { + print "Using MTR_BUILD_THREAD = $ENV{MTR_BUILD_THREAD}\n"; + print "Using MASTER_MYPORT = $ENV{MASTER_MYPORT}\n"; + print "Using MASTER_MYPORT1 = $ENV{MASTER_MYPORT1}\n"; + print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n"; + print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n"; + print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n"; + } + + # Create an environment variable to make it possible + # to detect that valgrind is being used from test cases + $ENV{'VALGRIND_TEST'}= $opt_valgrind; + +} + + +############################################################################## +# +# If we get a ^C, we try to clean up before termination +# +############################################################################## +# FIXME check restrictions what to do in a signal handler + +sub signal_setup () { + $SIG{INT}= \&handle_int_signal; +} + + +sub handle_int_signal () { + $SIG{INT}= 'DEFAULT'; # If we get a ^C again, we die... + mtr_warning("got INT signal, cleaning up....."); + stop_all_servers(); + mtr_error("We die from ^C signal from user"); +} + + +############################################################################## +# +# Handle left overs from previous runs +# +############################################################################## + +sub kill_running_servers () { + + if ( $opt_fast or $glob_use_embedded_server ) + { + # FIXME is embedded server really using PID files?! + unlink($master->[0]->{'path_pid'}); + unlink($master->[1]->{'path_pid'}); + unlink($slave->[0]->{'path_pid'}); + unlink($slave->[1]->{'path_pid'}); + unlink($slave->[2]->{'path_pid'}); + } + else + { + # Ensure that no old mysqld test servers are running + # This is different from terminating processes we have + # started from this run of the script, this is terminating + # leftovers from previous runs. + mtr_kill_leftovers(); + } +} + +# +# Remove var and any directories in var/ created by previous +# tests +# +sub remove_stale_vardir () { + + mtr_report("Removing Stale Files"); + + # Safety! + mtr_error("No, don't remove the vardir when running with --extern") + if $opt_extern; + + mtr_verbose("opt_vardir: $opt_vardir"); + if ( $opt_vardir eq $default_vardir ) + { + # + # Running with "var" in mysql-test dir + # + if ( -l $opt_vardir) + { + # var is a symlink + + if ( $opt_mem and readlink($opt_vardir) eq $opt_mem ) + { + # Remove the directory which the link points at + mtr_verbose("Removing " . readlink($opt_vardir)); + mtr_rmtree(readlink($opt_vardir)); + + # Remove the "var" symlink + mtr_verbose("unlink($opt_vardir)"); + unlink($opt_vardir); + } + elsif ( $opt_mem ) + { + # Just remove the "var" symlink + mtr_report("WARNING: Removing '$opt_vardir' symlink it's wrong"); + + mtr_verbose("unlink($opt_vardir)"); + unlink($opt_vardir); + } + else + { + # Some users creates a soft link in mysql-test/var to another area + # - allow it, but remove all files in it + + mtr_report("WARNING: Using the 'mysql-test/var' symlink"); + + # Make sure the directory where it points exist + if (! -d readlink($opt_vardir)) + { + mtr_report("The destination for symlink $opt_vardir does not exist; Removing it and creating a new var directory"); + unlink($opt_vardir); + } + + foreach my $bin ( glob("$opt_vardir/*") ) + { + mtr_verbose("Removing bin $bin"); + mtr_rmtree($bin); + } + } + } + else + { + # Remove the entire "var" dir + mtr_verbose("Removing $opt_vardir/"); + mtr_rmtree("$opt_vardir/"); + } + + if ( $opt_mem ) + { + # A symlink from var/ to $opt_mem will be set up + # remove the $opt_mem dir to assure the symlink + # won't point at an old directory + mtr_verbose("Removing $opt_mem"); + mtr_rmtree($opt_mem); + } + + } + else + { + # + # Running with "var" in some other place + # + + # Remove the var/ dir in mysql-test dir if any + # this could be an old symlink that shouldn't be there + # mtr_verbose("Removing $default_vardir"); + # mtr_rmtree($default_vardir); + + # Remove the "var" dir + mtr_verbose("Removing $opt_vardir/"); + mtr_rmtree("$opt_vardir/"); + } +} + +# +# Create var and the directories needed in var +# +sub setup_vardir() { + mtr_report("Creating Directories"); + + if ( $opt_vardir eq $default_vardir ) + { + # + # Running with "var" in mysql-test dir + # + if ( -l $opt_vardir ) + { + # it's a symlink + + # Make sure the directory where it points exist + if (! -d readlink($opt_vardir)) + { + mtr_report("The destination for symlink $opt_vardir does not exist; Removing it and creating a new var directory"); + unlink($opt_vardir); + } + } + elsif ( $opt_mem ) + { + # Runinng with "var" as a link to some "memory" location, normally tmpfs + mtr_verbose("Creating $opt_mem"); + mkpath($opt_mem); + + mtr_report("Symlinking 'var' to '$opt_mem'"); + symlink($opt_mem, $opt_vardir); + } + } + + if ( ! -d $opt_vardir ) + { + mtr_verbose("Creating $opt_vardir"); + mkpath($opt_vardir); + } + + # Ensure a proper error message if vardir couldn't be created + unless ( -d $opt_vardir and -w $opt_vardir ) + { + mtr_error("Writable 'var' directory is needed, use the " . + "'--vardir=<path>' option"); + } + + mkpath("$opt_vardir/log"); + mkpath("$opt_vardir/run"); + mkpath("$opt_vardir/tmp"); + mkpath($opt_tmpdir) if $opt_tmpdir ne "$opt_vardir/tmp"; + + # Create new data dirs + foreach my $data_dir (@data_dir_lst) + { + mkpath("$data_dir/mysql"); + mkpath("$data_dir/test"); + } + + # Make a link std_data_ln in var/ that points to std_data + if ( ! $glob_win32 ) + { + symlink("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data_ln"); + } + else + { + # on windows, copy all files from std_data into var/std_data_ln + mkpath("$opt_vardir/std_data_ln"); + mtr_copy_dir("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data_ln"); + } + + # Remove old log files + foreach my $name (glob("r/*.progress r/*.log r/*.warnings")) + { + unlink($name); + } + if ( $opt_valgrind and $opt_debug ) + { + # When both --valgrind and --debug is selected, send + # all output to the trace file, making it possible to + # see the exact location where valgrind complains + foreach my $mysqld (@{$master}, @{$slave}) + { + my $sidx= $mysqld->{idx} ? "$mysqld->{idx}" : ""; + my $trace_name= "$opt_vardir/log/" . $mysqld->{type} . "$sidx.trace"; + open(LOG, ">$mysqld->{path_myerr}") or die "Can't create $mysqld->{path_myerr}\n"; + print LOG " +NOTE: When running with --valgrind --debug the output from the .err file is +stored together with the trace file to make it easier to find the exact +position for valgrind errors. +See trace file $trace_name.\n"; + close(LOG); + $mysqld->{path_myerr}= $trace_name; + } + } +} + + +sub check_running_as_root () { + # Check if running as root + # i.e a file can be read regardless what mode we set it to + my $test_file= "$opt_vardir/test_running_as_root.txt"; + mtr_tofile($test_file, "MySQL"); + chmod(oct("0000"), $test_file); + + my $result=""; + if (open(FILE,"<",$test_file)) + { + $result= join('', <FILE>); + close FILE; + } + + # Some filesystems( for example CIFS) allows reading a file + # although mode was set to 0000, but in that case a stat on + # the file will not return 0000 + my $file_mode= (stat($test_file))[2] & 07777; + + $ENV{'MYSQL_TEST_ROOT'}= "NO"; + mtr_verbose("result: $result, file_mode: $file_mode"); + if ($result eq "MySQL" && $file_mode == 0) + { + mtr_warning("running this script as _root_ will cause some " . + "tests to be skipped"); + $ENV{'MYSQL_TEST_ROOT'}= "YES"; + } + + chmod(oct("0755"), $test_file); + unlink($test_file); + +} + + +sub check_ssl_support ($) { + my $mysqld_variables= shift; + + if ($opt_skip_ssl || $opt_extern) + { + if (!$opt_extern) + { + mtr_report("Skipping SSL"); + } + $opt_ssl_supported= 0; + $opt_ssl= 0; + return; + } + + if ( ! $mysqld_variables->{'ssl'} ) + { + if ( $opt_ssl) + { + mtr_error("Couldn't find support for SSL"); + return; + } + mtr_report("Skipping SSL, mysqld not compiled with SSL"); + $opt_ssl_supported= 0; + $opt_ssl= 0; + return; + } + mtr_report("Setting mysqld to support SSL connections"); + $opt_ssl_supported= 1; +} + + +sub check_debug_support ($) { + my $mysqld_variables= shift; + + if ( ! $mysqld_variables->{'debug'} ) + { + #mtr_report("Binaries are not debug compiled"); + $debug_compiled_binaries= 0; + + if ( $opt_debug ) + { + mtr_error("Can't use --debug, binaries does not support it"); + } + return; + } + mtr_report("Binaries are debug compiled"); + $debug_compiled_binaries= 1; +} + +############################################################################## +# +# Helper function to handle configuration-based subdirectories which Visual +# Studio uses for storing binaries. If opt_vs_config is set, this returns +# a path based on that setting; if not, it returns paths for the default +# /release/ and /debug/ subdirectories. +# +# $exe can be undefined, if the directory itself will be used +# +############################################################################### + +sub vs_config_dirs ($$) { + my ($path_part, $exe) = @_; + + $exe = "" if not defined $exe; + + if ($multiconfig) + { + return ("$glob_bindir/$path_part/$multiconfig/$exe"); + } + + return ("$glob_bindir/$path_part/release/$exe", + "$glob_bindir/$path_part/relwithdebinfo/$exe", + "$glob_bindir/$path_part/debug/$exe"); +} + +sub mysqld_wait_started($){ + my $mysqld= shift; + + if (sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + $mysqld->{'pid'}) == 0) + { + # Failed to wait for pid file + return 1; + } + + # Get the "real pid" of the process, it will be used for killing + # the process in ActiveState's perl on windows + $mysqld->{'real_pid'}= mtr_get_pid_from_file($mysqld->{'path_pid'}); + + return 0; +} + + +############################################################################## +# +# Run the benchmark suite +# +############################################################################## + +sub run_benchmarks ($) { + my $benchmark= shift; + + my $args; + + if ( ! $glob_use_embedded_server ) + { + mysqld_start($master->[0],[],[]); + if ( ! $master->[0]->{'pid'} ) + { + mtr_error("Can't start the mysqld server"); + } + } + + mtr_init_args(\$args); + + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); + mtr_add_arg($args, "--user=%s", $opt_user); + + if ( $opt_small_bench ) + { + mtr_add_arg($args, "--small-test"); + mtr_add_arg($args, "--small-tables"); + } + + chdir($glob_mysql_bench_dir) + or mtr_error("Couldn't chdir to '$glob_mysql_bench_dir': $!"); + + if ( ! $benchmark ) + { + mtr_add_arg($args, "--general-log"); + mtr_run("$glob_mysql_bench_dir/run-all-tests", $args, "", "", "", ""); + # FIXME check result code?! + } + elsif ( -x $benchmark ) + { + mtr_run("$glob_mysql_bench_dir/$benchmark", $args, "", "", "", ""); + # FIXME check result code?! + } + else + { + mtr_error("Benchmark $benchmark not found"); + } + + chdir($glob_mysql_test_dir); # Go back + + if ( ! $glob_use_embedded_server ) + { + stop_masters(); + } +} + + +############################################################################## +# +# Run the tests +# +############################################################################## + +sub run_tests () { + my ($tests)= @_; + + mtr_print_thick_line(); + + mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout); + + mtr_report_tests_not_skipped_though_disabled($tests); + + mtr_print_header(); + + foreach my $tinfo ( @$tests ) + { + if (run_testcase_check_skip_test($tinfo)) + { + next; + } + + mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout); + run_testcase($tinfo); + mtr_timer_stop($glob_timers,"testcase"); + } + + mtr_print_line(); + + if ( ! $glob_debugger and + ! $opt_extern and + ! $glob_use_embedded_server ) + { + stop_all_servers(); + } + + if ( $opt_gcov ) + { + gcov_collect(); # collect coverage information + } + if ( $opt_gprof ) + { + gprof_collect(); # collect coverage information + } + + mtr_report_stats($tests); + + mtr_timer_stop($glob_timers,"suite"); +} + + +############################################################################## +# +# Initiate the test databases +# +############################################################################## + +sub initialize_servers () { + + datadir_list_setup(); + + if ( $opt_extern ) + { + # Running against an already started server, if the specified + # vardir does not already exist it should be created + if ( ! -d $opt_vardir ) + { + mtr_report("Creating '$opt_vardir'"); + setup_vardir(); + } + else + { + mtr_verbose("No need to create '$opt_vardir' it already exists"); + } + } + else + { + kill_running_servers(); + + if ( ! $opt_start_dirty ) + { + remove_stale_vardir(); + setup_vardir(); + + mysql_install_db(); + if ( $opt_force ) + { + # Save a snapshot of the freshly installed db + # to make it possible to restore to a known point in time + save_installed_db(); + } + } + } + check_running_as_root(); + + mtr_log_init("$opt_vardir/log/mysql-test-run.log"); + +} + +sub mysql_install_db () { + + install_db('master', $master->[0]->{'path_myddir'}); + + if ($max_master_num > 1) + { + copy_install_db('master', $master->[1]->{'path_myddir'}); + } + + # Install the number of slave databses needed + for (my $idx= 0; $idx < $max_slave_num; $idx++) + { + copy_install_db("slave".($idx+1), $slave->[$idx]->{'path_myddir'}); + } + + return 0; +} + + +sub copy_install_db ($$) { + my $type= shift; + my $data_dir= shift; + + mtr_report("Installing \u$type Database"); + + # Just copy the installed db from first master + mtr_copy_dir($master->[0]->{'path_myddir'}, $data_dir); + +} + + +sub install_db ($$) { + my $type= shift; + my $data_dir= shift; + + mtr_report("Installing \u$type Database"); + + my $args; + my $cmd_args; + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--bootstrap"); + mtr_add_arg($args, "--basedir=%s", $glob_basedir); + mtr_add_arg($args, "--datadir=%s", $data_dir); + mtr_add_arg($args, "--loose-skip-aria"); + mtr_add_arg($args, "--disable-sync-frm"); + mtr_add_arg($args, "--loose-disable-debug"); + mtr_add_arg($args, "--tmpdir=."); + mtr_add_arg($args, "--core-file"); + + # + # Setup args for bootstrap.test + # + mtr_init_args(\$cmd_args); + mtr_add_arg($cmd_args, "--loose-skip-aria"); + + if ( $opt_debug ) + { + mtr_add_arg($args, "--debug=d:t:i:A,%s/log/bootstrap_%s.trace", + $path_vardir_trace, $type); + } + + mtr_add_arg($args, "--lc-messages-dir=%s", $path_language); + mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); + + # InnoDB arguments that affect file location and sizes may + # need to be given to the bootstrap process as well as the + # server process. + foreach my $extra_opt ( @opt_extra_mysqld_opt ) { + if ($extra_opt =~ /--innodb/) { + mtr_add_arg($args, $extra_opt); + } + } + + # If DISABLE_GRANT_OPTIONS is defined when the server is compiled (e.g., + # configure --disable-grant-options), mysqld will not recognize the + # --bootstrap or --skip-grant-tables options. The user can set + # MYSQLD_BOOTSTRAP to the full path to a mysqld which does accept + # --bootstrap, to accommodate this. + my $exe_mysqld_bootstrap = $ENV{'MYSQLD_BOOTSTRAP'} || $exe_mysqld; + + # ---------------------------------------------------------------------- + # export MYSQLD_BOOTSTRAP_CMD variable containing <path>/mysqld <args> + # ---------------------------------------------------------------------- + $ENV{'MYSQLD_BOOTSTRAP_CMD'}= "$exe_mysqld_bootstrap " . join(" ", @$args) . + " " . join(" ", @$cmd_args); + + # ---------------------------------------------------------------------- + # Create the bootstrap.sql file + # ---------------------------------------------------------------------- + my $bootstrap_sql_file= "$opt_vardir/tmp/bootstrap.sql"; + + # Use the mysql database for system tables + mtr_tofile($bootstrap_sql_file, "use mysql;\n"); + + # Add the offical mysql system tables + # for a production system + mtr_appendfile_to_file("$path_sql_dir/mysql_system_tables.sql", + $bootstrap_sql_file); + mtr_appendfile_to_file("$path_sql_dir/mysql_performance_tables.sql", + $bootstrap_sql_file); + + # Add the mysql system tables initial data + # for a production system + mtr_appendfile_to_file("$path_sql_dir/mysql_system_tables_data.sql", + $bootstrap_sql_file); + + # Add test data for timezone - this is just a subset, on a real + # system these tables will be populated either by mysql_tzinfo_to_sql + # or by downloading the timezone table package from our website + mtr_appendfile_to_file("$path_sql_dir/mysql_test_data_timezone.sql", + $bootstrap_sql_file); + + # Fill help tables, just an empty file when running from bk repo + # but will be replaced by a real fill_help_tables.sql when + # building the source dist + mtr_appendfile_to_file("$path_sql_dir/fill_help_tables.sql", + $bootstrap_sql_file); + + # Remove anonymous users + mtr_tofile($bootstrap_sql_file, + "DELETE FROM mysql.user where user= '';"); + + # Log bootstrap command + my $path_bootstrap_log= "$opt_vardir/log/bootstrap.log"; + mtr_tofile($path_bootstrap_log, + "$exe_mysqld_bootstrap " . join(" ", @$args) . "\n"); + + + if ( mtr_run($exe_mysqld_bootstrap, $args, $bootstrap_sql_file, + $path_bootstrap_log, $path_bootstrap_log, + "", { append_log_file => 1 }) != 0 ) + + { + mtr_error("Error executing mysqld --bootstrap\n" . + "Could not install system database from $bootstrap_sql_file\n" . + "see $path_bootstrap_log for errors"); + } +} + + +# +# Restore snapshot of the installed slave databases +# if the snapshot exists +# +sub restore_slave_databases ($) { + my ($num_slaves)= @_; + + if ( -d $path_snapshot) + { + for (my $idx= 0; $idx < $num_slaves; $idx++) + { + my $data_dir= $slave->[$idx]->{'path_myddir'}; + my $name= basename($data_dir); + mtr_rmtree($data_dir); + mtr_copy_dir("$path_snapshot/$name", $data_dir); + } + } +} + + +sub run_testcase_check_skip_test($) +{ + my ($tinfo)= @_; + + # ---------------------------------------------------------------------- + # Skip some tests silently + # ---------------------------------------------------------------------- + + if ( $::opt_start_from ) + { + if ($tinfo->{'name'} eq $::opt_start_from ) + { + ## Found parting test. Run this test and all tests after this one + $::opt_start_from= ""; + } + else + { + $tinfo->{'result'}= 'MTR_RES_SKIPPED'; + return 1; + } + } + + # ---------------------------------------------------------------------- + # If marked to skip, just print out and return. + # Note that a test case not marked as 'skip' can still be + # skipped later, because of the test case itself in cooperation + # with the mysqltest program tells us so. + # ---------------------------------------------------------------------- + + if ( $tinfo->{'skip'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_skipped($tinfo); + return 1; + } + + return 0; +} + + +sub do_before_run_mysqltest($) +{ + my $tinfo= shift; + my $args; + + # Remove old files produced by mysqltest + my $base_file= mtr_match_extension($tinfo->{'result_file'}, + "result"); # Trim extension + unlink("$base_file.reject"); + unlink("$base_file.progress"); + unlink("$base_file.log"); + unlink("$base_file.warnings"); + + if (!$opt_extern) + { + if (defined $tinfo->{binlog_format} and $mysql_version_id > 50100 ) + { + # Dynamically switch binlog format of + # master, slave is always restarted + foreach my $server ( @$master ) + { + next unless ($server->{'pid'}); + + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=root"); + mtr_add_arg($args, "--port=$server->{'port'}"); + mtr_add_arg($args, "--socket=$server->{'path_sock'}"); + + my $sql= "include/set_binlog_format_".$tinfo->{binlog_format}.".sql"; + mtr_verbose("Setting binlog format:", $tinfo->{binlog_format}); + if (mtr_run($exe_mysql, $args, $sql, "", "", "") != 0) + { + mtr_error("Failed to switch binlog format"); + } + } + } + } +} + +sub do_after_run_mysqltest($) +{ + my $tinfo= shift; + + # Save info from this testcase run to mysqltest.log + mtr_appendfile_to_file($path_current_test_log, $path_mysqltest_log) + if -f $path_current_test_log; + mtr_appendfile_to_file($path_timefile, $path_mysqltest_log) + if -f $path_timefile; +} + + +sub run_testcase_mark_logs($$) +{ + my ($tinfo, $log_msg)= @_; + + # Write a marker to all log files + + # The file indicating current test name + mtr_tonewfile($path_current_test_log, $log_msg); + + # each mysqld's .err file + foreach my $mysqld (@{$master}, @{$slave}) + { + mtr_tofile($mysqld->{path_myerr}, $log_msg); + } +} + +sub find_testcase_skipped_reason($) +{ + my ($tinfo)= @_; + + # Set default message + $tinfo->{'comment'}= "Detected by testcase(no log file)"; + + # Open mysqltest-time(the mysqltest log file) + my $F= IO::File->new($path_timefile) + or return; + my $reason; + + while ( my $line= <$F> ) + { + # Look for "reason: <reason for skipping test>" + if ( $line =~ /reason: (.*)/ ) + { + $reason= $1; + } + } + + if ( ! $reason ) + { + mtr_warning("Could not find reason for skipping test in $path_timefile"); + $reason= "Detected by testcase(reason unknown) "; + } + $tinfo->{'comment'}= $reason; +} + + +############################################################################## +# +# Run a single test case +# +############################################################################## + +# When we get here, we have already filtered out test cases that doesn't +# apply to the current setup, for example if we use a running server, test +# cases that restart the server are dropped. So this function should mostly +# be about doing things, not a lot of logic. + +# We don't start and kill the servers for each testcase. But some +# testcases needs a restart, because they specify options to start +# mysqld with. After that testcase, we need to restart again, to set +# back the normal options. + +sub run_testcase ($) { + my $tinfo= shift; + + # ------------------------------------------------------- + # Init variables that can change between each test case + # ------------------------------------------------------- + + $ENV{'TZ'}= $tinfo->{'timezone'}; + mtr_verbose("Setting timezone: $tinfo->{'timezone'}"); + + my $master_restart= run_testcase_need_master_restart($tinfo); + my $slave_restart= run_testcase_need_slave_restart($tinfo); + + if ($master_restart or $slave_restart) + { + # Can't restart a running server that may be in use + if ( $opt_extern ) + { + mtr_report_test_name($tinfo); + $tinfo->{comment}= "Can't restart a running server"; + mtr_report_test_skipped($tinfo); + return; + } + + run_testcase_stop_servers($tinfo, $master_restart, $slave_restart); + } + + # Write to all log files to indicate start of testcase + run_testcase_mark_logs($tinfo, "CURRENT_TEST: $tinfo->{name}\n"); + + my $died= mtr_record_dead_children(); + if ($died or $master_restart or $slave_restart) + { + if (run_testcase_start_servers($tinfo)) + { + mtr_report_test_name($tinfo); + report_failure_and_restart($tinfo); + return 1; + } + } + elsif ($glob_use_embedded_server) + { + run_master_init_script($tinfo); + } + + # ---------------------------------------------------------------------- + # If --start-and-exit or --start-dirty given, stop here to let user manually + # run tests + # ---------------------------------------------------------------------- + if ( $opt_start_and_exit or $opt_start_dirty ) + { + mtr_timer_stop_all($glob_timers); + mtr_report("\nServers started, exiting"); + if ($glob_win32_perl) + { + #ActiveState perl hangs when using normal exit, use POSIX::_exit instead + use POSIX qw[ _exit ]; + POSIX::_exit(0); + } + else + { + exit(0); + } + } + + { + do_before_run_mysqltest($tinfo); + + my $res= run_mysqltest($tinfo); + mtr_report_test_name($tinfo); + + do_after_run_mysqltest($tinfo); + + if ( $res == 0 ) + { + mtr_report_test_passed($tinfo); + } + elsif ( $res == 62 ) + { + # Testcase itself tell us to skip this one + + # Try to get reason from mysqltest.log + find_testcase_skipped_reason($tinfo); + mtr_report_test_skipped($tinfo); + } + elsif ( $res == 63 ) + { + $tinfo->{'timeout'}= 1; # Mark as timeout + report_failure_and_restart($tinfo); + } + elsif ( $res == 1 ) + { + # Test case failure reported by mysqltest + report_failure_and_restart($tinfo); + } + else + { + # mysqltest failed, probably crashed + $tinfo->{comment}= + "mysqltest returned unexpected code $res, it has probably crashed"; + report_failure_and_restart($tinfo); + } + } + + # Remove the file that mysqltest writes info to + unlink($path_timefile); +} + + +# +# Save a snapshot of the installed test db(s) +# I.e take a snapshot of the var/ dir +# +sub save_installed_db () { + + mtr_report("Saving snapshot of installed databases"); + mtr_rmtree($path_snapshot); + + foreach my $data_dir (@data_dir_lst) + { + my $name= basename($data_dir); + mtr_copy_dir("$data_dir", "$path_snapshot/$name"); + } +} + + +# +# Save any interesting files in the data_dir +# before the data dir is removed. +# +sub save_files_before_restore($$) { + my $test_name= shift; + my $data_dir= shift; + my $save_name= "$opt_vardir/log/$test_name"; + + # Look for core files + foreach my $core_file ( glob("$data_dir/core*") ) + { + last if $opt_max_save_core > 0 && $num_saved_cores >= $opt_max_save_core; + my $core_name= basename($core_file); + mtr_report("Saving $core_name"); + mkdir($save_name) if ! -d $save_name; + rename("$core_file", "$save_name/$core_name"); + ++$num_saved_cores; + } +} + + +# +# Restore snapshot of the installed test db(s) +# if the snapshot exists +# +sub restore_installed_db ($) { + my $test_name= shift; + + if ( -d $path_snapshot) + { + mtr_report("Restoring snapshot of databases"); + + foreach my $data_dir (@data_dir_lst) + { + my $name= basename($data_dir); + save_files_before_restore($test_name, $data_dir); + mtr_rmtree("$data_dir"); + mtr_copy_dir("$path_snapshot/$name", "$data_dir"); + } + } + else + { + # No snapshot existed + mtr_error("No snapshot existed"); + } +} + +sub report_failure_and_restart ($) { + my $tinfo= shift; + + mtr_report_test_failed($tinfo); + print "\n"; + if ( $opt_force ) + { + # Stop all servers that are known to be running + stop_all_servers(); + + # Restore the snapshot of the installed test db + restore_installed_db($tinfo->{'name'}); + mtr_report("Resuming Tests\n"); + return; + } + + my $test_mode= join(" ", @::glob_test_mode) || "default"; + mtr_report("Aborting: $tinfo->{'name'} failed in $test_mode mode. "); + mtr_report("To continue, re-run with '--force'."); + if ( ! $glob_debugger and + ! $opt_extern and + ! $glob_use_embedded_server ) + { + stop_all_servers(); + } + mtr_exit(1); + +} + + +sub run_master_init_script ($) { + my ($tinfo)= @_; + my $init_script= $tinfo->{'master_sh'}; + + # Run master initialization shell script if one exists + if ( $init_script ) + { + my $ret= mtr_run("/bin/sh", [$init_script], "", "", "", ""); + if ( $ret != 0 ) + { + # FIXME rewrite those scripts to return 0 if successful + # mtr_warning("$init_script exited with code $ret"); + } + } +} + + +############################################################################## +# +# Start and stop servers +# +############################################################################## + + +sub do_before_start_master ($) { + my ($tinfo)= @_; + + my $tname= $tinfo->{'name'}; + + # FIXME what about second master..... + + # Don't delete anything if starting dirty + return if ($opt_start_dirty); + + foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) + { + unlink($bin); + } + + # FIXME only remove the ones that are tied to this master + # Remove old master.info and relay-log.info files + unlink("$master->[0]->{'path_myddir'}/master.info"); + unlink("$master->[0]->{'path_myddir'}/relay-log.info"); + unlink("$master->[1]->{'path_myddir'}/master.info"); + unlink("$master->[1]->{'path_myddir'}/relay-log.info"); + + run_master_init_script($tinfo); +} + + +sub do_before_start_slave ($) { + my ($tinfo)= @_; + + my $tname= $tinfo->{'name'}; + my $init_script= $tinfo->{'master_sh'}; + + # Don't delete anything if starting dirty + return if ($opt_start_dirty); + + foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) + { + unlink($bin); + } + + unlink("$slave->[0]->{'path_myddir'}/master.info"); + unlink("$slave->[0]->{'path_myddir'}/relay-log.info"); + + # Run slave initialization shell script if one exists + if ( $init_script ) + { + my $ret= mtr_run("/bin/sh", [$init_script], "", "", "", ""); + if ( $ret != 0 ) + { + # FIXME rewrite those scripts to return 0 if successful + # mtr_warning("$init_script exited with code $ret"); + } + } + + foreach my $bin ( glob("$slave->[0]->{'path_myddir'}/log.*") ) + { + unlink($bin); + } +} + + +sub mysqld_arguments ($$$$) { + my $args= shift; + my $mysqld= shift; + my $extra_opt= shift; + my $slave_master_info= shift; + + my $idx= $mysqld->{'idx'}; + my $sidx= ""; # Index as string, 0 is empty string + if ( $idx> 0 ) + { + $sidx= $idx; + } + + my $prefix= ""; # If mysqltest server arg + if ( $glob_use_embedded_server ) + { + $prefix= "--server-arg="; + } + + mtr_add_arg($args, "%s--no-defaults", $prefix); + + mtr_add_arg($args, "%s--basedir=%s", $prefix, $glob_basedir); + mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); + + if ( $mysql_version_id >= 50036) + { + # By default, prevent the started mysqld to access files outside of vardir + mtr_add_arg($args, "%s--secure-file-priv=%s", $prefix, $opt_vardir); + } + + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); + } + + mtr_add_arg($args, "%s--character-set-server=latin1", $prefix); + mtr_add_arg($args, "%s--lc-messages-dir=%s", $prefix, $path_language); + mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); + + # Increase default connect_timeout to avoid intermittent + # disconnects when test servers are put under load + # see BUG#28359 + mtr_add_arg($args, "%s--connect-timeout=60", $prefix); + + + # When mysqld is run by a root user(euid is 0), it will fail + # to start unless we specify what user to run as, see BUG#30630 + my $euid= $>; + if (!$glob_win32 and $euid == 0 and + grep(/^--user/, @$extra_opt, @opt_extra_mysqld_opt) == 0) { + mtr_add_arg($args, "%s--user=root", $prefix); + } + + if ( $opt_valgrind_mysqld ) + { + if ( $mysql_version_id < 50100 ) + { + mtr_add_arg($args, "%s--skip-bdb", $prefix); + } + } + + mtr_add_arg($args, "%s--pid-file=%s", $prefix, + $mysqld->{'path_pid'}); + + mtr_add_arg($args, "%s--port=%d", $prefix, + $mysqld->{'port'}); + + mtr_add_arg($args, "%s--socket=%s", $prefix, + $mysqld->{'path_sock'}); + + mtr_add_arg($args, "%s--datadir=%s", $prefix, + $mysqld->{'path_myddir'}); + + mtr_add_arg($args, "%s--disable-sync-frm", $prefix); # Faster test + + if (!$opt_extern and $mysql_version_id >= 50106 ) + { + # Turn on logging to bothe tables and file + mtr_add_arg($args, "%s--log-output=table,file", $prefix); + } + + my $log_base_path= "$opt_vardir/log/$mysqld->{'type'}$sidx"; + mtr_add_arg($args, "%s--general-log-file=%s.log", + $prefix, $log_base_path); + mtr_add_arg($args, "%s--general-log", $prefix); + mtr_add_arg($args, + "%s--slow-query-log-file=%s-slow.log", + $prefix, $log_base_path); + mtr_add_arg($args, "%s--slow-query-log", $prefix); + + # Check if "extra_opt" contains --skip-log-bin + my $skip_binlog= grep(/^--skip-log-bin/, @$extra_opt, @opt_extra_mysqld_opt); + if ( $mysqld->{'type'} eq 'master' ) + { + if (! ($opt_skip_master_binlog || $skip_binlog) ) + { + mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, + $opt_vardir, $sidx); + } + + mtr_add_arg($args, "%s--server-id=%d", $prefix, + $idx > 0 ? $idx + 101 : 1); + + mtr_add_arg($args, "%s--loose-innodb_data_file_path=ibdata1:10M:autoextend", + $prefix); + + mtr_add_arg($args, "%s--local-infile", $prefix); + } + else + { + mtr_error("unknown mysqld type") + unless $mysqld->{'type'} eq 'slave'; + + mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix); + if (! ( $opt_skip_slave_binlog || $skip_binlog )) + { + mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, + $opt_vardir, $sidx); # FIXME use own dir for binlogs + mtr_add_arg($args, "%s--log-slave-updates", $prefix); + } + + mtr_add_arg($args, "%s--master-retry-count=10", $prefix); + + mtr_add_arg($args, "%s--relay-log=%s/log/slave%s-relay-bin", $prefix, + $opt_vardir, $sidx); + mtr_add_arg($args, "%s--report-host=127.0.0.1", $prefix); + mtr_add_arg($args, "%s--report-port=%d", $prefix, + $mysqld->{'port'}); + mtr_add_arg($args, "%s--report-user=root", $prefix); + mtr_add_arg($args, "%s--loose-skip-innodb", $prefix); + mtr_add_arg($args, "%s--skip-slave-start", $prefix); + + # Directory where slaves find the dumps generated by "load data" + # on the server. The path need to have constant length otherwise + # test results will vary, thus a relative path is used. + my $slave_load_path= "../tmp"; + mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, + $slave_load_path); + mtr_add_arg($args, "%s--slave_net_timeout=120", $prefix); + + if ( @$slave_master_info ) + { + foreach my $arg ( @$slave_master_info ) + { + mtr_add_arg($args, "%s%s", $prefix, $arg); + } + } + else + { +# NOTE: the backport (see BUG#48048) originally removed the +# commented out lines below. However, given that they are +# protected with a version check (< 50200) now, it should be +# safe to keep them. The problem is that the backported patch +# was into a 5.1 GA codebase - mysql-5.1-rep+2 tree - so +# version is 501XX, consequently check becomes worthless. It +# should be safe to uncomment them when merging up to 5.5. +# +# RQG semisync test runs on the 5.1 GA tree and needs MTR v1. +# This was causing the test to fail (slave would not start +# due to unrecognized option(s)). +# if ($mysql_version_id < 50200) +# { +# mtr_add_arg($args, "%s--master-user=root", $prefix); +# mtr_add_arg($args, "%s--master-connect-retry=1", $prefix); +# mtr_add_arg($args, "%s--master-host=127.0.0.1", $prefix); +# mtr_add_arg($args, "%s--master-password=", $prefix); +# mtr_add_arg($args, "%s--master-port=%d", $prefix, +# $master->[0]->{'port'}); # First master +# } + my $slave_server_id= 2 + $idx; + my $slave_rpl_rank= $slave_server_id; + mtr_add_arg($args, "%s--server-id=%d", $prefix, $slave_server_id); + mtr_add_arg($args, "%s--rpl-recovery-rank=%d", $prefix, $slave_rpl_rank); + } + } # end slave + + if ( $debug_compiled_binaries && defined $opt_debug ) + { + if ( $opt_debug ) + { + mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/%s%s.trace", + $prefix, $path_vardir_trace, $mysqld->{'type'}, $sidx); + } + else + { + mtr_add_arg($args, "--disable-debug"); + } + } + + mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix); + mtr_add_arg($args, "%s--sort_buffer_size=256K", $prefix); + mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix); + + if ( $opt_ssl_supported ) + { + mtr_add_arg($args, "%s--ssl-ca=%s/std_data/cacert.pem", $prefix, + $glob_mysql_test_dir); + mtr_add_arg($args, "%s--ssl-cert=%s/std_data/server-cert.pem", $prefix, + $glob_mysql_test_dir); + mtr_add_arg($args, "%s--ssl-key=%s/std_data/server-key.pem", $prefix, + $glob_mysql_test_dir); + } + + if ( $opt_warnings ) + { + mtr_add_arg($args, "%s--log-warnings", $prefix); + } + + # Indicate to "mysqld" it will be debugged in debugger + if ( $glob_debugger ) + { + mtr_add_arg($args, "%s--gdb", $prefix); + } + + my $found_skip_core= 0; + foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt ) + { + # Allow --skip-core-file to be set in <testname>-[master|slave].opt file + if ($arg eq "--skip-core-file") + { + $found_skip_core= 1; + } + elsif ($skip_binlog and mtr_match_prefix($arg, "--binlog-format")) + { + ; # Dont add --binlog-format when running without binlog + } + else + { + mtr_add_arg($args, "%s%s", $prefix, $arg); + } + } + if ( !$found_skip_core ) + { + mtr_add_arg($args, "%s%s", $prefix, "--core-file"); + } + + if ( $opt_bench ) + { + mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix); + mtr_add_arg($args, "%s--init-rpl-role=master", $prefix); + } + elsif ( $mysqld->{'type'} eq 'master' ) + { + mtr_add_arg($args, "%s--open-files-limit=1024", $prefix); + } + + return $args; +} + + +############################################################################## +# +# Start mysqld and return the PID +# +############################################################################## + +sub mysqld_start ($$$) { + my $mysqld= shift; + my $extra_opt= shift; + my $slave_master_info= shift; + + my $args; # Arg vector + my $exe; + my $pid= -1; + my $wait_for_pid_file= 1; + + my $type= $mysqld->{'type'}; + my $idx= $mysqld->{'idx'}; + + mtr_error("Internal error: mysqld should never be started for embedded") + if $glob_use_embedded_server; + + if ( $type eq 'master' ) + { + $exe= $exe_master_mysqld; + } + elsif ( $type eq 'slave' ) + { + $exe= $exe_slave_mysqld; + } + else + { + mtr_error("Unknown 'type' \"$type\" passed to mysqld_start"); + } + + mtr_init_args(\$args); + + if ( $opt_valgrind_mysqld ) + { + valgrind_arguments($args, \$exe); + } + + mysqld_arguments($args,$mysqld,$extra_opt,$slave_master_info); + + if ( $opt_gdb || $opt_manual_gdb) + { + gdb_arguments(\$args, \$exe, "$type"."_$idx"); + } + elsif ( $opt_ddd || $opt_manual_ddd ) + { + ddd_arguments(\$args, \$exe, "$type"."_$idx"); + } + elsif ( $opt_debugger ) + { + debugger_arguments(\$args, \$exe, "$type"."_$idx"); + } + elsif ( $opt_manual_debug ) + { + print "\nStart $type in your debugger\n" . + "dir: $glob_mysql_test_dir\n" . + "exe: $exe\n" . + "args: " . join(" ", @$args) . "\n\n" . + "Waiting ....\n"; + + # Indicate the exe should not be started + $exe= undef; + } + else + { + # Default to not wait until pid file has been created + $wait_for_pid_file= 0; + } + + # Remove the pidfile + unlink($mysqld->{'path_pid'}); + + if ( defined $exe ) + { + $pid= mtr_spawn($exe, $args, "", + $mysqld->{'path_myerr'}, + $mysqld->{'path_myerr'}, + "", + { append_log_file => 1 }); + } + + + if ( $wait_for_pid_file && !sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + $pid)) + { + + mtr_error("Failed to start mysqld $mysqld->{'type'}"); + } + + + # Remember pid of the started process + $mysqld->{'pid'}= $pid; + + # Remember options used when starting + $mysqld->{'start_opts'}= $extra_opt; + $mysqld->{'start_slave_master_info'}= $slave_master_info; + + mtr_verbose("mysqld pid: $pid"); + return $pid; +} + + +sub stop_all_servers () { + + mtr_report("Stopping All Servers"); + + my %admin_pids; # hash of admin processes that requests shutdown + my @kill_pids; # list of processes to shutdown/kill + my $pid; + + # Start shutdown of all started masters + foreach my $mysqld (@{$slave}, @{$master}) + { + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + real_pid => $mysqld->{'real_pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + errfile => $mysqld->{'path_myerr'}, + }); + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + + # Wait blocking until all shutdown processes has completed + mtr_wait_blocking(\%admin_pids); + + # Make sure that process has shutdown else try to kill them + mtr_check_stop_servers(\@kill_pids); +} + + +sub run_testcase_need_master_restart($) +{ + my ($tinfo)= @_; + + # We try to find out if we are to restart the master(s) + my $do_restart= 0; # Assumes we don't have to + + if ( $glob_use_embedded_server ) + { + mtr_verbose("Never start or restart for embedded server"); + return $do_restart; + } + elsif ( $tinfo->{'master_sh'} ) + { + $do_restart= 1; # Always restart if script to run + mtr_verbose("Restart master: Always restart if script to run"); + } + if ( $tinfo->{'force_restart'} ) + { + $do_restart= 1; # Always restart if --force-restart in -opt file + mtr_verbose("Restart master: Restart forced with --force-restart"); + } + elsif ( $master->[0]->{'running_master_options'} and + $master->[0]->{'running_master_options'}->{'timezone'} ne + $tinfo->{'timezone'}) + { + $do_restart= 1; + mtr_verbose("Restart master: Different timezone"); + } + # Check that running master was started with same options + # as the current test requires + elsif (! mtr_same_opts($master->[0]->{'start_opts'}, + $tinfo->{'master_opt'}) ) + { + $do_restart= 1; + mtr_verbose("Restart master: running with different options '" . + join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . + join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); + } + elsif( ! $master->[0]->{'pid'} ) + { + if ( $opt_extern ) + { + $do_restart= 0; + mtr_verbose("No restart: using extern master"); + } + else + { + $do_restart= 1; + mtr_verbose("Restart master: master is not started"); + } + } + return $do_restart; +} + +sub run_testcase_need_slave_restart($) +{ + my ($tinfo)= @_; + + # We try to find out if we are to restart the slaves + my $do_slave_restart= 0; # Assumes we don't have to + + if ( $glob_use_embedded_server ) + { + mtr_verbose("Never start or restart for embedded server"); + return $do_slave_restart; + } + elsif ( $max_slave_num == 0) + { + mtr_verbose("Skip slave restart: No testcase use slaves"); + } + else + { + + # Check if any slave is currently started + my $any_slave_started= 0; + foreach my $mysqld (@{$slave}) + { + if ( $mysqld->{'pid'} ) + { + $any_slave_started= 1; + last; + } + } + + if ($any_slave_started) + { + mtr_verbose("Restart slave: Slave is started, always restart"); + $do_slave_restart= 1; + } + elsif ( $tinfo->{'slave_num'} ) + { + mtr_verbose("Restart slave: Test need slave"); + $do_slave_restart= 1; + } + } + + return $do_slave_restart; + +} + +# ---------------------------------------------------------------------- +# If not using a running servers we may need to stop and restart. +# We restart in the case we have initiation scripts, server options +# etc to run. But we also restart again after the test first restart +# and test is run, to get back to normal server settings. +# +# To make the code a bit more clean, we actually only stop servers +# here, and mark this to be done. Then a generic "start" part will +# start up the needed servers again. +# ---------------------------------------------------------------------- + +sub run_testcase_stop_servers($$$) { + my ($tinfo, $do_restart, $do_slave_restart)= @_; + my $pid; + my %admin_pids; # hash of admin processes that requests shutdown + my @kill_pids; # list of processes to shutdown/kill + + # Remember if we restarted for this test case (count restarts) + $tinfo->{'restarted'}= $do_restart; + + if ( $do_restart ) + { + delete $master->[0]->{'running_master_options'}; # Forget history + + # Start shutdown of all started masters + foreach my $mysqld (@{$master}) + { + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 20); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + real_pid => $mysqld->{'real_pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + errfile => $mysqld->{'path_myerr'}, + }); + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + } + + if ( $do_restart || $do_slave_restart ) + { + + delete $slave->[0]->{'running_slave_options'}; # Forget history + + # Start shutdown of all started slaves + foreach my $mysqld (@{$slave}) + { + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 20); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + real_pid => $mysqld->{'real_pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + errfile => $mysqld->{'path_myerr'}, + }); + + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + } + + # ---------------------------------------------------------------------- + # Shutdown has now been started and lists for the shutdown processes + # and the processes to be killed has been created + # ---------------------------------------------------------------------- + + # Wait blocking until all shutdown processes has completed + mtr_wait_blocking(\%admin_pids); + + + # Make sure that process has shutdown else try to kill them + mtr_check_stop_servers(\@kill_pids); +} + + +# +# run_testcase_start_servers +# +# Start the servers needed by this test case +# +# RETURN +# 0 OK +# 1 Start failed +# + +sub run_testcase_start_servers($) { + my $tinfo= shift; + my $tname= $tinfo->{'name'}; + + if ( $tinfo->{'component_id'} eq 'mysqld' ) + { + if ( !$master->[0]->{'pid'} ) + { + # Master mysqld is not started + do_before_start_master($tinfo); + + mysqld_start($master->[0],$tinfo->{'master_opt'},[]); + + } + + # Save this test case information, so next can examine it + $master->[0]->{'running_master_options'}= $tinfo; + } + + # ---------------------------------------------------------------------- + # Start slaves - if needed + # ---------------------------------------------------------------------- + if ( $tinfo->{'slave_num'} ) + { + restore_slave_databases($tinfo->{'slave_num'}); + + do_before_start_slave($tinfo); + + for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) + { + if ( ! $slave->[$idx]->{'pid'} ) + { + mysqld_start($slave->[$idx],$tinfo->{'slave_opt'}, + $tinfo->{'slave_mi'}); + + } + } + + # Save this test case information, so next can examine it + $slave->[0]->{'running_slave_options'}= $tinfo; + } + + # Wait for mysqld's to start + foreach my $mysqld (@{$master},@{$slave}) + { + + next if !$mysqld->{'pid'}; + + if (mysqld_wait_started($mysqld)) + { + # failed to start + $tinfo->{'comment'}= + "Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"; + return 1; + } + } + return 0; +} + +# +# Run include/check-testcase.test +# Before a testcase, run in record mode, save result file to var +# After testcase, run and compare with the recorded file, they should be equal! +# +# RETURN VALUE +# 0 OK +# 1 Check failed +# +sub run_check_testcase ($$) { + + my $mode= shift; + my $mysqld= shift; + + my $name= "check-" . $mysqld->{'type'} . $mysqld->{'idx'}; + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--silent"); + mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); + + mtr_add_arg($args, "--socket=%s", $mysqld->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $mysqld->{'port'}); + mtr_add_arg($args, "--database=test"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--password="); + + mtr_add_arg($args, "-R"); + mtr_add_arg($args, "$opt_vardir/tmp/$name.result"); + + if ( $mode eq "before" ) + { + mtr_add_arg($args, "--record"); + } + + my $res = mtr_run_test($exe_mysqltest,$args, + "include/check-testcase.test", "", "", ""); + + if ( $res == 1 and $mode eq "after") + { + mtr_run("diff",["-u", + "$opt_vardir/tmp/$name.result", + "$opt_vardir/tmp/$name.reject"], + "", "", "", ""); + } + elsif ( $res ) + { + mtr_error("Could not execute 'check-testcase' $mode testcase"); + } + return $res; +} + +############################################################################## +# +# Report the features that were compiled in +# +############################################################################## + +sub run_report_features () { + my $args; + + if ( ! $glob_use_embedded_server ) + { + mysqld_start($master->[0],[],[]); + if ( ! $master->[0]->{'pid'} ) + { + mtr_error("Can't start the mysqld server"); + } + mysqld_wait_started($master->[0]); + } + + my $tinfo = {}; + $tinfo->{'name'} = 'report features'; + $tinfo->{'result_file'} = undef; + $tinfo->{'component_id'} = 'mysqld'; + $tinfo->{'path'} = 'include/report-features.test'; + $tinfo->{'timezone'}= "GMT-3"; + $tinfo->{'slave_num'} = 0; + $tinfo->{'master_opt'} = []; + $tinfo->{'slave_opt'} = []; + $tinfo->{'slave_mi'} = []; + $tinfo->{'comment'} = 'report server features'; + run_mysqltest($tinfo); + + if ( ! $glob_use_embedded_server ) + { + stop_all_servers(); + } +} + + +sub run_mysqltest ($) { + my ($tinfo)= @_; + my $exe= $exe_mysqltest; + my $args; + + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--silent"); + mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); + mtr_add_arg($args, "--logdir=%s/log", $opt_vardir); + + # Log line number and time for each line in .test file + mtr_add_arg($args, "--mark-progress") + if $opt_mark_progress; + + # component_id == mysqld + { + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $master->[0]->{'port'}); + mtr_add_arg($args, "--database=test"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--password="); + } + + if ( $opt_ps_protocol ) + { + mtr_add_arg($args, "--ps-protocol"); + } + + if ( $opt_sp_protocol ) + { + mtr_add_arg($args, "--sp-protocol"); + } + + if ( $opt_view_protocol ) + { + mtr_add_arg($args, "--view-protocol"); + } + + if ( $opt_cursor_protocol ) + { + mtr_add_arg($args, "--cursor-protocol"); + } + + if ( $opt_strace_client ) + { + $exe= "strace"; # FIXME there are ktrace, .... + mtr_add_arg($args, "-o"); + mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir); + mtr_add_arg($args, "$exe_mysqltest"); + } + + if ( $opt_timer ) + { + mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir); + } + + if ( $opt_compress ) + { + mtr_add_arg($args, "--compress"); + } + + if ( $opt_sleep ) + { + mtr_add_arg($args, "--sleep=%d", $opt_sleep); + } + + if ( $opt_debug ) + { + mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", + $path_vardir_trace); + } + + if ( $opt_ssl_supported ) + { + mtr_add_arg($args, "--ssl-ca=%s/std_data/cacert.pem", + $glob_mysql_test_dir); + mtr_add_arg($args, "--ssl-cert=%s/std_data/client-cert.pem", + $glob_mysql_test_dir); + mtr_add_arg($args, "--ssl-key=%s/std_data/client-key.pem", + $glob_mysql_test_dir); + } + + if ( $opt_ssl ) + { + # Turn on SSL for _all_ test cases if option --ssl was used + mtr_add_arg($args, "--ssl"); + } + elsif ( $opt_ssl_supported ) + { + mtr_add_arg($args, "--skip-ssl"); + } + + foreach my $arg ( @opt_extra_mysqltest_opt ) + { + mtr_add_arg($args, "%s", $arg); + } + + # ---------------------------------------------------------------------- + # If embedded server, we create server args to give mysqltest to pass on + # ---------------------------------------------------------------------- + + if ( $glob_use_embedded_server ) + { + mysqld_arguments($args,$master->[0],$tinfo->{'master_opt'},[]); + } + + # ---------------------------------------------------------------------- + # export MYSQL_TEST variable containing <path>/mysqltest <args> + # ---------------------------------------------------------------------- + $ENV{'MYSQL_TEST'}= + mtr_native_path($exe_mysqltest) . " " . join(" ", @$args); + + # ---------------------------------------------------------------------- + # Add arguments that should not go into the MYSQL_TEST env var + # ---------------------------------------------------------------------- + + if ( $opt_valgrind_mysqltest ) + { + # Prefix the Valgrind options to the argument list. + # We do this here, since we do not want to Valgrind the nested invocations + # of mysqltest; that would mess up the stderr output causing test failure. + my @args_saved = @$args; + mtr_init_args(\$args); + valgrind_arguments($args, \$exe); + mtr_add_arg($args, "%s", $_) for @args_saved; + } + + mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'}); + + # Number of lines of resut to include in failure report + mtr_add_arg($args, "--tail-lines=20"); + + if ( defined $tinfo->{'result_file'} ) { + mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'}); + } + + if ( $opt_record ) + { + mtr_add_arg($args, "--record"); + } + + if ( $opt_client_gdb ) + { + gdb_arguments(\$args, \$exe, "client"); + } + elsif ( $opt_client_ddd ) + { + ddd_arguments(\$args, \$exe, "client"); + } + elsif ( $opt_client_debugger ) + { + debugger_arguments(\$args, \$exe, "client"); + } + + if ( $opt_check_testcases ) + { + foreach my $mysqld (@{$master}, @{$slave}) + { + if ($mysqld->{'pid'}) + { + run_check_testcase("before", $mysqld); + } + } + } + + my $res = mtr_run_test($exe,$args,"","",$path_timefile,""); + + if ( $opt_check_testcases ) + { + foreach my $mysqld (@{$master}, @{$slave}) + { + if ($mysqld->{'pid'}) + { + if (run_check_testcase("after", $mysqld)) + { + # Check failed, mark the test case with that info + $tinfo->{'check_testcase_failed'}= 1; + } + } + } + } + + return $res; + +} + + +# +# Modify the exe and args so that program is run in gdb in xterm +# +sub gdb_arguments { + my $args= shift; + my $exe= shift; + my $type= shift; + + # Write $args to gdb init file + my $str= join(" ", @$$args); + my $gdb_init_file= "$opt_tmpdir/gdbinit.$type"; + + # Remove the old gdbinit file + unlink($gdb_init_file); + + if ( $type eq "client" ) + { + # write init file for client + mtr_tofile($gdb_init_file, + "set args $str\n" . + "break main\n"); + } + else + { + # write init file for mysqld + mtr_tofile($gdb_init_file, <<EOGDB ); +set args $str +EOGDB + } + + if ( $opt_manual_gdb ) + { + print "\nTo start gdb for $type, type in another window:\n"; + print "gdb -cd $glob_mysql_test_dir -x $gdb_init_file $$exe\n"; + + # Indicate the exe should not be started + $$exe= undef; + return; + } + + $$args= []; + mtr_add_arg($$args, "-title"); + mtr_add_arg($$args, "$type"); + mtr_add_arg($$args, "-e"); + + if ( $exe_libtool ) + { + mtr_add_arg($$args, $exe_libtool); + mtr_add_arg($$args, "--mode=execute"); + } + + mtr_add_arg($$args, "gdb"); + mtr_add_arg($$args, "-x"); + mtr_add_arg($$args, "$gdb_init_file"); + mtr_add_arg($$args, "$$exe"); + + $$exe= "xterm"; +} + + +# +# Modify the exe and args so that program is run in ddd +# +sub ddd_arguments { + my $args= shift; + my $exe= shift; + my $type= shift; + + # Write $args to ddd init file + my $str= join(" ", @$$args); + my $gdb_init_file= "$opt_tmpdir/gdbinit.$type"; + + # Remove the old gdbinit file + unlink($gdb_init_file); + + if ( $type eq "client" ) + { + # write init file for client + mtr_tofile($gdb_init_file, + "set args $str\n" . + "break main\n"); + } + else + { + # write init file for mysqld + mtr_tofile($gdb_init_file, + "file $$exe\n" . + "set args $str\n"); + } + + if ( $opt_manual_ddd ) + { + print "\nTo start ddd for $type, type in another window:\n"; + print "ddd -cd $glob_mysql_test_dir -x $gdb_init_file $$exe\n"; + + # Indicate the exe should not be started + $$exe= undef; + return; + } + + my $save_exe= $$exe; + $$args= []; + if ( $exe_libtool ) + { + $$exe= $exe_libtool; + mtr_add_arg($$args, "--mode=execute"); + mtr_add_arg($$args, "ddd"); + } + else + { + $$exe= "ddd"; + } + mtr_add_arg($$args, "--command=$gdb_init_file"); + mtr_add_arg($$args, "$save_exe"); +} + + +# +# Modify the exe and args so that program is run in the selected debugger +# +sub debugger_arguments { + my $args= shift; + my $exe= shift; + my $debugger= $opt_debugger || $opt_client_debugger; + + if ( $debugger =~ /vcexpress|vc|devenv/ ) + { + # vc[express] /debugexe exe arg1 .. argn + + # Add /debugexe and name of the exe before args + unshift(@$$args, "/debugexe"); + unshift(@$$args, "$$exe"); + + # Set exe to debuggername + $$exe= $debugger; + + } + elsif ( $debugger =~ /windbg/ ) + { + # windbg exe arg1 .. argn + + # Add name of the exe before args + unshift(@$$args, "$$exe"); + + # Set exe to debuggername + $$exe= $debugger; + + } + elsif ( $debugger eq "dbx" ) + { + # xterm -e dbx -r exe arg1 .. argn + + unshift(@$$args, $$exe); + unshift(@$$args, "-r"); + unshift(@$$args, $debugger); + unshift(@$$args, "-e"); + + $$exe= "xterm"; + + } + else + { + mtr_error("Unknown argument \"$debugger\" passed to --debugger"); + } +} + + +# +# Modify the exe and args so that program is run in valgrind +# +sub valgrind_arguments { + my $args= shift; + my $exe= shift; + + if ( $opt_callgrind) + { + mtr_add_arg($args, "--tool=callgrind"); + mtr_add_arg($args, "--base=$opt_vardir/log"); + } + else + { + mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option + mtr_add_arg($args, "--leak-check=yes"); + #mtr_add_arg($args, "--db-attach=yes"); + mtr_add_arg($args, "--num-callers=16"); + mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) + if -f "$glob_mysql_test_dir/valgrind.supp"; + } + + # Add valgrind options, can be overridden by user + mtr_add_arg($args, '%s', $_) for (@valgrind_args); + + mtr_add_arg($args, $$exe); + + $$exe= $opt_valgrind_path || "valgrind"; + + if ($exe_libtool) + { + # Add "libtool --mode-execute" before the test to execute + # if running in valgrind(to avoid valgrinding bash) + unshift(@$args, "--mode=execute", $$exe); + $$exe= $exe_libtool; + } +} + + +############################################################################## +# +# Usage +# +############################################################################## + +sub usage ($) { + my $message= shift; + + if ( $message ) + { + print STDERR "$message\n"; + } + + print <<HERE; + +$0 [ OPTIONS ] [ TESTCASE ] + +Options to control what engine/variation to run + + embedded-server Use the embedded server, i.e. no mysqld daemons + ps-protocol Use the binary protocol between client and server + cursor-protocol Use the cursor protocol between client and server + (implies --ps-protocol) + view-protocol Create a view to execute all non updating queries + sp-protocol Create a stored procedure to execute all queries + compress Use the compressed protocol between client and server + ssl Use ssl protocol between client and server + skip-ssl Dont start server with support for ssl connections + bench Run the benchmark suite + small-bench Run the benchmarks with --small-tests --small-tables + vs-config Visual Studio configuration used to create executables + (default: MTR_VS_CONFIG environment variable) + +Options to control directories to use + benchdir=DIR The directory where the benchmark suite is stored + (default: ../../mysql-bench) + tmpdir=DIR The directory where temporary files are stored + (default: ./var/tmp). + vardir=DIR The directory where files generated from the test run + is stored (default: ./var). Specifying a ramdisk or + tmpfs will speed up tests. + mem Run testsuite in "memory" using tmpfs or ramdisk + Attempts to find a suitable location + using a builtin list of standard locations + for tmpfs (/dev/shm) + The option can also be set using environment + variable MTR_MEM=[DIR] + +Options to control what test suites or cases to run + + force Continue to run the suite after failure + do-test=PREFIX or REGEX + Run test cases which name are prefixed with PREFIX + or fulfills REGEX + skip-test=PREFIX or REGEX + Skip test cases which name are prefixed with PREFIX + or fulfills REGEX + start-from=PREFIX Run test cases starting from test prefixed with PREFIX + suite[s]=NAME1,..,NAMEN Collect tests in suites from the comma separated + list of suite names. + The default is: "$opt_suites_default" + skip-rpl Skip the replication test cases. + big-test Set the environment variable BIG_TEST, which can be + checked from test cases. + combination="ARG1 .. ARG2" Specify a set of "mysqld" arguments for one + combination. + skip-combination Skip any combination options and combinations files + +Options that specify ports + + master_port=PORT Specify the port number used by the first master + slave_port=PORT Specify the port number used by the first slave + mtr-build-thread=# Specify unique collection of ports. Can also be set by + setting the environment variable MTR_BUILD_THREAD. + +Options for test case authoring + + record TESTNAME (Re)genereate the result file for TESTNAME + check-testcases Check testcases for sideeffects + mark-progress Log line number and elapsed time to <testname>.progress + +Options that pass on options + + mysqld=ARGS Specify additional arguments to "mysqld" + +Options to run test on running server + + extern Use running server for tests + user=USER User for connection to extern server + socket=PATH Socket for connection to extern server + +Options for debugging the product + + client-ddd Start mysqltest client in ddd + client-debugger=NAME Start mysqltest in the selected debugger + client-gdb Start mysqltest client in gdb + ddd Start mysqld in ddd + debug Dump trace output for all servers and client programs + debugger=NAME Start mysqld in the selected debugger + gdb Start the mysqld(s) in gdb + manual-debug Let user manually start mysqld in debugger, before + running test(s) + manual-gdb Let user manually start mysqld in gdb, before running + test(s) + manual-ddd Let user manually start mysqld in ddd, before running + test(s) + master-binary=PATH Specify the master "mysqld" to use + slave-binary=PATH Specify the slave "mysqld" to use + strace-client Create strace output for mysqltest client + max-save-core Limit the number of core files saved (to avoid filling + up disks for heavily crashing server). Defaults to + $opt_max_save_core, set to 0 for no limit. + +Options for coverage, profiling etc + + gcov FIXME + gprof FIXME + valgrind Run the "mysqltest" and "mysqld" executables using + valgrind with default options + valgrind-all Synonym for --valgrind + valgrind-mysqltest Run the "mysqltest" and "mysql_client_test" executable + with valgrind + valgrind-mysqld Run the "mysqld" executable with valgrind + valgrind-options=ARGS Deprecated, use --valgrind-option + valgrind-option=ARGS Option to give valgrind, replaces default option(s), + can be specified more then once + valgrind-path=[EXE] Path to the valgrind executable + callgrind Instruct valgrind to use callgrind + +Misc options + + comment=STR Write STR to the output + notimer Don't show test case execution time + script-debug Debug this script itself + verbose More verbose output + start-and-exit Only initialize and start the servers, using the + startup settings for the specified test case (if any) + start-dirty Only start the servers (without initialization) for + the specified test case (if any) + fast Don't try to clean up from earlier runs + reorder Reorder tests to get fewer server restarts + help Get this help text + + testcase-timeout=MINUTES Max test case run time (default $default_testcase_timeout) + suite-timeout=MINUTES Max test suite run time (default $default_suite_timeout) + warnings | log-warnings Pass --log-warnings to mysqld + + sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time + client-bindir=PATH Path to the directory where client binaries are located + client-libdir=PATH Path to the directory where client libraries are located + +Deprecated options + with-openssl Deprecated option for ssl + + +HERE + mtr_exit(1); + +} + +sub list_options ($) { + my $hash= shift; + + for (keys %$hash) { + s/(=.*|!)$//; + s/\|/\n--/g; + print "--$_\n"; + } + + mtr_exit(1); +} |