#!/usr/bin/perl # -*- cperl -*- # This is a transformation of the "mysql-test-run" Bourne shell script # to Perl. There are reasons this rewrite is not the prettiest Perl # you have seen # # - The original script is huge and for most part uncommented, # not even a usage description of the flags. # # - There has been an attempt to write a replacement in C for the # original Bourne shell script. It was kind of working but lacked # lot of functionality to really be a replacement. Not to redo # that mistake and catch all the obscure features of the original # script, the rewrite in Perl is more close to the original script # meaning it also share some of the ugly parts as well. # # - The original intention was that this script was to be a prototype # to be the base for a new C version with full functionality. Since # then it was decided that the Perl version should replace the # Bourne shell version, but the Perl style still reflects the wish # to make the Perl to C step easy. # # Some coding style from the original intent has been kept # # - To make this Perl script easy to alter even for those that not # code Perl that often, the coding style is 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. # # - At the moment, there are tons of "global" variables that control # this script, even accessed from the files in "lib/*.pl". This # will change over time, for now global variables are used instead # of using %opt, %path and %exe hashes, because I want more # compile time checking, that hashes would not give me. Once this # script is debugged, hashes will be used and passed as parameters # to functions, to more closely mimic how it would be coded in C # using structs. # # - 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" # # FIXME Save a PID file from this code as well, to record the process # id we think it has. In Cygwin, a fork creates one Cygwin process, # and then the real Win32 process. Cygwin Perl can only kill Cygwin # processes. And "mysqld --bootstrap ..." doesn't save a PID file. $Devel::Trace::TRACE= 0; # Don't trace boring init stuff #require 5.6.1; use File::Path; use File::Basename; use File::Copy; use Cwd; use Getopt::Long; use Sys::Hostname; #use Carp; use IO::Socket; use IO::Socket::INET; use Data::Dumper; use strict; #use diagnostics; require "lib/mtr_cases.pl"; require "lib/mtr_process.pl"; require "lib/mtr_timer.pl"; require "lib/mtr_io.pl"; require "lib/mtr_gcov.pl"; require "lib/mtr_gprof.pl"; require "lib/mtr_report.pl"; require "lib/mtr_diff.pl"; require "lib/mtr_match.pl"; require "lib/mtr_misc.pl"; $Devel::Trace::TRACE= 1; # Used by gcov our @mysqld_src_dirs= ( "strings", "mysys", "include", "extra", "regex", "isam", "merge", "myisam", "myisammrg", "heap", "sql", ); ############################################################################## # # Default settings # ############################################################################## # We are to use handle_options() in "mysys/my_getopt.c" for the C version # # In the C version we want to use structs and, in some cases, arrays of # structs. We let each struct be a separate hash. # Misc global variables our $glob_win32= 0; # OS and native Win32 executables our $glob_win32_perl= 0; # ActiveState Win32 Perl our $glob_cygwin_perl= 0; # Cygwin Perl our $glob_cygwin_shell= undef; our $glob_mysql_test_dir= undef; our $glob_mysql_bench_dir= undef; our $glob_hostname= undef; our $glob_scriptname= undef; our $glob_timers= undef; our $glob_use_running_server= 0; our $glob_use_running_ndbcluster= 0; our $glob_use_embedded_server= 0; our @glob_test_mode; our $glob_basedir; # The total result our $path_charsetsdir; our $path_client_bindir; our $path_language; our $path_timefile; our $path_manager_log; # Used by mysqldadmin our $path_slave_load_tmpdir; # What is this?! our $path_mysqltest_log; our $path_my_basedir; our $opt_vardir; # A path but set directly on cmd line our $opt_tmpdir; # A path but set directly on cmd line our $opt_usage; our $opt_suite; our $opt_netware; our $opt_script_debug= 0; # Script debugging, enable with --script-debug # Options FIXME not all.... our $exe_master_mysqld; our $exe_mysql; our $exe_mysqladmin; our $exe_mysqlbinlog; our $exe_mysql_client_test; our $exe_mysqld; our $exe_mysqldump; # Called from test case our $exe_mysqlimport; # Called from test case our $exe_mysqlshow; # Called from test case our $exe_mysql_fix_system_tables; our $exe_mysqltest; our $exe_slave_mysqld; our $exe_my_print_defaults; our $opt_bench= 0; our $opt_small_bench= 0; our $opt_big_test= 0; # Send --big-test to mysqltest our @opt_extra_mysqld_opt; our $opt_comment; our $opt_compress; our $opt_current_test; our $opt_ddd; our $opt_debug; our $opt_do_test; our @opt_cases; # The test cases names in argv our $opt_embedded_server; our $opt_extern; our $opt_fast; our $opt_force; our $opt_reorder; our $opt_gcov; our $opt_gcov_err; our $opt_gcov_msg; our $opt_gdb; our $opt_client_gdb; our $opt_manual_gdb; our $opt_gprof; our $opt_gprof_dir; our $opt_gprof_master; our $opt_gprof_slave; our $opt_local; our $opt_local_master; our $master; # Will be struct in C our $slave; our $opt_ndbcluster_port; our $opt_ndbconnectstring; our $opt_no_manager; # Does nothing now, we never use manager our $opt_manager_port; # Does nothing now, we never use manager our $opt_old_master; our $opt_record; our $opt_result_ext; our $opt_skip; our $opt_skip_rpl; our $opt_skip_test; our $opt_sleep; our $opt_ps_protocol; our $opt_sleep_time_after_restart= 1; our $opt_sleep_time_for_delete= 10; our $opt_testcase_timeout; our $opt_suite_timeout; my $default_testcase_timeout= 15; # 15 min max my $default_suite_timeout= 120; # 2 hours max our $opt_socket; our $opt_source_dist; our $opt_start_and_exit; our $opt_start_dirty; our $opt_start_from; our $opt_strace_client; our $opt_timer; our $opt_user; our $opt_user_test; our $opt_valgrind; our $opt_valgrind_mysqld; our $opt_valgrind_mysqltest; our $opt_valgrind_all; our $opt_valgrind_options; our $opt_verbose; our $opt_wait_for_master; our $opt_wait_for_slave; our $opt_wait_timeout= 10; our $opt_warnings; our $opt_udiff; our $opt_skip_ndbcluster; our $opt_with_ndbcluster; our $opt_with_ndbcluster_only= 0; # dummy, ignored our $opt_with_openssl; our $exe_ndb_mgm; our $path_ndb_tools_dir; our $path_ndb_backup_dir; our $file_ndb_testrun_log; our $flag_ndb_status_ok= 1; ###################################################################### # # Function declarations # ###################################################################### sub main (); sub initial_setup (); sub command_line_setup (); sub executable_setup (); sub environment_setup (); sub kill_running_server (); sub kill_and_cleanup (); sub ndbcluster_support (); sub ndbcluster_install (); sub ndbcluster_start (); sub ndbcluster_stop (); sub run_benchmarks ($); sub run_tests (); sub mysql_install_db (); sub install_db ($$); sub run_testcase ($); sub report_failure_and_restart ($); sub do_before_start_master ($$); sub do_before_start_slave ($$); sub mysqld_start ($$$$); sub mysqld_arguments ($$$$$); sub stop_masters_slaves (); sub stop_masters (); sub stop_slaves (); sub run_mysqltest ($); sub usage ($); ###################################################################### # # Main program # ###################################################################### main(); sub main () { initial_setup(); command_line_setup(); executable_setup(); if (! $opt_skip_ndbcluster and ! $opt_with_ndbcluster) { $opt_with_ndbcluster= ndbcluster_support(); } environment_setup(); signal_setup(); if ( $opt_gcov ) { gcov_prepare(); } if ( $opt_gprof ) { gprof_prepare(); } if ( ! $glob_use_running_server ) { if ( $opt_start_dirty ) { kill_running_server(); } else { kill_and_cleanup(); mysql_install_db(); # mysql_loadstd(); FIXME copying from "std_data" .frm and # .MGR but there are none?! } } if ( $opt_start_dirty ) { if ( ndbcluster_start() ) { mtr_error("Can't start ndbcluster"); } if ( mysqld_start('master',0,[],[]) ) { mtr_report("Servers started, exiting"); } else { mtr_error("Can't start the mysqld server"); } } elsif ( $opt_bench ) { run_benchmarks(shift); # Shift what? Extra arguments?! } else { run_tests(); } mtr_exit(0); } ############################################################################## # # Initial setup independent on command line arguments # ############################################################################## sub initial_setup () { select(STDOUT); $| = 1; # Make unbuffered $glob_scriptname= basename($0); $glob_win32_perl= ($^O eq "MSWin32"); $glob_cygwin_perl= ($^O eq "cygwin"); $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); # 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 to the mysql-test directory and execute the script " . "as follows:\n./$glob_scriptname"); } if ( -d "../sql" ) { $opt_source_dist= 1; } $glob_hostname= mtr_short_hostname(); # 'basedir' is always parent of "mysql-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"`; my $shell= $ENV{'SHELL'} || "/bin/bash"; $glob_cygwin_shell= `cygpath -w "$shell"`; # The Windows path c:\... chomp($glob_mysql_test_dir); chomp($glob_cygwin_shell); } $glob_basedir= dirname($glob_mysql_test_dir); $glob_mysql_bench_dir= "$glob_basedir/mysql-bench"; # FIXME make configurable # needs to be same length to test logging (FIXME what???) $path_slave_load_tmpdir= "../../var/tmp"; $path_my_basedir= $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; $glob_timers= mtr_init_timers(); } ############################################################################## # # Default settings # ############################################################################## sub command_line_setup () { # These are defaults for things that are set on the command line $opt_suite= "main"; # Special default suite my $opt_master_myport= 9306; my $opt_slave_myport= 9308; $opt_ndbcluster_port= 9350; # # 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 limiteation 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 if ( $ENV{'MTR_BUILD_THREAD'} ) { # Up to two masters, up to three slaves $opt_master_myport= $ENV{'MTR_BUILD_THREAD'} * 10 + 10000; # and 1 $opt_slave_myport= $opt_master_myport + 2; # and 3 4 $opt_ndbcluster_port= $opt_master_myport + 5; } 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)"); } # Read the command line # Note: Keep list, and the order, in sync with usage at end of this file Getopt::Long::Configure("pass_through"); GetOptions( # Control what engine/variation to run 'embedded-server' => \$opt_embedded_server, 'ps-protocol' => \$opt_ps_protocol, 'bench' => \$opt_bench, 'small-bench' => \$opt_small_bench, 'no-manager' => \$opt_no_manager, # Currently not used # Control what test suites or cases to run 'force' => \$opt_force, 'with-ndbcluster' => \$opt_with_ndbcluster, 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, 'with-ndbcluster-only' => \$opt_with_ndbcluster_only, 'do-test=s' => \$opt_do_test, 'suite=s' => \$opt_suite, 'skip-rpl' => \$opt_skip_rpl, 'skip-test=s' => \$opt_skip_test, # Specify ports 'master_port=i' => \$opt_master_myport, 'slave_port=i' => \$opt_slave_myport, 'ndbcluster_port=i' => \$opt_ndbcluster_port, 'manager-port=i' => \$opt_manager_port, # Currently not used # Test case authoring 'record' => \$opt_record, # ??? 'mysqld=s' => \@opt_extra_mysqld_opt, # Run test on running server 'extern' => \$opt_extern, 'ndbconnectstring=s' => \$opt_ndbconnectstring, # Debugging 'gdb' => \$opt_gdb, 'manual-gdb' => \$opt_manual_gdb, 'client-gdb' => \$opt_client_gdb, 'ddd' => \$opt_ddd, 'strace-client' => \$opt_strace_client, 'master-binary=s' => \$exe_master_mysqld, 'slave-binary=s' => \$exe_slave_mysqld, # Coverage, profiling etc 'gcov' => \$opt_gcov, 'gprof' => \$opt_gprof, 'valgrind:s' => \$opt_valgrind, 'valgrind-mysqltest:s' => \$opt_valgrind_mysqltest, 'valgrind-all:s' => \$opt_valgrind_all, 'valgrind-options=s' => \$opt_valgrind_options, # Misc 'big-test' => \$opt_big_test, 'comment=s' => \$opt_comment, 'compress' => \$opt_compress, 'debug' => \$opt_debug, 'fast' => \$opt_fast, 'local' => \$opt_local, 'local-master' => \$opt_local_master, 'netware' => \$opt_netware, 'old-master' => \$opt_old_master, 'reorder' => \$opt_reorder, 'script-debug' => \$opt_script_debug, 'sleep=i' => \$opt_sleep, 'socket=s' => \$opt_socket, 'start-dirty' => \$opt_start_dirty, 'start-and-exit' => \$opt_start_and_exit, 'start-from=s' => \$opt_start_from, 'timer' => \$opt_timer, 'tmpdir=s' => \$opt_tmpdir, 'unified-diff|udiff' => \$opt_udiff, 'user-test=s' => \$opt_user_test, 'user=s' => \$opt_user, 'vardir=s' => \$opt_vardir, 'verbose' => \$opt_verbose, 'wait-timeout=i' => \$opt_wait_timeout, 'testcase-timeout=i' => \$opt_testcase_timeout, 'suite-timeout=i' => \$opt_suite_timeout, 'warnings|log-warnings' => \$opt_warnings, 'with-openssl' => \$opt_with_openssl, 'help|h' => \$opt_usage, ) or usage("Can't read options"); if ( $opt_usage ) { usage(""); } if ( $opt_comment ) { print "\n"; print '#' x 78, "\n"; print "# $opt_comment\n"; print '#' x 78, "\n\n"; } if ( $opt_with_ndbcluster_only ) { print "# Option '--with-ndbcluster-only' is ignored in this release.\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); } } # -------------------------------------------------------------------------- # Set the "var/" directory, as it is the base for everything else # -------------------------------------------------------------------------- if ( ! $opt_vardir ) { $opt_vardir= "$glob_mysql_test_dir/var"; } # 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"; } # -------------------------------------------------------------------------- # If not set, set these to defaults # -------------------------------------------------------------------------- $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any # FIXME maybe not needed? $path_manager_log= "$opt_vardir/log/manager.log" unless $path_manager_log; $opt_current_test= "$opt_vardir/log/current_test" unless $opt_current_test; # -------------------------------------------------------------------------- # Do sanity checks of command line arguments # -------------------------------------------------------------------------- if ( $opt_extern and $opt_local ) { mtr_error("Can't use --extern and --local at the same time"); } if ( ! $opt_socket ) { # FIXME set default before reading options? # $opt_socket= '@MYSQL_UNIX_ADDR@'; $opt_socket= "/tmp/mysql.sock"; # FIXME } # -------------------------------------------------------------------------- # Look at the command line options and set script flags # -------------------------------------------------------------------------- if ( $opt_record and ! @opt_cases ) { mtr_error("Will not run in record mode without a specific test case"); } if ( $opt_embedded_server ) { $glob_use_embedded_server= 1; push(@glob_test_mode, "embedded"); $opt_skip_rpl= 1; # We never run replication with embedded $opt_skip_ndbcluster= 1; if ( $opt_extern ) { mtr_error("Can't use --extern with --embedded-server"); } } if ( $opt_ps_protocol ) { push(@glob_test_mode, "ps-protocol"); } # FIXME don't understand what this is # if ( $opt_local_master ) # { # $opt_master_myport= 3306; # } if ( $opt_small_bench ) { $opt_bench= 1; } if ( $opt_sleep ) { $opt_sleep_time_after_restart= $opt_sleep; } if ( $opt_gcov and ! $opt_source_dist ) { mtr_error("Coverage test needs the source - please use source dist"); } if ( $opt_gdb ) { $opt_wait_timeout= 300; if ( $opt_extern ) { mtr_error("Can't use --extern with --gdb"); } } if ( $opt_manual_gdb ) { $opt_gdb= 1; if ( $opt_extern ) { mtr_error("Can't use --extern with --manual-gdb"); } } if ( $opt_ddd ) { if ( $opt_extern ) { mtr_error("Can't use --extern with --ddd"); } } if ( $opt_ndbconnectstring ) { $glob_use_running_ndbcluster= 1; $opt_with_ndbcluster= 1; } else { $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port"; } if ( $opt_skip_ndbcluster ) { $opt_with_ndbcluster= 0; } # The ":s" in the argument spec, means we have three different cases # # undefined option not set # "" option set with no argument # "somestring" option is name/path of valgrind executable # Take executable path from any of them, if any $opt_valgrind_mysqld= $opt_valgrind; $opt_valgrind= $opt_valgrind_mysqltest if $opt_valgrind_mysqltest; $opt_valgrind= $opt_valgrind_all if $opt_valgrind_all; # If valgrind flag not defined, define if other valgrind flags are unless ( defined $opt_valgrind ) { $opt_valgrind= "" if defined $opt_valgrind_mysqltest or defined $opt_valgrind_all; } if ( ! $opt_testcase_timeout ) { $opt_testcase_timeout= $default_testcase_timeout; $opt_testcase_timeout*= 10 if defined $opt_valgrind; } if ( ! $opt_suite_timeout ) { $opt_suite_timeout= $default_suite_timeout; $opt_suite_timeout*= 4 if defined $opt_valgrind; } if ( defined $opt_valgrind ) { $opt_sleep_time_after_restart= 10; $opt_sleep_time_for_delete= 60; # >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" } if ( ! $opt_user ) { if ( $glob_use_running_server ) { $opt_user= "test"; } else { $opt_user= "root"; # We want to do FLUSH xxx commands } } # Put this into a hash, will be a C struct $master->[0]= { path_myddir => "$opt_vardir/master-data", path_myerr => "$opt_vardir/log/master.err", path_mylog => "$opt_vardir/log/master.log", path_mypid => "$opt_vardir/run/master.pid", path_mysock => "$opt_tmpdir/master.sock", path_myport => $opt_master_myport, start_timeout => 400, # enough time create innodb tables ndbcluster => 1, # ndbcluster not started }; $master->[1]= { path_myddir => "$opt_vardir/master1-data", path_myerr => "$opt_vardir/log/master1.err", path_mylog => "$opt_vardir/log/master1.log", path_mypid => "$opt_vardir/run/master1.pid", path_mysock => "$opt_tmpdir/master1.sock", path_myport => $opt_master_myport + 1, start_timeout => 400, # enough time create innodb tables }; $slave->[0]= { path_myddir => "$opt_vardir/slave-data", path_myerr => "$opt_vardir/log/slave.err", path_mylog => "$opt_vardir/log/slave.log", path_mypid => "$opt_vardir/run/slave.pid", path_mysock => "$opt_tmpdir/slave.sock", path_myport => $opt_slave_myport, start_timeout => 400, }; $slave->[1]= { path_myddir => "$opt_vardir/slave1-data", path_myerr => "$opt_vardir/log/slave1.err", path_mylog => "$opt_vardir/log/slave1.log", path_mypid => "$opt_vardir/run/slave1.pid", path_mysock => "$opt_tmpdir/slave1.sock", path_myport => $opt_slave_myport + 1, start_timeout => 300, }; $slave->[2]= { path_myddir => "$opt_vardir/slave2-data", path_myerr => "$opt_vardir/log/slave2.err", path_mylog => "$opt_vardir/log/slave2.log", path_mypid => "$opt_vardir/run/slave2.pid", path_mysock => "$opt_tmpdir/slave2.sock", path_myport => $opt_slave_myport + 2, start_timeout => 300, }; if ( $opt_extern ) { $glob_use_running_server= 1; $opt_skip_rpl= 1; # We don't run rpl test cases $master->[0]->{'path_mysock'}= $opt_socket; } $path_timefile= "$opt_vardir/log/mysqltest-time"; $path_mysqltest_log= "$opt_vardir/log/mysqltest.log"; } ############################################################################## # # Set paths to various executable programs # ############################################################################## sub executable_setup () { if ( $opt_source_dist ) { if ( $glob_win32 ) { $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", "$glob_basedir/bin"); $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-nt", "$path_client_bindir/mysqld", "$path_client_bindir/mysqld-debug", "$path_client_bindir/mysqld-max"); $path_language= mtr_path_exists("$glob_basedir/share/english/"); $path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets"); $exe_my_print_defaults= mtr_exe_exists("$path_client_bindir/my_print_defaults"); } else { $path_client_bindir= mtr_path_exists("$glob_basedir/client"); $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld"); $path_language= mtr_path_exists("$glob_basedir/sql/share/english/"); $path_charsetsdir= mtr_path_exists("$glob_basedir/sql/share/charsets"); $exe_my_print_defaults= mtr_exe_exists("$glob_basedir/extra/my_print_defaults"); } if ( $glob_use_embedded_server ) { my $path_examples= "$glob_basedir/libmysqld/examples"; $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest_embedded"); $exe_mysql_client_test= mtr_exe_exists("$path_examples/mysql_client_test_embedded", "/usr/bin/false"); } else { if ( $opt_valgrind_mysqltest ) { # client/mysqltest might be a libtool .sh script, so look for real exe # to avoid valgrinding bash ;) $exe_mysqltest= mtr_exe_exists("$path_client_bindir/.libs/lt-mysqltest", "$path_client_bindir/.libs/mysqltest", "$path_client_bindir/mysqltest"); } else { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); } $exe_mysql_client_test= mtr_exe_exists("$glob_basedir/tests/mysql_client_test", "/usr/bin/false"); } $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"); $exe_mysql_fix_system_tables= mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables"); $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools"); $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; } else { $path_client_bindir= mtr_path_exists("$glob_basedir/bin"); $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"); $exe_mysql_fix_system_tables= mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", "$glob_basedir/scripts/mysql_fix_privilege_tables"); $exe_my_print_defaults= mtr_exe_exists("$path_client_bindir/my_print_defaults"); $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", "$glob_basedir/share/english/"); $path_charsetsdir= mtr_path_exists("$glob_basedir/share/mysql/charsets", "$glob_basedir/share/charsets"); if ( $glob_win32 ) { $exe_mysqld= mtr_exe_exists ("$glob_basedir/bin/mysqld-nt", "$glob_basedir/bin/mysqld", "$glob_basedir/bin/mysqld-debug",); } else { $exe_mysqld= mtr_exe_exists ("$glob_basedir/libexec/mysqld", "$glob_basedir/bin/mysqld"); } if ( $glob_use_embedded_server ) { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest_embedded"); $exe_mysql_client_test= mtr_exe_exists("$glob_basedir/tests/mysql_client_test_embedded", "$path_client_bindir/mysql_client_test_embedded", "/usr/bin/false"); } else { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); $exe_mysql_client_test= mtr_exe_exists("$path_client_bindir/mysql_client_test", "/usr/bin/false"); # FIXME temporary } $path_ndb_tools_dir= "$glob_basedir/bin"; $exe_ndb_mgm= "$glob_basedir/bin/ndb_mgm"; } $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; $path_ndb_backup_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; $file_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; } ############################################################################## # # Set environment to be used by childs of this process # ############################################################################## # Note that some env is setup in spawn/run, in "mtr_process.pl" sub environment_setup () { # -------------------------------------------------------------------------- # We might not use a standard installation directory, like /usr/lib. # Set LD_LIBRARY_PATH to make sure we find our installed libraries. # -------------------------------------------------------------------------- unless ( $opt_source_dist ) { $ENV{'LD_LIBRARY_PATH'}= "$glob_basedir/lib" . ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); $ENV{'DYLD_LIBRARY_PATH'}= "$glob_basedir/lib" . ($ENV{'DYLD_LIBRARY_PATH'} ? ":$ENV{'DYLD_LIBRARY_PATH'}" : ""); } # -------------------------------------------------------------------------- # Also command lines in .opt files may contain env vars # -------------------------------------------------------------------------- $ENV{'UMASK'}= "0660"; # The octal *string* $ENV{'UMASK_DIR'}= "0770"; # The octal *string* $ENV{'LC_COLLATE'}= "C"; $ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server; $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; $ENV{'MYSQL_TEST_WINDIR'}= $glob_mysql_test_dir; $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; $ENV{'MASTER_WINMYSOCK'}= $master->[0]->{'path_mysock'}; $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'}; $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'}; $ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'}; $ENV{'MASTER_MYPORT1'}= $master->[1]->{'path_myport'}; $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'path_myport'}; $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'path_myport'}; $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'path_myport'}; # $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME $ENV{'MYSQL_TCP_PORT'}= 3306; $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; if ( $glob_cygwin_perl ) { foreach my $key ('MYSQL_TEST_WINDIR','MASTER_MYSOCK') { $ENV{$key}= `cygpath -w $ENV{$key}`; $ENV{$key} =~ s,\\,\\\\,g; chomp($ENV{$key}); } } $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set # We are nice and report a bit about our settings 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"; print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; } ############################################################################## # # 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_masters_slaves(); mtr_error("We die from ^C signal from user"); } ############################################################################## # # Handle left overs from previous runs # ############################################################################## sub kill_running_server () { if ( $opt_fast or $glob_use_embedded_server ) { # FIXME is embedded server really using PID files?! unlink($master->[0]->{'path_mypid'}); unlink($master->[1]->{'path_mypid'}); unlink($slave->[0]->{'path_mypid'}); unlink($slave->[1]->{'path_mypid'}); unlink($slave->[2]->{'path_mypid'}); } else { # Ensure that no old mysqld test servers are running # This is different from terminating processes we have # started from ths run of the script, this is terminating # leftovers from previous runs. mtr_report("Killing Possible Leftover Processes"); mkpath("$opt_vardir/log"); # Needed for mysqladmin log mtr_kill_leftovers(); ndbcluster_stop(); $master->[0]->{'ndbcluster'}= 1; } } sub kill_and_cleanup () { kill_running_server (); mtr_report("Removing Stale Files"); if ( $opt_vardir eq "$glob_mysql_test_dir/var" ) { # # Running with "var" in mysql-test dir # if ( -l "$glob_mysql_test_dir/var" ) { # Some users creates a soft link in mysql-test/var to another area # - allow it mtr_report("WARNING: Using the 'mysql-test/var' symlink"); rmtree("$opt_vardir/log"); rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port"); rmtree("$opt_vardir/run"); rmtree("$opt_vardir/tmp"); } else { # Remove the entire "var" dir rmtree("$opt_vardir/"); } } 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 rmtree("$glob_mysql_test_dir/var"); # Remove the "var" dir rmtree("$opt_vardir/"); } mkpath("$opt_vardir/log"); mkpath("$opt_vardir/run"); mkpath("$opt_vardir/tmp"); mkpath($opt_tmpdir) if $opt_tmpdir ne "$opt_vardir/tmp"; # FIXME do we really need to create these all, or are they # created for us when tables are created? my @data_dir_lst = ( $master->[0]->{'path_myddir'}, $master->[1]->{'path_myddir'}, $slave->[0]->{'path_myddir'}, $slave->[1]->{'path_myddir'}, $slave->[2]->{'path_myddir'}); foreach my $data_dir (@data_dir_lst) { rmtree("$data_dir"); 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"); opendir(DIR, "$glob_mysql_test_dir/std_data") or mtr_error("Can't find the std_data directory: $!"); for my $elem ( readdir(DIR) ) { next if -d "$glob_mysql_test_dir/std_data/$elem"; copy("$glob_mysql_test_dir/std_data/$elem", "$opt_vardir/std_data_ln/$elem"); } closedir(DIR); } } ############################################################################## # # Start the ndb cluster # ############################################################################## sub ndbcluster_support () { # check ndbcluster support by testing using a switch # that is only available in that case if ( mtr_run($exe_mysqld, ["--no-defaults", "--ndb-use-exact-count", "--help"], "", "/dev/null", "/dev/null", "") != 0 ) { mtr_report("No ndbcluster support"); return 0; } mtr_report("Has ndbcluster support"); return 1; } # FIXME why is there a different start below?! sub ndbcluster_install () { if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) { return 0; } mtr_report("Install ndbcluster"); my $ndbcluster_opts= $opt_bench ? "" : "--small"; my $ndbcluster_port_base= $opt_ndbcluster_port + 2; if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", "--port-base=$ndbcluster_port_base", "--data-dir=$opt_vardir", $ndbcluster_opts, "--initial"], "", "", "", "") ) { mtr_error("Error ndbcluster_install"); return 1; } ndbcluster_stop(); $master->[0]->{'ndbcluster'}= 1; return 0; } sub ndbcluster_start () { if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) { return 0; } # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", "--data-dir=$opt_vardir"], "", "/dev/null", "", "") ) { mtr_error("Error ndbcluster_start"); return 1; } return 0; } sub ndbcluster_stop () { if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) { return; } my $ndbcluster_port_base= $opt_ndbcluster_port + 2; # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", "--data-dir=$opt_vardir", "--stop"], "", "/dev/null", "", ""); return; } ############################################################################## # # Run the benchmark suite # ############################################################################## sub run_benchmarks ($) { my $benchmark= shift; my $args; if ( ! $glob_use_embedded_server and ! $opt_local_master ) { $master->[0]->{'pid'}= 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_mysock'}); mtr_add_arg($args, "--user=%s", $opt_user); if ( $opt_small_bench ) { mtr_add_arg($args, "--small-test"); mtr_add_arg($args, "--small-tables"); } if ( $opt_with_ndbcluster ) { mtr_add_arg($args, "--create-options=TYPE=ndb"); } my $benchdir= "$glob_basedir/sql-bench"; chdir($benchdir); # FIXME check error # FIXME write shorter.... if ( ! $benchmark ) { mtr_add_arg($args, "--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 test suite # ############################################################################## # FIXME how to specify several suites to run? Comma separated list? sub run_tests () { run_suite($opt_suite); } sub run_suite () { my $suite= shift; mtr_print_thick_line(); mtr_report("Finding Tests in the '$suite' suite"); mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout); my $tests= collect_test_cases($suite); mtr_report("Starting Tests in the '$suite' suite"); mtr_print_header(); foreach my $tinfo ( @$tests ) { mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout); run_testcase($tinfo); mtr_timer_stop($glob_timers,"testcase"); } mtr_print_line(); if ( ! $opt_gdb and ! $glob_use_running_server and ! $opt_ddd and ! $glob_use_embedded_server ) { stop_masters_slaves(); } 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 mysql_install_db () { # FIXME not exactly true I think, needs improvements install_db('master', $master->[0]->{'path_myddir'}); install_db('master', $master->[1]->{'path_myddir'}); install_db('slave', $slave->[0]->{'path_myddir'}); install_db('slave', $slave->[1]->{'path_myddir'}); install_db('slave', $slave->[2]->{'path_myddir'}); if ( ndbcluster_install() ) { # failed to install, disable usage but flag that its no ok $opt_with_ndbcluster= 0; $flag_ndb_status_ok= 0; } return 0; } sub install_db ($$) { my $type= shift; my $data_dir= shift; my $init_db_sql= "lib/init_db.sql"; my $init_db_sql_tmp= "/tmp/init_db.sql$$"; my $args; mtr_report("Installing \u$type Databases"); open(IN, $init_db_sql) or mtr_error("Can't open $init_db_sql: $!"); open(OUT, ">", $init_db_sql_tmp) or mtr_error("Can't write to $init_db_sql_tmp: $!"); while () { chomp; s/\@HOSTNAME\@/$glob_hostname/; if ( /^\s*$/ ) { print OUT "\n"; } elsif (/;$/) { print OUT "$_\n"; } else { print OUT "$_ "; } } close OUT; close IN; mtr_init_args(\$args); mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--bootstrap"); mtr_add_arg($args, "--console"); mtr_add_arg($args, "--skip-grant-tables"); mtr_add_arg($args, "--basedir=%s", $path_my_basedir); mtr_add_arg($args, "--datadir=%s", $data_dir); mtr_add_arg($args, "--skip-innodb"); mtr_add_arg($args, "--skip-ndbcluster"); mtr_add_arg($args, "--skip-bdb"); if ( ! $opt_netware ) { mtr_add_arg($args, "--language=%s", $path_language); mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); } if ( mtr_run($exe_mysqld, $args, $init_db_sql_tmp, $path_manager_log, $path_manager_log, "") != 0 ) { unlink($init_db_sql_tmp); mtr_error("Error executing mysqld --bootstrap\n" . "Could not install $type test DBs"); } unlink($init_db_sql_tmp); } ############################################################################## # # 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; my $tname= $tinfo->{'name'}; mtr_tonewfile($opt_current_test,"$tname\n"); # Always tell where we are # output current test to ndbcluster log file to enable diagnostics mtr_tofile($file_ndb_testrun_log,"CURRENT TEST $tname\n"); # ---------------------------------------------------------------------- # 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; } # ---------------------------------------------------------------------- # 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. # ---------------------------------------------------------------------- if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) { # We try to find out if we are to restart the server my $do_restart= 0; # Assumes we don't have to if ( $tinfo->{'master_sh'} ) { $do_restart= 1; # Always restart if script to run } elsif ( $master->[0]->{'running_master_is_special'} and $master->[0]->{'running_master_is_special'}->{'timezone'} eq $tinfo->{'timezone'} and mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, $tinfo->{'master_opt'}) ) { # If running master was started with special settings, but # the current test requuires the same ones, we *don't* restart. $do_restart= 0; } elsif ( $tinfo->{'master_restart'} or $master->[0]->{'running_master_is_special'} ) { $do_restart= 1; } if ( $do_restart ) { stop_masters(); delete $master->[0]->{'running_master_is_special'}; # Forget history } # ---------------------------------------------------------------------- # Always terminate all slaves, if any. Else we may have useless # reconnection attempts and error messages in case the slave and # master servers restart. # ---------------------------------------------------------------------- stop_slaves(); } # ---------------------------------------------------------------------- # Prepare to start masters. Even if we use embedded, we want to run # the preparation. # ---------------------------------------------------------------------- $ENV{'TZ'}= $tinfo->{'timezone'}; mtr_report_test_name($tinfo); mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); # FIXME test cases that depend on each other, prevent this from # being at this location. # do_before_start_master($tname,$tinfo->{'master_sh'}); # ---------------------------------------------------------------------- # If any mysqld servers running died, we have to know # ---------------------------------------------------------------------- mtr_record_dead_children(); # ---------------------------------------------------------------------- # Start masters # ---------------------------------------------------------------------- if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) { # FIXME give the args to the embedded server?! # FIXME what does $opt_local_master mean?! # FIXME split up start and check that started so that can do # starts in parallel, masters and slaves at the same time. if ( ! $opt_local_master ) { if ( $master->[0]->{'ndbcluster'} ) { $master->[0]->{'ndbcluster'}= ndbcluster_start(); if ( $master->[0]->{'ndbcluster'} ) { report_failure_and_restart($tinfo); return; } } if ( ! $master->[0]->{'pid'} ) { # FIXME not correct location for do_before_start_master() do_before_start_master($tname,$tinfo->{'master_sh'}); $master->[0]->{'pid'}= mysqld_start('master',0,$tinfo->{'master_opt'},[]); if ( ! $master->[0]->{'pid'} ) { report_failure_and_restart($tinfo); return; } } if ( $opt_with_ndbcluster and ! $master->[1]->{'pid'} ) { # Test needs cluster, start an extra mysqld connected to cluster $master->[1]->{'pid'}= mysqld_start('master',1,$tinfo->{'master_opt'},[]); if ( ! $master->[1]->{'pid'} ) { report_failure_and_restart($tinfo); return; } } if ( $tinfo->{'master_restart'} ) { # Save this test case information, so next can examine it $master->[0]->{'running_master_is_special'}= $tinfo; } } # ---------------------------------------------------------------------- # Start slaves - if needed # ---------------------------------------------------------------------- if ( $tinfo->{'slave_num'} ) { mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); do_before_start_slave($tname,$tinfo->{'slave_sh'}); for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) { if ( ! $slave->[$idx]->{'pid'} ) { $slave->[$idx]->{'pid'}= mysqld_start('slave',$idx, $tinfo->{'slave_opt'}, $tinfo->{'slave_mi'}); if ( ! $slave->[$idx]->{'pid'} ) { report_failure_and_restart($tinfo); return; } } } } } # ---------------------------------------------------------------------- # If --start-and-exit given, stop here to let user manually run tests # ---------------------------------------------------------------------- if ( $opt_start_and_exit ) { mtr_report("\nServers started, exiting"); exit(0); } # ---------------------------------------------------------------------- # Run the test case # ---------------------------------------------------------------------- { # remove the old reject file if ( $opt_suite eq "main" ) { unlink("r/$tname.reject"); } else { unlink("suite/$opt_suite/r/$tname.reject"); } unlink($path_timefile); my $res= run_mysqltest($tinfo); if ( $res == 0 ) { mtr_report_test_passed($tinfo); } elsif ( $res == 62 ) { # Testcase itself tell us to skip this one mtr_report_test_skipped($tinfo); } elsif ( $res == 63 ) { $tinfo->{'timeout'}= 1; # Mark as timeout report_failure_and_restart($tinfo); } else { # Test case failed, if in control mysqltest returns 1 if ( $res != 1 ) { mtr_tofile($path_timefile, "mysqltest returned unexpected code $res, " . "it has probably crashed"); } report_failure_and_restart($tinfo); } } } sub report_failure_and_restart ($) { my $tinfo= shift; mtr_report_test_failed($tinfo); mtr_show_failed_diff($tinfo->{'name'}); print "\n"; if ( ! $opt_force ) { my $test_mode= join(" ", @::glob_test_mode) || "default"; print "Aborting: $tinfo->{'name'} failed in $test_mode mode. "; print "To continue, re-run with '--force'.\n"; if ( ! $opt_gdb and ! $glob_use_running_server and ! $opt_ddd and ! $glob_use_embedded_server ) { stop_masters_slaves(); } mtr_exit(1); } # FIXME always terminate on failure?! if ( ! $opt_gdb and ! $glob_use_running_server and ! $opt_ddd and ! $glob_use_embedded_server ) { stop_masters_slaves(); } print "Resuming Tests\n\n"; } ############################################################################## # # Start and stop servers # ############################################################################## # The embedded server needs the cleanup so we do some of the start work # but stop before actually running mysqld or anything. sub do_before_start_master ($$) { my $tname= shift; my $init_script= shift; # FIXME what about second master..... # Remove stale binary logs except for 2 tests which need them FIXME here???? if ( $tname ne "rpl_crash_binlog_ib_1b" and $tname ne "rpl_crash_binlog_ib_2b" and $tname ne "rpl_crash_binlog_ib_3b") { # FIXME we really want separate dir for binlogs 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 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"); } } # for gcov FIXME needed? If so we need more absolute paths # chdir($glob_basedir); } sub do_before_start_slave ($$) { my $tname= shift; my $init_script= shift; # Remove stale binary logs and old master.info files # except for too tests which need them if ( $tname ne "rpl_crash_binlog_ib_1b" and $tname ne "rpl_crash_binlog_ib_2b" and $tname ne "rpl_crash_binlog_ib_3b" ) { # FIXME we really want separate dir for binlogs foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) { unlink($bin); } # FIXME really master?! 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 $type= shift; # master/slave/bootstrap my $idx= shift; my $extra_opt= shift; my $slave_master_info= shift; my $sidx= ""; # Index as string, 0 is empty string if ( $idx > 0 ) { $sidx= sprintf("%d", $idx); # sprintf not needed in Perl for this } my $prefix= ""; # If mysqltest server arg if ( $glob_use_embedded_server ) { $prefix= "--server-arg="; } else { # We can't pass embedded server --no-defaults mtr_add_arg($args, "%s--no-defaults", $prefix); } mtr_add_arg($args, "%s--console", $prefix); mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); mtr_add_arg($args, "%s--core", $prefix); mtr_add_arg($args, "%s--default-character-set=latin1", $prefix); mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); if ( defined $opt_valgrind_mysqld ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); mtr_add_arg($args, "%s--skip-bdb", $prefix); } my $pidfile; if ( $type eq 'master' ) { my $id= $idx > 0 ? $idx + 101 : 1; mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, $opt_vardir, $sidx); mtr_add_arg($args, "%s--pid-file=%s", $prefix, $master->[$idx]->{'path_mypid'}); mtr_add_arg($args, "%s--port=%d", $prefix, $master->[$idx]->{'path_myport'}); mtr_add_arg($args, "%s--server-id=%d", $prefix, $id); mtr_add_arg($args, "%s--socket=%s", $prefix, $master->[$idx]->{'path_mysock'}); mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:50M", $prefix); mtr_add_arg($args, "%s--local-infile", $prefix); mtr_add_arg($args, "%s--datadir=%s", $prefix, $master->[$idx]->{'path_myddir'}); if ( $idx > 0 ) { mtr_add_arg($args, "%s--skip-innodb", $prefix); } if ( $opt_skip_ndbcluster ) { mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); } } if ( $type eq 'slave' ) { my $slave_server_id= 2 + $idx; my $slave_rpl_rank= $slave_server_id; mtr_add_arg($args, "%s--datadir=%s", $prefix, $slave->[$idx]->{'path_myddir'}); # FIXME slave get this option twice?! mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix); 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); # FIXME option duplicated for slave mtr_add_arg($args, "%s--log=%s", $prefix, $slave->[$idx]->{'path_mylog'}); mtr_add_arg($args, "%s--master-retry-count=10", $prefix); mtr_add_arg($args, "%s--pid-file=%s", $prefix, $slave->[$idx]->{'path_mypid'}); mtr_add_arg($args, "%s--port=%d", $prefix, $slave->[$idx]->{'path_myport'}); 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, $slave->[$idx]->{'path_myport'}); mtr_add_arg($args, "%s--report-user=root", $prefix); mtr_add_arg($args, "%s--skip-innodb", $prefix); mtr_add_arg($args, "%s--skip-ndbcluster", $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. mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, $path_slave_load_tmpdir); mtr_add_arg($args, "%s--socket=%s", $prefix, $slave->[$idx]->{'path_mysock'}); mtr_add_arg($args, "%s--set-variable=slave_net_timeout=10", $prefix); if ( @$slave_master_info ) { foreach my $arg ( @$slave_master_info ) { mtr_add_arg($args, "%s%s", $prefix, $arg); } } else { 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]->{'path_myport'}); # First master 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 ( $opt_debug ) { if ( $type eq 'master' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/master%s.trace", $prefix, $opt_vardir, $sidx); } if ( $type eq 'slave' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/slave%s.trace", $prefix, $opt_vardir, $sidx); } } if ( $opt_with_ndbcluster ) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $opt_ndbconnectstring); } # FIXME always set nowdays??? SMALL_SERVER mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix); mtr_add_arg($args, "%s--sort_buffer=256K", $prefix); mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix); if ( $opt_with_openssl ) { 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); } if ( $opt_gdb or $opt_client_gdb or $opt_manual_gdb or $opt_ddd) { mtr_add_arg($args, "%s--gdb", $prefix); } # If we should run all tests cases, we will use a local server for that if ( -w "/" ) { # We are running as root; We need to add the --root argument mtr_add_arg($args, "%s--user=root", $prefix); } if ( $type eq 'master' ) { if ( ! $opt_old_master ) { mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix); mtr_add_arg($args, "%s--init-rpl-role=master", $prefix); } # FIXME strange,..... # FIXME MYSQL_MYPORT is not set anythere?! if ( $opt_local_master ) { mtr_add_arg($args, "%s--host=127.0.0.1", $prefix); mtr_add_arg($args, "%s--port=%s", $prefix, $ENV{'MYSQL_MYPORT'}); } } foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt ) { mtr_add_arg($args, "%s%s", $prefix, $arg); } if ( $opt_bench ) { mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix); mtr_add_arg($args, "%s--init-rpl-role=master", $prefix); } elsif ( $type eq 'master' ) { mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--open-files-limit=1024", $prefix); mtr_add_arg($args, "%s--log=%s", $prefix, $master->[0]->{'path_mylog'}); } return $args; } # FIXME # if ( $type eq 'master' and $glob_use_embedded_server ) # { # # Add a -A to each argument to pass it to embedded server # my @mysqltest_opt= map {("-A",$_)} @args; # $opt_extra_mysqltest_opt= \@mysqltest_opt; # return; # } ############################################################################## # # Start mysqld and return the PID # ############################################################################## sub mysqld_start ($$$$) { my $type= shift; # master/slave/bootstrap my $idx= shift; my $extra_opt= shift; my $slave_master_info= shift; my $args; # Arg vector my $exe; my $pid; if ( $type eq 'master' ) { $exe= $exe_master_mysqld; } elsif ( $type eq 'slave' ) { $exe= $exe_slave_mysqld; } else { $exe= $exe_mysqld; } mtr_init_args(\$args); if ( defined $opt_valgrind_mysqld ) { valgrind_arguments($args, \$exe); } mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info); if ( $type eq 'master' ) { if ( $pid= mtr_spawn($exe, $args, "", $master->[$idx]->{'path_myerr'}, $master->[$idx]->{'path_myerr'}, "", { append_log_file => 1 }) ) { return sleep_until_file_created($master->[$idx]->{'path_mypid'}, $master->[$idx]->{'start_timeout'}, $pid); } } if ( $type eq 'slave' ) { if ( $pid= mtr_spawn($exe, $args, "", $slave->[$idx]->{'path_myerr'}, $slave->[$idx]->{'path_myerr'}, "", { append_log_file => 1 }) ) { return sleep_until_file_created($slave->[$idx]->{'path_mypid'}, $master->[$idx]->{'start_timeout'}, $pid); } } return 0; } sub stop_masters_slaves () { print "Ending Tests\n"; print "Shutting-down MySQL daemon\n\n"; stop_masters(); print "Master(s) shutdown finished\n"; stop_slaves(); print "Slave(s) shutdown finished\n"; } sub stop_masters () { my @args; for ( my $idx; $idx < 2; $idx++ ) { # FIXME if we hit ^C before fully started, this test will prevent # the mysqld process from being killed if ( $master->[$idx]->{'pid'} ) { push(@args,{ pid => $master->[$idx]->{'pid'}, pidfile => $master->[$idx]->{'path_mypid'}, sockfile => $master->[$idx]->{'path_mysock'}, port => $master->[$idx]->{'path_myport'}, }); $master->[$idx]->{'pid'}= 0; # Assume we are done with it } } if ( ! $master->[0]->{'ndbcluster'} ) { ndbcluster_stop(); $master->[0]->{'ndbcluster'}= 1; } mtr_stop_mysqld_servers(\@args); } sub stop_slaves () { my $force= shift; my @args; for ( my $idx; $idx < 3; $idx++ ) { if ( $slave->[$idx]->{'pid'} ) { push(@args,{ pid => $slave->[$idx]->{'pid'}, pidfile => $slave->[$idx]->{'path_mypid'}, sockfile => $slave->[$idx]->{'path_mysock'}, port => $slave->[$idx]->{'path_myport'}, }); $slave->[$idx]->{'pid'}= 0; # Assume we are done with it } } mtr_stop_mysqld_servers(\@args); } sub run_mysqltest ($) { my $tinfo= shift; my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'} --password="; if ( $opt_debug ) { $cmdline_mysqldump .= " --debug=d:t:A,$opt_vardir/log/mysqldump.trace"; } my $cmdline_mysqlimport= "$exe_mysqlimport -uroot " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'} --password="; if ( $opt_debug ) { $cmdline_mysqlimport .= " --debug=d:t:A,$opt_vardir/log/mysqlimport.trace"; } my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'} --password="; if ( $opt_debug ) { $cmdline_mysqlshow .= " --debug=d:t:A,$opt_vardir/log/mysqlshow.trace"; } my $cmdline_mysqlbinlog= "$exe_mysqlbinlog --no-defaults --local-load=$opt_tmpdir"; if ( $opt_debug ) { $cmdline_mysqlbinlog .= " --debug=d:t:A,$opt_vardir/log/mysqlbinlog.trace"; } my $cmdline_mysql= "$exe_mysql --host=localhost --user=root --password= " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'}"; my $cmdline_mysql_client_test= "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'}"; if ( $glob_use_embedded_server ) { $cmdline_mysql_client_test.= " -A --language=$path_language" . " -A --datadir=$slave->[0]->{'path_myddir'}" . " -A --character-sets-dir=$path_charsetsdir"; } my $cmdline_mysql_fix_system_tables= "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . "--port=$master->[0]->{'path_myport'} " . "--socket=$master->[0]->{'path_mysock'}"; # FIXME really needing a PATH??? # $ENV{'PATH'}= "/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$ENV{'PATH'}"; $ENV{'MYSQL'}= $cmdline_mysql; $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; $ENV{'CHARSETSDIR'}= $path_charsetsdir; $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults; $ENV{'NDB_STATUS_OK'}= $flag_ndb_status_ok; $ENV{'NDB_MGM'}= $exe_ndb_mgm; $ENV{'NDB_BACKUP_DIR'}= $path_ndb_backup_dir; $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; $ENV{'NDB_TOOLS_OUTPUT'}= $file_ndb_testrun_log; $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; my $exe= $exe_mysqltest; my $args; mtr_init_args(\$args); mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); mtr_add_arg($args, "--database=test"); mtr_add_arg($args, "--user=%s", $opt_user); mtr_add_arg($args, "--password="); mtr_add_arg($args, "--silent"); mtr_add_arg($args, "-v"); mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); mtr_add_arg($args, "--port=%d", $master->[0]->{'path_myport'}); if ( $opt_ps_protocol ) { mtr_add_arg($args, "--ps-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_big_test ) { mtr_add_arg($args, "--big-test"); } 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", $opt_vardir); } if ( $opt_with_openssl ) { 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 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 /mysqltest # ---------------------------------------------------------------------- $ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args); # ---------------------------------------------------------------------- # Add arguments that should not go into the MYSQL_TEST env var # ---------------------------------------------------------------------- if ( defined $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, "-R"); mtr_add_arg($args, $tinfo->{'result_file'}); if ( $opt_record ) { mtr_add_arg($args, "--record"); } return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); } sub valgrind_arguments { my $args= shift; my $exe= shift; mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option mtr_add_arg($args, "--alignment=8"); mtr_add_arg($args, "--leak-check=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"; if ( defined $opt_valgrind_all ) { mtr_add_arg($args, "-v"); mtr_add_arg($args, "--show-reachable=yes"); } if ( $opt_valgrind_options ) { # FIXME split earlier and put into @glob_valgrind_* mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options)); } mtr_add_arg($args, $$exe); $$exe= $opt_valgrind || "valgrind"; } ############################################################################## # # Usage # ############################################################################## sub usage ($) { my $message= shift; if ( $message ) { print STDERR "$message \n"; } print STDERR <