diff options
Diffstat (limited to 'mysql-test/mysql-test-run.pl')
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 6173 |
1 files changed, 2915 insertions, 3258 deletions
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index b342421ca2e..ba426446075 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -6,124 +6,108 @@ # # mysql-test-run.pl # -# Tool used for executing a suite of .test file +# Tool used for executing a suite of .test files # # See the "MySQL Test framework manual" for more information # http://dev.mysql.com/doc/mysqltest/en/index.html # -# 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 strict; +use warnings; -use lib "lib/"; +BEGIN { + # Check that mysql-test-run.pl is started from mysql-test/ + unless ( -f "mysql-test-run.pl" ) + { + print "**** ERROR **** ", + "You must start mysql-test-run from the mysql-test/ directory\n"; + exit(1); + } + # Check that lib exist + unless ( -d "lib/" ) + { + print "**** ERROR **** ", + "Could not find the lib/ directory \n"; + exit(1); + } +} -$Devel::Trace::TRACE= 0; # Don't trace boring init stuff +BEGIN { + # Check backward compatibility support + # By setting the environment variable MTR_VERSION + # it's possible to use a previous version of + # mysql-test-run.pl + my $version= $ENV{MTR_VERSION} || 2; + if ( $version == 1 ) + { + print "=======================================================\n"; + print " WARNING: Using mysql-test-run.pl version 1! \n"; + print "=======================================================\n"; + # Should use exec() here on *nix but this appears not to work on Windows + exit(system($^X, "lib/v1/mysql-test-run.pl", @ARGV) >> 8); + } + elsif ( $version == 2 ) + { + # This is the current version, just continue + ; + } + else + { + print "ERROR: Version $version of mysql-test-run does not exist!\n"; + exit(1); + } +} + +use lib "lib"; -#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 My::File::Path; # Patched version of File::Path +use File::Basename; +use File::Copy; +use File::Find; +use File::Temp qw / tempdir /; +use File::Spec::Functions qw / splitdir /; +use My::Platform; +use My::SafeProcess; +use My::ConfigFactory; +use My::Options; +use My::Find; +use My::SysInfo; +use My::CoreDump; +use mtr_cases; +use mtr_report; +use mtr_match; +use mtr_unique; use IO::Socket::INET; -use strict; -use warnings; - -select(STDOUT); -$| = 1; # Automatically flush STDOUT +use IO::Select; -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); -our $glob_netware= ($^O eq "NetWare"); # NetWare - -require "lib/mtr_cases.pl"; -require "lib/mtr_im.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_match.pl"; require "lib/mtr_misc.pl"; -require "lib/mtr_stress.pl"; -require "lib/mtr_unique.pl"; - -$Devel::Trace::TRACE= 1; -############################################################################## -# -# Default settings -# -############################################################################## +$SIG{INT}= sub { mtr_error("Got ^C signal"); }; -# 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_mysql_test_dir; +our $basedir; 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 $path_my_basedir; -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 +our $path_current_testlog; +our $path_testlog; + +our $default_vardir; +our $opt_vardir; # Path to use for var/ dir +my $path_vardir_trace; # unix formatted opt_vardir for trace files +my $opt_tmpdir; # Path to use for tmp/ dir +my $path_config_file; # The generated config file, var/my.cnf # Visual Studio produces executables in different sub-directories based on the # configuration used to build them. To make life easier, an environment @@ -131,70 +115,40 @@ our $opt_tmpdir; # A path but set directly on cmd line # executables will be used by the test suite. our $opt_vs_config = $ENV{'MTR_VS_CONFIG'}; -our $default_vardir; +my $DEFAULT_SUITES= "main,binlog,federated,rpl,rpl_ndb,ndb"; +my $opt_suites; -our $opt_usage; -our $opt_suites; -our $opt_suites_default= "main,binlog,rpl,rpl_ndb,ndb"; # 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 $exe_mysql_fix_system_tables; -our $file_mysql_fix_privilege_tables; our $exe_mysqltest; -our $exe_ndbd; -our $exe_ndb_mgmd; -our $exe_slave_mysqld; -our $exe_im; -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_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; +my $opt_compress; +my $opt_ssl; +my $opt_skip_ssl; +my $opt_ssl_supported; +my $opt_ps_protocol; +my $opt_sp_protocol; +my $opt_cursor_protocol; +my $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; +# Options used when connecting to an already running server +my %opts_extern; +sub using_extern { return (keys %opts_extern > 0);}; -our $opt_fast; +our $opt_fast= 0; our $opt_force; -our $opt_reorder= 0; -our $opt_enable_disabled; our $opt_mem= $ENV{'MTR_MEM'}; our $opt_gcov; @@ -209,59 +163,41 @@ 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 $clusters; - -our $instance_manager; +my $config; # The currently running config +my $current_config_name; # The currently running config file template -our $opt_master_myport; -our $opt_slave_myport; -our $im_port; -our $im_mysqld1_port; -our $im_mysqld2_port; -our $opt_ndbcluster_port; -our $opt_ndbconnectstring; -our $opt_ndbcluster_port_slave; -our $opt_ndbconnectstring_slave; +my $baseport; +my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto"; -our $opt_record; +my $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_skip_im; +our $opt_check_testcases= 1; +my $opt_mark_progress; -our $opt_sleep; +my $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 +my $opt_testcase_timeout= 15; # minutes +my $opt_suite_timeout = 300; # minutes +my $opt_shutdown_timeout= 10; # seconds +my $opt_start_timeout = 180; # seconds -our $opt_start_and_exit; -our $opt_start_dirty; -our $opt_start_from; +sub testcase_timeout { return $opt_testcase_timeout * 60; }; +sub suite_timeout { return $opt_suite_timeout * 60; }; +sub check_timeout { return $opt_testcase_timeout * 6; }; -our $opt_strace_client; +my $opt_start; +my $opt_start_dirty; +my $opt_repeat= 1; +my $opt_retry= 3; +my $opt_retry_failure= 2; -our $opt_timer= 1; +my $opt_strace_client; -our $opt_user; +our $opt_user = "root"; my $opt_valgrind= 0; my $opt_valgrind_mysqld= 0; @@ -271,283 +207,558 @@ 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_warnings= 1; our $opt_skip_ndbcluster= 0; -our $opt_skip_ndbcluster_slave= 0; -our $opt_with_ndbcluster= 0; -our $opt_with_ndbcluster_only= 0; -our $glob_ndbcluster_supported= 0; -our $opt_ndb_extra_test= 0; -our $opt_skip_master_binlog= 0; -our $opt_skip_slave_binlog= 0; - -our $exe_ndb_mgm; -our $exe_ndb_waiter; -our $path_ndb_tools_dir; -our $path_ndb_examples_dir; -our $exe_ndb_example; -our $path_ndb_testrun_log; - -our $path_sql_dir; - -our @data_dir_lst; - -our $used_binlog_format; -our $used_default_engine; + +my $exe_ndbd; +my $exe_ndb_mgmd; +my $exe_ndb_waiter; + 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. +my $opt_max_save_core= $ENV{MTR_MAX_SAVE_CORE} || 5; +my $opt_max_save_datadir= $ENV{MTR_MAX_SAVE_DATADIR} || 20; +my $opt_max_test_fail= $ENV{MTR_MAX_TEST_FAIL} || 10; -###################################################################### -# -# 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 check_ndbcluster_support ($); -sub rm_ndbcluster_tables ($); -sub ndbcluster_start_install ($); -sub ndbcluster_start ($$); -sub ndbcluster_wait_started ($$); -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 ndbd_start ($$$); -sub ndb_mgmd_start ($); -sub mysqld_start ($$$); -sub mysqld_arguments ($$$$); -sub stop_all_servers (); -sub run_mysqltest ($); -sub usage ($); - - -###################################################################### -# -# Main program -# -###################################################################### +my $opt_parallel= $ENV{MTR_PARALLEL} || 1; + +select(STDOUT); +$| = 1; # Automatically flush STDOUT main(); -sub main () { + +sub main { + # Default, verbosity on + report_option('verbose', 0); + + # 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. + mtr_report("Logging: $0 ", join(" ", @ARGV)); command_line_setup(); - check_ndbcluster_support(\%mysqld_variables); - check_ssl_support(\%mysqld_variables); - check_debug_support(\%mysqld_variables); + if ( $opt_gcov ) { + gcov_prepare($basedir); + } + + if (!$opt_suites) { + $opt_suites= $DEFAULT_SUITES; + + # Check for any extra suites to enable based on the path name + my %extra_suites= + ( + "mysql-5.1-new-ndb" => "ndb_team", + "mysql-5.1-new-ndb-merge" => "ndb_team", + "mysql-5.1-telco-6.2" => "ndb_team", + "mysql-5.1-telco-6.2-merge" => "ndb_team", + "mysql-5.1-telco-6.3" => "ndb_team", + "mysql-6.0-ndb" => "ndb_team", + ); + + foreach my $dir ( reverse splitdir($basedir) ) { + my $extra_suite= $extra_suites{$dir}; + if (defined $extra_suite) { + mtr_report("Found extra suite: $extra_suite"); + $opt_suites= "$extra_suite,$opt_suites"; + last; + } + } + } - executable_setup(); + mtr_report("Collecting tests..."); + my $tests= collect_test_cases($opt_suites, \@opt_cases); - environment_setup(); - signal_setup(); + if ( $opt_report_features ) { + # Put "report features" as the first test to run + my $tinfo = My::Test->new + ( + name => 'report_features', + # No result_file => Prints result + path => 'include/report-features.test', + template_path => "include/default_my.cnf", + master_opt => [], + slave_opt => [], + ); + unshift(@$tests, $tinfo); + } - if ( $opt_gcov ) - { - gcov_prepare(); + print "vardir: $opt_vardir\n"; + initialize_servers(); + + ####################################################################### + my $num_tests= @$tests; + if ( not defined $opt_parallel ) { + # Try to find a suitable value for number of workers + my $sys_info= My::SysInfo->new(); + + $opt_parallel= $sys_info->num_cpus(); + for my $limit (2000, 1500, 1000, 500){ + $opt_parallel-- if ($sys_info->min_bogomips() < $limit); + } + $opt_parallel= 8 if ($opt_parallel > 8); + $opt_parallel= $num_tests if ($opt_parallel > $num_tests); + $opt_parallel= 1 if (IS_WINDOWS and $sys_info->isvm()); + $opt_parallel= 1 if ($opt_parallel < 1); + mtr_report("Using parallel: $opt_parallel"); + } + + # Create server socket on any free port + my $server = new IO::Socket::INET + ( + LocalAddr => 'localhost', + Proto => 'tcp', + Listen => $opt_parallel, + ); + mtr_error("Could not create testcase server port: $!") unless $server; + my $server_port = $server->sockport(); + mtr_report("Using server port $server_port"); + + # Create child processes + my %children; + for my $child_num (1..$opt_parallel){ + my $child_pid= My::SafeProcess::Base::_safe_fork(); + if ($child_pid == 0){ + $server= undef; # Close the server port in child + $tests= {}; # Don't need the tests list in child + + # Use subdir of var and tmp unless only one worker + if ($opt_parallel > 1) { + set_vardir("$opt_vardir/$child_num"); + $opt_tmpdir= "$opt_tmpdir/$child_num"; + } + + run_worker($server_port, $child_num); + exit(1); + } + + $children{$child_pid}= 1; } + ####################################################################### + + mtr_report(); + mtr_print_thick_line(); + mtr_print_header(); - if ( $opt_gprof ) + my $completed= run_test_server($server, $tests, $opt_parallel); + + # Send Ctrl-C to any children still running + kill("INT", keys(%children)); + + # Wait for childs to exit + foreach my $pid (keys %children) { - gprof_prepare(); + my $ret_pid= waitpid($pid, 0); + if ($ret_pid != $pid){ + mtr_report("Unknown process $ret_pid exited"); + } + else { + delete $children{$ret_pid}; + } } - if ( $opt_bench ) - { - initialize_servers(); - run_benchmarks(shift); # Shift what? Extra arguments?! + if ( not defined @$completed ) { + mtr_error("Test suite aborted"); } - elsif ( $opt_stress ) - { - initialize_servers(); - run_stress_test() + + if ( @$completed != $num_tests){ + + if ($opt_force){ + # All test should have been run, print any that are still in $tests + #foreach my $test ( @$tests ){ + # $test->print_test(); + #} + } + + # Not all tests completed, failure + mtr_report(); + mtr_report("Only ", int(@$completed), " of $num_tests completed."); + mtr_error("Not all tests completed"); } - else - { - # Figure out which tests we are going to run - if (!$opt_suites) - { - $opt_suites= $opt_suites_default; - - # Check for any extra suites to enable based on the path name - my %extra_suites= - ( - "mysql-5.1-new-ndb" => "ndb_team", - "mysql-5.1-new-ndb-merge" => "ndb_team", - "mysql-5.1-telco-6.2" => "ndb_team", - "mysql-5.1-telco-6.2-merge" => "ndb_team", - "mysql-5.1-telco-6.3" => "ndb_team", - "mysql-6.0-ndb" => "ndb_team", - ); - foreach my $dir ( reverse splitdir($glob_basedir) ) - { - my $extra_suite= $extra_suites{$dir}; - if (defined $extra_suite){ - mtr_report("Found extra suite: $extra_suite"); - $opt_suites= "$extra_suite,$opt_suites"; - last; - } + mtr_print_line(); + + if ( $opt_gcov ) { + gcov_collect($basedir, $opt_gcov, + $opt_gcov_msg, $opt_gcov_err); + } + + mtr_report_stats($completed); + + exit(0); +} + + +sub run_test_server ($$$) { + my ($server, $tests, $childs) = @_; + + my $num_saved_cores= 0; # Number of core files saved in vardir/log/ so far. + my $num_saved_datadir= 0; # Number of datadirs saved in vardir/log/ so far. + my $num_failed_test= 0; # Number of tests failed so far + + # Scheduler variables + my $max_ndb= $childs / 2; + $max_ndb = 4 if $max_ndb > 4; + $max_ndb = 1 if $max_ndb < 1; + my $num_ndb_tests= 0; + + my $completed= []; + my %running; + my $result; + + my $suite_timeout_proc= My::SafeProcess->timer(suite_timeout()); + + my $s= IO::Select->new(); + $s->add($server); + while (1) { + my @ready = $s->can_read(1); # Wake up once every second + foreach my $sock (@ready) { + if ($sock == $server) { + # New client connected + my $child= $sock->accept(); + mtr_verbose("Client connected"); + $s->add($child); + print $child "HELLO\n"; } - } + else { + my $line= <$sock>; + if (!defined $line) { + # Client disconnected + mtr_verbose("Child closed socket"); + $s->remove($sock); + if (--$childs == 0){ + $suite_timeout_proc->kill(); + return $completed; + } + next; + } + chomp($line); + + if ($line eq 'TESTRESULT'){ + $result= My::Test::read_test($sock); + # $result->print_test(); + + # Report test status + mtr_report_test($result); + + if ( $result->is_failed() ) { + + # Save the workers "savedir" in var/log + my $worker_savedir= $result->{savedir}; + my $worker_savename= basename($worker_savedir); + my $savedir= "$opt_vardir/log/$worker_savename"; + + if ($opt_max_save_datadir > 0 && + $num_saved_datadir >= $opt_max_save_datadir) + { + mtr_report(" - skipping '$worker_savedir/'"); + rmtree($worker_savedir); + } + else { + mtr_report(" - saving '$worker_savedir/' to '$savedir/'"); + rename($worker_savedir, $savedir); + # Move any core files from e.g. mysqltest + foreach my $coref (glob("core*"), glob("*.dmp")) + { + mtr_report(" - found '$coref', moving it to '$savedir'"); + move($coref, $savedir); + } + if ($opt_max_save_core > 0) { + # Limit number of core files saved + find({ no_chdir => 1, + wanted => sub { + my $core_file= $File::Find::name; + my $core_name= basename($core_file); + + if ($core_name =~ /^core/ or # Starting with core + (IS_WINDOWS and $core_name =~ /\.dmp$/)){ + # Ending with .dmp + mtr_report(" - found '$core_name'", + "($num_saved_cores/$opt_max_save_core)"); + + My::CoreDump->show($core_file); + + if ($num_saved_cores >= $opt_max_save_core) { + mtr_report(" - deleting it, already saved", + "$opt_max_save_core"); + unlink("$core_file"); + } + ++$num_saved_cores; + } + } + }, + $savedir); + } + } + $num_saved_datadir++; + + if ( !$opt_force ) { + # Test has failed, force is off + $suite_timeout_proc->kill(); + push(@$completed, $result); + return $completed; + } + elsif ($opt_max_test_fail > 0 and + $num_failed_test >= $opt_max_test_fail) { + $suite_timeout_proc->kill(); + mtr_report("Too many tests($num_failed_test) failed!", + "Terminating..."); + return undef; + } + $num_failed_test++; + } + + # Retry test run after test failure + my $retries= $result->{retries} || 2; + my $test_has_failed= $result->{failures} || 0; + if ($test_has_failed and $retries <= $opt_retry){ + # Test should be run one more time unless it has failed + # too many times already + my $failures= $result->{failures}; + if ($opt_retry > 1 and $failures >= $opt_retry_failure){ + mtr_report("\nTest has failed $failures times,", + "no more retries!\n"); + } + else { + mtr_report("\nRetrying test, attempt($retries/$opt_retry)...\n"); + delete($result->{result}); + $result->{retries}= $retries+1; + $result->write_test($sock, 'TESTCASE'); + next; + } + } - my $tests= collect_test_cases($opt_suites); + # Repeat test $opt_repeat number of times + my $repeat= $result->{repeat} || 1; + if ($repeat < $opt_repeat) + { + $result->{retries}= 0; + $result->{failures}= 0; + delete($result->{result}); + $result->{repeat}= $repeat+1; + $result->write_test($sock, 'TESTCASE'); + next; + } - # Turn off NDB and other similar options if no tests use it - my ($need_ndbcluster,$need_im); - foreach my $test (@$tests) - { - next if $test->{skip}; + # Remove from list of running + mtr_error("'", $result->{name},"' is not known to be running") + unless delete $running{$result->key()}; - if (!$opt_extern) - { - $need_ndbcluster||= $test->{ndb_test}; - $need_im||= $test->{component_id} eq 'im'; + # Update scheduler variables + $num_ndb_tests-- if ($result->{ndb_test}); + + # Save result in completed list + push(@$completed, $result); - # 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; } + elsif ($line eq 'START'){ + ; # Send first test + } + else { + mtr_error("Unknown response: '$line' from client"); + } + + # Find next test to schedule + # - Try to use same configuration as worker used last time + # - Limit number of parallel ndb tests + + my $next; + my $second_best; + for(my $i= 0; $i <= @$tests; $i++) + { + my $t= $tests->[$i]; - # 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; + last unless defined $t; + + if (run_testcase_check_skip_test($t)){ + # Move the test to completed list + #mtr_report("skip - Moving test $i to completed"); + push(@$completed, splice(@$tests, $i, 1)); + + # Since the test at pos $i was taken away, next + # test will also be at $i -> redo + redo; + } + + # Limit number of parallell NDB tests + if ($t->{ndb_test} and $num_ndb_tests >= $max_ndb){ + #mtr_report("Skipping, num ndb is already at max, $num_ndb_tests"); + next; + } + + # Prefer same configuration + if (defined $result and + $result->{template_path} eq $t->{template_path}) + { + #mtr_report("Test uses same config => good match"); + # Test uses same config => good match + $next= splice(@$tests, $i, 1); + last; + } + + # Second best choice is the first that does not fulfill + # any of the above conditions + if (!defined $second_best){ + #mtr_report("Setting second_best to $i"); + $second_best= $i; + } + } + + # Use second best choice if no other test has been found + if (!$next and defined $second_best){ + #mtr_report("Take second best choice $second_best"); + mtr_error("Internal error, second best too large($second_best)") + if $second_best > $#$tests; + $next= splice(@$tests, $second_best, 1); + } + + if ($next) { + #$next->print_test(); + $next->write_test($sock, 'TESTCASE'); + $running{$next->key()}= $next; + $num_ndb_tests++ if ($next->{ndb_test}); + } + else { + # No more test, tell child to exit + #mtr_report("Saying BYE to child"); + print $sock "BYE\n"; } } - $use_innodb||= $test->{'innodb_test'}; } - # Check if cluster can be skipped - if ( !$need_ndbcluster ) + # ---------------------------------------------------- + # Check if test suite timer expired + # ---------------------------------------------------- + if ( ! $suite_timeout_proc->wait_one(0) ) { - $opt_skip_ndbcluster= 1; - $opt_skip_ndbcluster_slave= 1; + mtr_report("Test suite timeout! Terminating..."); + return undef; } + } +} - # Check if slave cluster can be skipped - if ($max_slave_num == 0) - { - $opt_skip_ndbcluster_slave= 1; - } - # Check if im can be skipped - if ( ! $need_im ) - { - $opt_skip_im= 1; - } +sub run_worker ($) { + my ($server_port, $thread_num)= @_; - initialize_servers(); + $SIG{INT}= sub { exit(1); }; - if ( $opt_report_features ) { - run_report_features(); - } + # Connect to server + my $server = new IO::Socket::INET + ( + PeerAddr => 'localhost', + PeerPort => $server_port, + Proto => 'tcp' + ); + mtr_error("Could not connect to server at port $server_port: $!") + unless $server; - run_tests($tests); - } + # -------------------------------------------------------------------------- + # Set worker name + # -------------------------------------------------------------------------- + report_option('name',"worker[$thread_num]"); - mtr_exit(0); -} + # -------------------------------------------------------------------------- + # Use auto build thread in all but first worker + # -------------------------------------------------------------------------- + set_build_thread_ports($thread_num > 1 ? 'auto' : $opt_build_thread); -############################################################################## -# -# Default settings -# -############################################################################## + if (check_ports_free()){ + # Some port was not free(which one has already been printed) + mtr_error("Some port(s) was not free") + } -# -# 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. -# + # -------------------------------------------------------------------------- + # Turn off verbosity in workers, unless explicitly specified + # -------------------------------------------------------------------------- + report_option('verbose', undef) if ($opt_verbose == 0); -sub warn_about_removed_option { - my ($option, $value, $hash_value) = @_; + environment_setup(); - warn "WARNING: This option is no longer used, and is ignored: --$option\n"; -} + # Read hello from server which it will send when shared + # resources have been setup + my $hello= <$server>; -sub command_line_setup () { + setup_vardir(); + check_running_as_root(); - # These are defaults for things that are set on the command line + if ( using_extern() ) { + create_config_file_for_extern(%opts_extern); + } - my $opt_comment; + # Ask server for first test + print $server "START\n"; + + while(my $line= <$server>){ + chomp($line); + if ($line eq 'TESTCASE'){ + my $test= My::Test::read_test($server); + #$test->print_test(); - # Magic number -69.4 results in traditional test ports starting from 9306. - set_mtr_build_thread_ports(-69.4); + # Clear comment and logfile, to avoid + # reusing them from previous test + delete($test->{'comment'}); + delete($test->{'logfile'}); - # 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"; + run_testcase($test); + #$test->{result}= 'MTR_RES_PASSED'; + # Send it back, now with results set + #$test->print_test(); + $test->write_test($server, 'TESTRESULT'); + } + elsif ($line eq 'BYE'){ + mtr_report("Server said BYE"); + exit(0); + } + else { + mtr_error("Could not understand server, '$line'"); } } - if ( $ENV{'MTR_BUILD_THREAD'} ) - { - set_mtr_build_thread_ports($ENV{'MTR_BUILD_THREAD'}); - } + stop_all_servers(); - # 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"; + exit(1); +} - # 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 = ( - ); +sub ignore_option { + my ($opt, $value)= @_; + mtr_report("Ignoring option '$opt'"); +} + + + +# Setup any paths that are $opt_vardir related +sub set_vardir { + my ($vardir)= @_; + + $opt_vardir= $vardir; + $path_vardir_trace= $opt_vardir; + # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/... + $path_vardir_trace=~ s/^\w://; + + # Location of my.cnf that all clients use + $path_config_file= "$opt_vardir/my.cnf"; + + $path_testlog= "$opt_vardir/log/mysqltest.log"; + $path_current_testlog= "$opt_vardir/log/current_test"; + +} + + +sub command_line_setup { + my $opt_comment; + my $opt_usage; + + # Read the command line options + # 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 @@ -559,54 +770,47 @@ sub command_line_setup () { 'ssl|with-openssl' => \$opt_ssl, 'skip-ssl' => \$opt_skip_ssl, 'compress' => \$opt_compress, - 'bench' => \$opt_bench, - 'small-bench' => \$opt_small_bench, - 'with-ndbcluster|ndb' => \$opt_with_ndbcluster, - 'vs-config' => \$opt_vs_config, + 'vs-config' => \$opt_vs_config, + + # Max number of parallel threads to use + 'parallel=i' => \$opt_parallel, + + # Config file to use as template for all tests + 'defaults-file=s' => \&collect_option, + # Extra config file to append to all generated configs + 'defaults-extra-file=s' => \&collect_option, # Control what test suites or cases to run 'force' => \$opt_force, - 'with-ndbcluster-only' => \$opt_with_ndbcluster_only, + 'with-ndbcluster-only' => \&collect_option, 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, - 'skip-ndbcluster-slave|skip-ndb-slave' - => \$opt_skip_ndbcluster_slave, - 'ndb-extra-test' => \$opt_ndb_extra_test, - '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-im' => \$opt_skip_im, - 'skip-test=s' => \$opt_skip_test, + 'skip-rpl' => \&collect_option, + 'skip-test=s' => \&collect_option, + 'do-test=s' => \&collect_option, + 'start-from=s' => \&collect_option, 'big-test' => \$opt_big_test, - 'combination=s' => \@opt_combinations, - 'skip-combination' => \$opt_skip_combination, + 'combination=s' => \@opt_combinations, + 'skip-combinations' => \&collect_option, + + 'skip-im' => \&ignore_option, # Specify ports - 'master_port=i' => \$opt_master_myport, - 'slave_port=i' => \$opt_slave_myport, - 'ndbcluster-port|ndbcluster_port=i' => \$opt_ndbcluster_port, - 'ndbcluster-port-slave=i' => \$opt_ndbcluster_port_slave, - 'im-port=i' => \$im_port, # Instance Manager port. - 'im-mysqld1-port=i' => \$im_mysqld1_port, # Port of mysqld, controlled by IM - 'im-mysqld2-port=i' => \$im_mysqld2_port, # Port of mysqld, controlled by IM - 'mtr-build-thread=i' => \$opt_mtr_build_thread, + 'build-thread|mtr-build-thread=i' => \$opt_build_thread, # Test case authoring 'record' => \$opt_record, - 'check-testcases' => \$opt_check_testcases, + 'check-testcases!' => \$opt_check_testcases, 'mark-progress' => \$opt_mark_progress, # Extra options used when starting mysqld 'mysqld=s' => \@opt_extra_mysqld_opt, # Run test on running server - 'extern' => \$opt_extern, - 'ndb-connectstring=s' => \$opt_ndbconnectstring, - 'ndb-connectstring-slave=s' => \$opt_ndbconnectstring_slave, + 'extern=s' => \%opts_extern, # Append to hash # Debugging + 'debug' => \$opt_debug, 'gdb' => \$opt_gdb, 'client-gdb' => \$opt_client_gdb, 'manual-gdb' => \$opt_manual_gdb, @@ -616,14 +820,13 @@ sub command_line_setup () { '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, + 'strace-client:s' => \$opt_strace_client, 'max-save-core=i' => \$opt_max_save_core, + 'max-save-datadir=i' => \$opt_max_save_datadir, + 'max-test-fail=i' => \$opt_max_test_fail, # Coverage, profiling etc 'gcov' => \$opt_gcov, - 'gprof' => \$opt_gprof, 'valgrind|valgrind-all' => \$opt_valgrind, 'valgrind-mysqltest' => \$opt_valgrind_mysqltest, 'valgrind-mysqld' => \$opt_valgrind_mysqld, @@ -642,21 +845,9 @@ sub command_line_setup () { '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, @@ -664,48 +855,37 @@ sub command_line_setup () { # 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, + 'reorder!' => \&collect_option, + 'enable-disabled' => \&collect_option, + 'verbose+' => \$opt_verbose, + 'verbose-restart' => \&report_option, 'sleep=i' => \$opt_sleep, - 'socket=s' => \$opt_socket, 'start-dirty' => \$opt_start_dirty, - 'start-and-exit' => \$opt_start_and_exit, - 'timer!' => \$opt_timer, + 'start' => \$opt_start, + 'print-testcases' => \&collect_option, + 'repeat=i' => \$opt_repeat, + 'retry=i' => \$opt_retry, + 'retry-failure=i' => \$opt_retry_failure, + 'timer!' => \&report_option, '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), + 'shutdown-timeout=i' => \$opt_shutdown_timeout, + 'warnings!' => \$opt_warnings, + 'timestamp' => \&report_option, + 'timediff' => \&report_option, 'help|h' => \$opt_usage, ) or usage("Can't read options"); usage("") if $opt_usage; - $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 to the mysql-test directory and execute the script " . - "as follows:\n./$glob_scriptname"); + # -------------------------------------------------------------------------- + # Setup verbosity + # -------------------------------------------------------------------------- + if ($opt_verbose != 0){ + report_option('verbose', $opt_verbose); } if ( -d "../sql" ) @@ -714,77 +894,28 @@ sub command_line_setup () { } # Find the absolute path to the test directory - $glob_mysql_test_dir= cwd(); - if ( $glob_cygwin_perl ) + $glob_mysql_test_dir= cwd(); + if (IS_CYGWIN) { - # Windows programs like 'mysqld' needs Windows paths - $glob_mysql_test_dir= `cygpath -m "$glob_mysql_test_dir"`; - chomp($glob_mysql_test_dir); + # Use mixed path format i.e c:/path/to/ + $glob_mysql_test_dir= mixed_path($glob_mysql_test_dir); } - $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); + $basedir= dirname($glob_mysql_test_dir); # 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; - - $path_my_basedir= - $source_dist ? $glob_mysql_test_dir : $glob_basedir; - - $glob_timers= mtr_init_timers(); - - # -------------------------------------------------------------------------- - # Embedded server flag - # -------------------------------------------------------------------------- - if ( $opt_embedded_server ) + if ( ! $source_dist and ! -d "$basedir/bin" ) { - $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_ndbcluster= 1; # Turn off use of NDB cluster - $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"); - } + $basedir= dirname($basedir); } - # - # 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) { @@ -793,52 +924,39 @@ sub command_line_setup () { } else { - $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", - "$glob_basedir/client_debug", + $path_client_bindir= mtr_path_exists("$basedir/client_release", + "$basedir/client_debug", vs_config_dirs('client', ''), - "$glob_basedir/client", - "$glob_basedir/bin"); + "$basedir/client", + "$basedir/bin"); } - + # Look for language files and charsetsdir, use same share - $path_share= mtr_path_exists("$glob_basedir/share/mysql", - "$glob_basedir/sql/share", - "$glob_basedir/share"); + my $path_share= mtr_path_exists("$basedir/share/mysql", + "$basedir/sql/share", + "$basedir/share"); + $path_language= mtr_path_exists("$path_share/english"); $path_charsetsdir= mtr_path_exists("$path_share/charsets"); - - if (!$opt_extern) + if (using_extern()) { - $exe_mysqld= mtr_exe_exists (vs_config_dirs('sql', 'mysqld'), - vs_config_dirs('sql', 'mysqld-debug'), - "$glob_basedir/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_basedir/libexec/mysqld", - "$glob_basedir/bin/mysqld", - "$glob_basedir/sbin/mysqld"); - - # Use the mysqld found above to find out what features are available - collect_mysqld_features(); + # Connect to the running mysqld and find out what it supports + collect_mysqld_features_from_running_server(); } else { - $mysqld_variables{'port'}= 3306; - $mysqld_variables{'master-port'}= 3306; + # Run the mysqld to find out what features are available + collect_mysqld_features(); } if ( $opt_comment ) { - print "\n"; - print '#' x 78, "\n"; - print "# $opt_comment\n"; - print '#' x 78, "\n\n"; + mtr_report(); + mtr_print_thick_line('#'); + mtr_report("# $opt_comment"); + mtr_print_thick_line('#'); } foreach my $arg ( @ARGV ) @@ -866,22 +984,13 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Find out type of logging that are being used # -------------------------------------------------------------------------- - if (!$opt_extern && $mysql_version_id >= 50100 ) + foreach my $arg ( @opt_extra_mysqld_opt ) { - foreach my $arg ( @opt_extra_mysqld_opt ) - { - if ( $arg =~ /binlog[-_]format=(\S+)/ ) - { - $used_binlog_format= $1; - } - } - if (defined $used_binlog_format) + if ( $arg =~ /binlog[-_]format=(\S+)/ ) { - mtr_report("Using binlog format '$used_binlog_format'"); - } - else - { - mtr_report("Using dynamic switching of binlog format"); + # Save this for collect phase + collect_option('binlog-format', $1); + mtr_report("Using binlog format '$1'"); } } @@ -889,26 +998,20 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Find out default storage engine being used(if any) # -------------------------------------------------------------------------- - if ( $opt_with_ndbcluster ) - { - # --ndb or --with-ndbcluster turns on --default-storage-engine=ndbcluster - push(@opt_extra_mysqld_opt, "--default-storage-engine=ndbcluster"); - } - foreach my $arg ( @opt_extra_mysqld_opt ) { if ( $arg =~ /default-storage-engine=(\S+)/ ) { - $used_default_engine= $1; + # Save this for collect phase + collect_option('default-storage-engine', $1); + mtr_report("Using default engine '$1'") } } - mtr_report("Using default engine '$used_default_engine'") - if defined $used_default_engine; # -------------------------------------------------------------------------- # Check if we should speed up tests by trying to run on tmpfs # -------------------------------------------------------------------------- - if ( defined $opt_mem ) + if ( defined $opt_mem) { mtr_error("Can't use --mem and --vardir at the same time ") if $opt_vardir; @@ -916,7 +1019,7 @@ sub command_line_setup () { if $opt_tmpdir; # Search through list of locations that are known - # to be "fast disks" to list to find a suitable location + # to be "fast disks" to find a suitable location # Use --mem=<dir> as first location to look. my @tmpfs_locations= ($opt_mem, "/dev/shm", "/tmp"); @@ -924,72 +1027,56 @@ sub command_line_setup () { { if ( -d $fs ) { - mtr_report("Using tmpfs in $fs"); - $opt_mem= "$fs/var"; - $opt_mem .= $opt_mtr_build_thread if $opt_mtr_build_thread; + my $template= "var_${opt_build_thread}_XXXX"; + $opt_mem= tempdir( $template, DIR => $fs, CLEANUP => 0); last; } } } # -------------------------------------------------------------------------- - # Set the "var/" directory, as it is the base for everything else + # Set the "var/" directory, the base for everything else # -------------------------------------------------------------------------- + $default_vardir= "$glob_mysql_test_dir/var"; 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) ) + (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:/,i) ) { # Make absolute path, relative test dir $opt_vardir= "$glob_mysql_test_dir/$opt_vardir"; } + set_vardir($opt_vardir); + # -------------------------------------------------------------------------- - # Set tmpdir + # Set the "tmp" directory # -------------------------------------------------------------------------- - $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; + if ( ! $opt_tmpdir ) + { + $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; + + if (check_socket_path_length("$opt_tmpdir/mysql_testsocket.sock")) + { + mtr_report("Too long tmpdir path '$opt_tmpdir'", + " creating a shorter one..."); + + # Create temporary directory in standard location for temporary files + $opt_tmpdir= tempdir( TMPDIR => 1, CLEANUP => 1 ); + mtr_report(" - using tmpdir: '$opt_tmpdir'\n"); + } + } $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any # -------------------------------------------------------------------------- - # Check im suport + # fast option # -------------------------------------------------------------------------- - if ($opt_extern) - { - mtr_report("Disable instance manager when running with extern mysqld"); - $opt_skip_im= 1; - } - elsif ( $mysql_version_id < 50000 ) - { - # Instance manager is not supported until 5.0 - $opt_skip_im= 1; - } - elsif ( $glob_win32 ) - { - mtr_report("Disable Instance manager - testing not supported on Windows"); - $opt_skip_im= 1; + if ($opt_fast){ + $opt_shutdown_timeout= 0; # Kill processes instead of nice shutdown } # -------------------------------------------------------------------------- @@ -1000,25 +1087,68 @@ sub command_line_setup () { mtr_error("Will not run in record mode without a specific test case"); } - if ( $opt_record ) - { - $opt_skip_combination = 1; + if ( $opt_record ) { + # Use only one worker with --record + $opt_parallel= 1; } # -------------------------------------------------------------------------- - # ps protcol flag + # Embedded server flag # -------------------------------------------------------------------------- - if ( $opt_ps_protocol ) + if ( $opt_embedded_server ) { - push(@glob_test_mode, "ps-protocol"); - } + if ( IS_WINDOWS ) + { + # Add the location for libmysqld.dll to the path. + my $separator= ";"; + my $lib_mysqld= + mtr_path_exists(vs_config_dirs('libmysqld','')); + if ( IS_CYGWIN ) + { + $lib_mysqld= posix_path($lib_mysqld); + $separator= ":"; + } + $ENV{'PATH'}= "$ENV{'PATH'}".$separator.$lib_mysqld; + } + $opt_skip_ndbcluster= 1; # Turn off use of NDB cluster + $opt_skip_ssl= 1; # Turn off use of SSL - # -------------------------------------------------------------------------- - # Bench flags - # -------------------------------------------------------------------------- - if ( $opt_small_bench ) - { - $opt_bench= 1; + # Turn off use of bin log + push(@opt_extra_mysqld_opt, "--skip-log-bin"); + + if ( using_extern() ) + { + mtr_error("Can't use --extern with --embedded-server"); + } + + + if ($opt_gdb) + { + mtr_warning("Silently converting --gdb to --client-gdb in embedded mode"); + $opt_client_gdb= $opt_gdb; + $opt_gdb= undef; + } + + if ($opt_ddd) + { + mtr_warning("Silently converting --ddd to --client-ddd in embedded mode"); + $opt_client_ddd= $opt_ddd; + $opt_ddd= undef; + } + + if ($opt_debugger) + { + mtr_warning("Silently converting --debugger to --client-debugger in embedded mode"); + $opt_client_debugger= $opt_debugger; + $opt_debugger= undef; + } + + if ( $opt_gdb || $opt_ddd || $opt_manual_gdb || $opt_manual_ddd || + $opt_manual_debug || $opt_debugger ) + { + mtr_error("You need to use the client debug options for the", + "embedded server. Ex: --client-gdb"); + } } # -------------------------------------------------------------------------- @@ -1046,17 +1176,22 @@ sub command_line_setup () { { # Indicate that we are using debugger $glob_debugger= 1; - if ( $opt_extern ) + if ( using_extern() ) { mtr_error("Can't use --extern when using debugger"); } } # -------------------------------------------------------------------------- - # Check if special exe was selected for master or slave + # Check timeout arguments # -------------------------------------------------------------------------- - $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; - $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; + + mtr_error("Invalid value '$opt_testcase_timeout' supplied ". + "for option --testcase-timeout") + if ($opt_testcase_timeout <= 0); + mtr_error("Invalid value '$opt_suite_timeout' supplied ". + "for option --testsuite-timeout") + if ($opt_suite_timeout <= 0); # -------------------------------------------------------------------------- # Check valgrind arguments @@ -1067,6 +1202,12 @@ sub command_line_setup () { $opt_valgrind= 1; $opt_valgrind_mysqld= 1; $opt_valgrind_mysqltest= 1; + + # Increase the timeouts when running with valgrind + $opt_testcase_timeout*= 10; + $opt_suite_timeout*= 6; + $opt_start_timeout*= 10; + } elsif ( $opt_valgrind_mysqld ) { @@ -1100,272 +1241,17 @@ sub command_line_setup () { join(" ", @valgrind_args), "\""); } - if ( ! $opt_testcase_timeout ) - { - $opt_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= $default_suite_timeout; - $opt_suite_timeout*= 6 if $opt_valgrind; - $opt_suite_timeout*= 6 if ($opt_debug and $glob_win32); - } + mtr_report("Checking supported features..."); - 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 - cluster => 0, # index in clusters list - 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 - cluster => 0, # index in clusters list - 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, - - cluster => 1, # index in clusters list - 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, - cluster => -1, # index in clusters list - 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, - cluster => -1, # index in clusters list - start_opts => [], - }; - - $instance_manager= - { - path_err => "$opt_vardir/log/im.err", - path_log => "$opt_vardir/log/im.log", - path_pid => "$opt_vardir/run/im.pid", - path_angel_pid => "$opt_vardir/run/im.angel.pid", - path_sock => "$sockdir/im.sock", - port => $im_port, - start_timeout => $master->[0]->{'start_timeout'}, - admin_login => 'im_admin', - admin_password => 'im_admin_secret', - admin_sha1 => '*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295', - password_file => "$opt_vardir/im.passwd", - defaults_file => "$opt_vardir/im.cnf", - }; - - $instance_manager->{'instances'}->[0]= - { - server_id => 1, - port => $im_mysqld1_port, - path_datadir => "$opt_vardir/im_mysqld_1.data", - path_sock => "$sockdir/mysqld_1.sock", - path_pid => "$opt_vardir/run/mysqld_1.pid", - start_timeout => 400, # enough time create innodb tables - old_log_format => 1 - }; - - $instance_manager->{'instances'}->[1]= - { - server_id => 2, - port => $im_mysqld2_port, - path_datadir => "$opt_vardir/im_mysqld_2.data", - path_sock => "$sockdir/mysqld_2.sock", - path_pid => "$opt_vardir/run/mysqld_2.pid", - nonguarded => 1, - start_timeout => 400, # enough time create innodb tables - old_log_format => 1 - }; - - my $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; - $clusters->[0]= - { - name => "Master", - nodes => 2, - port => "$opt_ndbcluster_port", - data_dir => "$data_dir", - connect_string => "host=localhost:$opt_ndbcluster_port", - path_pid => "$data_dir/ndb_3.pid", # Nodes + 1 - pid => 0, # pid of ndb_mgmd - installed_ok => 0, - }; - - $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port_slave"; - $clusters->[1]= - { - name => "Slave", - nodes => 1, - port => "$opt_ndbcluster_port_slave", - data_dir => "$data_dir", - connect_string => "host=localhost:$opt_ndbcluster_port_slave", - path_pid => "$data_dir/ndb_2.pid", # Nodes + 1 - pid => 0, # pid of ndb_mgmd - installed_ok => 0, - }; - - # Init pids of ndbd's - foreach my $cluster ( @{$clusters} ) - { - for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ ) - { - my $nodeid= $idx+1; - $cluster->{'ndbds'}->[$idx]= - { - pid => 0, - nodeid => $nodeid, - path_pid => "$cluster->{'data_dir'}/ndb_${nodeid}.pid", - path_fs => "$cluster->{'data_dir'}/ndb_${nodeid}_fs", - }; - } - } - - # -------------------------------------------------------------------------- - # extern - # -------------------------------------------------------------------------- - if ( $opt_extern ) - { - # Turn off features not supported when running with extern server - $opt_skip_rpl= 1; - $opt_skip_ndbcluster= 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; - } - - - # -------------------------------------------------------------------------- - # ndbconnectstring and ndbconnectstring_slave - # -------------------------------------------------------------------------- - if ( $opt_ndbconnectstring ) - { - # ndbconnectstring was supplied by user, the tests shoudl be run - # against an already started cluster, change settings - my $cluster= $clusters->[0]; # Master cluster - $cluster->{'connect_string'}= $opt_ndbconnectstring; - $cluster->{'use_running'}= 1; - - mtr_error("Can't specify --ndb-connectstring and --skip-ndbcluster") - if $opt_skip_ndbcluster; - } - $ENV{'NDB_CONNECTSTRING'}= $clusters->[0]->{'connect_string'}; - - - if ( $opt_ndbconnectstring_slave ) - { - # ndbconnectstring-slave was supplied by user, the tests should be run - # agains an already started slave cluster, change settings - my $cluster= $clusters->[1]; # Slave cluster - $cluster->{'connect_string'}= $opt_ndbconnectstring_slave; - $cluster->{'use_running'}= 1; - - mtr_error("Can't specify ndb-connectstring_slave and " . - "--skip-ndbcluster-slave") - if $opt_skip_ndbcluster_slave; - } - - - $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_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; + check_ndbcluster_support(\%mysqld_variables); + check_ssl_support(\%mysqld_variables); + check_debug_support(\%mysqld_variables); - $path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/"; + executable_setup(); - 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}" : ""; - $mysqld->{path_myerr}= - "$opt_vardir/log/" . $mysqld->{type} . "$sidx.trace"; - } - } } + # # 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 @@ -1381,79 +1267,47 @@ sub command_line_setup () { # 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"; +sub set_build_thread_ports($) { + my $build_thread= shift || 0; + + if ( lc($build_thread) eq 'auto' ) { + #mtr_report("Requesting build thread... "); + $build_thread= mtr_get_unique_id(250, 299); + if ( !defined $build_thread ) { + mtr_error("Could not get a unique build thread id"); + } + #mtr_report(" - got $build_thread"); } + $ENV{MTR_BUILD_THREAD}= $build_thread; + $opt_build_thread= $build_thread; - # 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 - $opt_ndbcluster_port= $opt_master_myport + 5; - $opt_ndbcluster_port_slave= $opt_master_myport + 6; - $im_port= $opt_master_myport + 7; - $im_mysqld1_port= $opt_master_myport + 8; - $im_mysqld2_port= $opt_master_myport + 9; - - if ( $opt_master_myport < 5001 or $opt_master_myport + 10 >= 32767 ) + # Calculate baseport + $baseport= $build_thread * 10 + 10000; + if ( $baseport < 5001 or $baseport + 9 >= 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'}); + "($baseport - $baseport + 9)"); } - for (my $idx= 0; $idx < $max_slave_num; $idx++) - { - push(@data_dir_lst, $slave->[$idx]->{'path_myddir'}); - } + mtr_report("Using MTR_BUILD_THREAD $build_thread,", + "with reserved ports $baseport..".($baseport+9)); - unless ($opt_skip_im) - { - foreach my $instance (@{$instance_manager->{'instances'}}) - { - push(@data_dir_lst, $instance->{'path_datadir'}); - } - } } -############################################################################## -# -# Set paths to various executable programs -# -############################################################################## - - -sub collect_mysqld_features () { +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 + my $use_tmpdir; + if ( defined $opt_tmpdir and -d $opt_tmpdir){ + # Create the tempdir in $opt_tmpdir + $use_tmpdir= $opt_tmpdir; } + my $tmpdir= tempdir(CLEANUP => 0, # Directory removed by this function + DIR => $use_tmpdir); # - # Execute "mysqld --help --verbose" to get a list + # Execute "mysqld --no-defaults --help --verbose" to get a # list of all features and settings # # --no-defaults and --skip-grant-tables are to avoid loading @@ -1461,7 +1315,18 @@ sub collect_mysqld_features () { # # --datadir must exist, mysqld will chdir into it # - my $list= `$exe_mysqld --no-defaults --datadir=$tmpdir --language=$path_language --skip-grant-tables --verbose --help`; + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--datadir=%s", mixed_path($tmpdir)); + mtr_add_arg($args, "--language=%s", $path_language); + mtr_add_arg($args, "--skip-grant-tables"); + mtr_add_arg($args, "--verbose"); + mtr_add_arg($args, "--help"); + + my $exe_mysqld= find_mysqld($basedir); + my $cmd= join(" ", $exe_mysqld, @$args); + my $list= `$cmd`; foreach my $line (split('\n', $list)) { @@ -1516,99 +1381,75 @@ sub collect_mysqld_features () { } } } - rmtree($tmpdir) if (!$opt_tmpdir); + rmtree($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)= @_; + +sub collect_mysqld_features_from_running_server () +{ + my $mysql= mtr_exe_exists("$path_client_bindir/mysql"); 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`; -} + while (my ($option, $value)= each( %opts_extern )) { + mtr_add_arg($args, "--$option=$value"); + } -sub collect_mysqld_features_from_running_server () -{ - my $list= run_query($master->[0], "use mysql; SHOW VARIABLES"); + mtr_add_arg($args, "--silent"); # Tab separated output + mtr_add_arg($args, "-e '%s'", "use mysql; SHOW VARIABLES"); + my $cmd= "$mysql " . join(' ', @$args); + mtr_verbose("cmd: $cmd"); - foreach my $line (split('\n', $list)) + my $list = `$cmd` or + mtr_error("Could not connect to extern server using command: '$cmd'"); + foreach my $line (split('\n', $list )) { # Put variables into hash if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ ) { - print "$1=\"$2\"\n"; + # print "$1=\"$2\"\n"; $mysqld_variables{$1}= $2; } } + + # Parse version + my $version_str= $mysqld_variables{'version'}; + if ( $version_str =~ /^([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"); + } + mtr_error("Could not find version of MySQL") unless $mysql_version_id; } -sub executable_setup_im () { +sub find_mysqld { + my ($mysqld_basedir)= @_; - # Look for instance manager binary - mysqlmanager - $exe_im= - mtr_exe_maybe_exists( - "$glob_basedir/server-tools/instance-manager/mysqlmanager", - "$glob_basedir/libexec/mysqlmanager", - "$glob_basedir/bin/mysqlmanager", - "$glob_basedir/sbin/mysqlmanager"); + my @mysqld_names= ("mysqld", "mysqld-max-nt", "mysqld-max", + "mysqld-nt"); - return ($exe_im eq ""); -} + if ( $opt_debug ){ + # Put mysqld-debug first in the list of binaries to look for + mtr_verbose("Adding mysqld-debug first in list of binaries to look for"); + unshift(@mysqld_names, "mysqld-debug"); + } -sub executable_setup_ndb () { - - # Look for ndb tols and binaries - my $ndb_path= mtr_file_exists("$glob_basedir/ndb", - "$glob_basedir/storage/ndb", - "$glob_basedir/bin"); - - $exe_ndbd= - mtr_exe_maybe_exists("$ndb_path/src/kernel/ndbd", - "$ndb_path/ndbd", - "$glob_basedir/libexec/ndbd"); - $exe_ndb_mgm= - mtr_exe_maybe_exists("$ndb_path/src/mgmclient/ndb_mgm", - "$ndb_path/ndb_mgm"); - $exe_ndb_mgmd= - mtr_exe_maybe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", - "$ndb_path/ndb_mgmd", - "$glob_basedir/libexec/ndb_mgmd"); - $exe_ndb_waiter= - mtr_exe_maybe_exists("$ndb_path/tools/ndb_waiter", - "$ndb_path/ndb_waiter"); - - # May not exist - $path_ndb_tools_dir= mtr_file_exists("$ndb_path/tools", - "$ndb_path"); - # May not exist - $path_ndb_examples_dir= - mtr_file_exists("$ndb_path/ndbapi-examples", - "$ndb_path/examples"); - # May not exist - $exe_ndb_example= - mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); - - return ( $exe_ndbd eq "" or - $exe_ndb_mgm eq "" or - $exe_ndb_mgmd eq "" or - $exe_ndb_waiter eq ""); + return my_find_bin($mysqld_basedir, + ["sql", "libexec", "sbin", "bin"], + [@mysqld_names]); } + sub executable_setup () { # @@ -1626,105 +1467,35 @@ sub executable_setup () { } } - # 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_basedir/extra/my_print_defaults"); - - # Look for perror - $exe_perror= mtr_exe_exists(vs_config_dirs('extra', 'perror'), - "$glob_basedir/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) + if ( ! $opt_skip_ndbcluster ) { - # 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"); - } + $exe_ndbd= + my_find_bin($basedir, + ["storage/ndb/src/kernel", "libexec", "sbin", "bin"], + "ndbd"); - 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= ""; - } + $exe_ndb_mgmd= + my_find_bin($basedir, + ["storage/ndb/src/mgmsrv", "libexec", "sbin", "bin"], + "ndb_mgmd"); - if ( ! $glob_win32 ) - { - # Look for mysql_fix_system_table script - $exe_mysql_fix_system_tables= - mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", - "$path_client_bindir/mysql_fix_privilege_tables"); - } - - # 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"); - - if ( ! $opt_skip_ndbcluster and executable_setup_ndb()) - { - mtr_warning("Could not find all required ndb binaries, " . - "all ndb tests will fail, use --skip-ndbcluster to " . - "skip testing it."); - - foreach my $cluster (@{$clusters}) - { - $cluster->{"executable_setup_failed"}= 1; - } - } - - if ( ! $opt_skip_im and executable_setup_im()) - { - mtr_warning("Could not find all required instance manager binaries, " . - "all im tests will fail, use --skip-im to " . - "continue without instance manager"); - $instance_manager->{"executable_setup_failed"}= 1; - } - - # Look for the udf_example library - $lib_udf_example= - mtr_file_exists(vs_config_dirs('sql', 'udf_example.dll'), - "$glob_basedir/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_basedir/storage/example/.libs/ha_example.so",); + $exe_ndb_waiter= + my_find_bin($basedir, + ["storage/ndb/tools/", "bin"], + "ndb_waiter"); } # Look for mysqltest executable - if ( $glob_use_embedded_server ) + if ( $opt_embedded_server ) { $exe_mysqltest= mtr_exe_exists(vs_config_dirs('libmysqld/examples','mysqltest_embedded'), - "$glob_basedir/libmysqld/examples/mysqltest_embedded", + "$basedir/libmysqld/examples/mysqltest_embedded", "$path_client_bindir/mysqltest_embedded"); } else @@ -1732,120 +1503,115 @@ sub executable_setup () { $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_basedir/libmysqld/examples/mysql_client_test_embedded"); - } - else - { - $exe_mysql_client_test= - mtr_exe_maybe_exists(vs_config_dirs('tests', 'mysql_client_test'), - "$glob_basedir/tests/mysql_client_test", - "$glob_basedir/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_basedir/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="; +sub client_debug_arg($$) { + my ($args, $client_name)= @_; + + if ( $opt_debug ) { + mtr_add_arg($args, + "--debug=d:t:A,%s/log/%s.trace", + $path_vardir_trace, $client_name) + } } -############################################################################## -# -# 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_fix_arguments () { -sub mysql_client_test_arguments() -{ - my $exe= $exe_mysql_client_test; + return "" if ( IS_WINDOWS ); + my $exe= + mtr_script_exists("$basedir/scripts/mysql_fix_privilege_tables", + "$path_client_bindir/mysql_fix_privilege_tables"); my $args; mtr_init_args(\$args); - if ( $opt_valgrind_mysqltest ) - { - valgrind_arguments($args, \$exe); - } + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); - 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'}"); + mtr_add_arg($args, "--basedir=%s", $basedir); + mtr_add_arg($args, "--bindir=%s", $path_client_bindir); + mtr_add_arg($args, "--verbose"); + return mtr_args2str($exe, @$args); +} - 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"); - } +sub client_arguments ($) { + my $client_name= shift; + my $client_exe= mtr_exe_exists("$path_client_bindir/$client_name"); - if ( $glob_use_embedded_server ) - { - mtr_add_arg($args, - " -A --language=$path_language"); - mtr_add_arg($args, - " -A --datadir=$slave->[0]->{'path_myddir'}"); - mtr_add_arg($args, - " -A --character-sets-dir=$path_charsetsdir"); + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + client_debug_arg($args, $client_name); + return mtr_args2str($client_exe, @$args); +} + + +sub mysqlslap_arguments () { + my $exe= mtr_exe_maybe_exists("$path_client_bindir/mysqlslap"); + if ( $exe eq "" ) { + # mysqlap was not found + + if (defined $mysql_version_id and $mysql_version_id >= 50100 ) { + mtr_error("Could not find the mysqlslap binary"); + } + return ""; # Don't care about mysqlslap } - return join(" ", $exe, @$args); + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + client_debug_arg($args, "mysqlslap"); + return mtr_args2str($exe, @$args); } -sub mysql_upgrade_arguments() -{ - my $exe= $exe_mysql_upgrade; + +sub mysqldump_arguments ($) { + my($group_suffix) = @_; + my $exe= mtr_exe_exists("$path_client_bindir/mysqldump"); my $args; mtr_init_args(\$args); -# if ( $opt_valgrind_mysql_ugrade ) -# { -# valgrind_arguments($args, \$exe); -# } + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix); + client_debug_arg($args, "mysqldump-$group_suffix"); + return mtr_args2str($exe, @$args); +} - 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"); +sub mysql_client_test_arguments(){ + my $exe; + # mysql_client_test executable may _not_ exist + if ( $opt_embedded_server ) { + $exe= mtr_exe_maybe_exists( + vs_config_dirs('libmysqld/examples','mysql_client_test_embedded'), + "$basedir/libmysqld/examples/mysql_client_test_embedded", + "$basedir/bin/mysql_client_test_embedded"); + } else { + $exe= mtr_exe_maybe_exists(vs_config_dirs('tests', 'mysql_client_test'), + "$basedir/tests/mysql_client_test", + "$basedir/bin/mysql_client_test"); } - return join(" ", $exe, @$args); + my $args; + mtr_init_args(\$args); + if ( $opt_valgrind_mysqltest ) { + valgrind_arguments($args, \$exe); + } + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--testcase"); + mtr_add_arg($args, "--vardir=$opt_vardir"); + client_debug_arg($args,"mysql_client_test"); + + return mtr_args2str($exe, @$args); } -# Note that some env is setup in spawn/run, in "mtr_process.pl" -sub environment_setup () { +# +# Set environment to be used by childs of this process for +# things that are constant during the whole lifetime of mysql-test-run +# +sub environment_setup { umask(022); @@ -1862,24 +1628,67 @@ sub environment_setup () { # are used in favor of the system installed ones if ( $source_dist ) { - push(@ld_library_paths, "$glob_basedir/libmysql/.libs/", - "$glob_basedir/libmysql_r/.libs/", - "$glob_basedir/zlib.libs/"); + push(@ld_library_paths, "$basedir/libmysql/.libs/", + "$basedir/libmysql_r/.libs/", + "$basedir/zlib.libs/"); } else { - push(@ld_library_paths, "$glob_basedir/lib"); + push(@ld_library_paths, "$basedir/lib"); } } - # -------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Add the path where libndbclient can be found # -------------------------------------------------------------------------- - if ( $glob_ndbcluster_supported ) + if ( !$opt_skip_ndbcluster ) { - push(@ld_library_paths, "$glob_basedir/storage/ndb/src/.libs"); + push(@ld_library_paths, "$basedir/storage/ndb/src/.libs"); + } + + # -------------------------------------------------------------------------- + # Add the path where mysqld will find udf_example.so + # -------------------------------------------------------------------------- + my $lib_udf_example= + mtr_file_exists(vs_config_dirs('sql', 'udf_example.dll'), + "$basedir/sql/.libs/udf_example.so",); + + if ( $lib_udf_example ) + { + push(@ld_library_paths, dirname($lib_udf_example)); + } + + $ENV{'UDF_EXAMPLE_LIB'}= + ($lib_udf_example ? basename($lib_udf_example) : ""); + $ENV{'UDF_EXAMPLE_LIB_OPT'}= "--plugin-dir=". + ($lib_udf_example ? dirname($lib_udf_example) : ""); + + # -------------------------------------------------------------------------- + # Add the path where mysqld will find ha_example.so + # -------------------------------------------------------------------------- + if ($mysql_version_id >= 50100) { + my $lib_example_plugin= + mtr_file_exists(vs_config_dirs('storage/example', 'ha_example.dll'), + "$basedir/storage/example/.libs/ha_example.so",); + $ENV{'EXAMPLE_PLUGIN'}= + ($lib_example_plugin ? basename($lib_example_plugin) : ""); + $ENV{'EXAMPLE_PLUGIN_OPT'}= "--plugin-dir=". + ($lib_example_plugin ? dirname($lib_example_plugin) : ""); + } + # ---------------------------------------------------- + # Add the path where mysqld will find mypluglib.so + # ---------------------------------------------------- + my $lib_simple_parser= + mtr_file_exists(vs_config_dirs('plugin/fulltext', 'mypluglib.dll'), + "$basedir/plugin/fulltext/.libs/mypluglib.so",); + + $ENV{'SIMPLE_PARSER'}= + ($lib_simple_parser ? basename($lib_simple_parser) : ""); + $ENV{'SIMPLE_PARSER_OPT'}= "--plugin-dir=". + ($lib_simple_parser ? dirname($lib_simple_parser) : ""); + # -------------------------------------------------------------------------- # Valgrind need to be run with debug libraries otherwise it's almost # impossible to add correct supressions, that means if "/usr/lib/debug" @@ -1894,7 +1703,8 @@ sub environment_setup () { 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= + mtr_grab_file('/etc/debian_version')) !~ /^[0-9]+\.[0-9]$/ or $deb_version > 3.1 ) ) { push(@ld_library_paths, $debug_libraries_path); @@ -1922,14 +1732,10 @@ sub environment_setup () { 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 @@ -1940,307 +1746,109 @@ sub environment_setup () { # $ENV{'LC_ALL'}= "C"; $ENV{'LC_CTYPE'}= "C"; - + $ENV{'LC_COLLATE'}= "C"; - $ENV{'USE_RUNNING_SERVER'}= $opt_extern; + $ENV{'USE_RUNNING_SERVER'}= using_extern(); $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; - $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; + $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'master-port'} || 3306; $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{'IM_PATH_SOCK'}= $instance_manager->{path_sock}; - $ENV{'IM_USERNAME'}= $instance_manager->{admin_login}; - $ENV{'IM_PASSWORD'}= $instance_manager->{admin_password}; - $ENV{MTR_BUILD_THREAD}= $opt_mtr_build_thread; - - $ENV{'EXE_MYSQL'}= $exe_mysql; - + $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; # ---------------------------------------------------- # Setup env for NDB # ---------------------------------------------------- if ( ! $opt_skip_ndbcluster ) { - $ENV{'NDB_MGM'}= $exe_ndb_mgm; + $ENV{'NDB_MGM'}= + my_find_bin($basedir, + ["storage/ndb/src/mgmclient", "bin"], + "ndb_mgm"); - $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; - $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; + $ENV{'NDB_TOOLS_DIR'}= + my_find_dir($basedir, + ["storage/ndb/tools", "bin"]); - $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; + $ENV{'NDB_EXAMPLES_DIR'}= + my_find_dir($basedir, + ["storage/ndb/ndbapi-examples", "bin"]); - $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; - $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; - $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; - $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; + $ENV{'NDB_EXAMPLES_BINARY'}= + my_find_bin($basedir, + ["storage/ndb/ndbapi-examples/ndbapi_simple", "bin"], + "ndbapi_simple", NOT_REQUIRED); - if ( $mysql_version_id >= 50000 ) - { - $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; - $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; - } + my $path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; + $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; } # ---------------------------------------------------- - # Setup env for IM + # mysql clients # ---------------------------------------------------- - if ( ! $opt_skip_im ) - { - $ENV{'IM_EXE'}= $exe_im; - $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; - $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; - $ENV{'IM_PORT'}= $instance_manager->{port}; - $ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file}; - $ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file}; - - $ENV{'IM_MYSQLD1_SOCK'}= - $instance_manager->{instances}->[0]->{path_sock}; - $ENV{'IM_MYSQLD1_PORT'}= - $instance_manager->{instances}->[0]->{port}; - $ENV{'IM_MYSQLD1_PATH_PID'}= - $instance_manager->{instances}->[0]->{path_pid}; - $ENV{'IM_MYSQLD2_SOCK'}= - $instance_manager->{instances}->[1]->{path_sock}; - $ENV{'IM_MYSQLD2_PORT'}= - $instance_manager->{instances}->[1]->{port}; - $ENV{'IM_MYSQLD2_PATH_PID'}= - $instance_manager->{instances}->[1]->{path_pid}; - } - - # ---------------------------------------------------- - # 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= "; + $ENV{'MYSQL_CHECK'}= client_arguments("mysqlcheck"); + $ENV{'MYSQL_DUMP'}= mysqldump_arguments(".1"); + $ENV{'MYSQL_DUMP_SLAVE'}= mysqldump_arguments(".2"); + $ENV{'MYSQL_SLAP'}= mysqlslap_arguments(); + $ENV{'MYSQL_IMPORT'}= client_arguments("mysqlimport"); + $ENV{'MYSQL_SHOW'}= client_arguments("mysqlshow"); + $ENV{'MYSQL_BINLOG'}= client_arguments("mysqlbinlog"); + $ENV{'MYSQL'}= client_arguments("mysql"); + $ENV{'MYSQL_UPGRADE'}= client_arguments("mysql_upgrade"); + $ENV{'MYSQLADMIN'}= native_path($exe_mysqladmin); + $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); + $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= mysql_fix_arguments(); + $ENV{'EXE_MYSQL'}= $exe_mysql; - 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 + # bug25714 executable may _not_ exist in + # some versions, test using it should be skipped # ---------------------------------------------------- - if ( !$opt_extern && $mysql_version_id >= 50000 ) - { - $ENV{'MYSQL_UPGRADE'}= mysql_upgrade_arguments(); - } + my $exe_bug25714= + mtr_exe_maybe_exists(vs_config_dirs('tests', 'bug25714'), + "$basedir/tests/bug25714"); + $ENV{'MYSQL_BUG25714'}= native_path($exe_bug25714); # ---------------------------------------------------- - # Setup env so childs can execute mysql_fix_system_tables + # mysql_fix_privilege_tables.sql # ---------------------------------------------------- - if ( !$opt_extern && ! $glob_win32 ) - { - 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]->{'port'} " . - "--socket=$master->[0]->{'path_sock'}"; - $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; - - } + my $file_mysql_fix_privilege_tables= + mtr_file_exists("$basedir/scripts/mysql_fix_privilege_tables.sql", + "$basedir/share/mysql_fix_privilege_tables.sql", + "$basedir/share/mysql/mysql_fix_privilege_tables.sql"); $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 + # my_print_defaults # ---------------------------------------------------- - $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) : ""); + my $exe_my_print_defaults= + mtr_exe_exists(vs_config_dirs('extra', 'my_print_defaults'), + "$path_client_bindir/my_print_defaults", + "$basedir/extra/my_print_defaults"); + $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= native_path($exe_my_print_defaults); # ---------------------------------------------------- # Setup env so childs can execute myisampack and myisamchk # ---------------------------------------------------- - $ENV{'MYISAMCHK'}= mtr_native_path(mtr_exe_exists( + $ENV{'MYISAMCHK'}= native_path(mtr_exe_exists( vs_config_dirs('storage/myisam', 'myisamchk'), vs_config_dirs('myisam', 'myisamchk'), "$path_client_bindir/myisamchk", - "$glob_basedir/storage/myisam/myisamchk", - "$glob_basedir/myisam/myisamchk")); - $ENV{'MYISAMPACK'}= mtr_native_path(mtr_exe_exists( + "$basedir/storage/myisam/myisamchk", + "$basedir/myisam/myisamchk")); + $ENV{'MYISAMPACK'}= native_path(mtr_exe_exists( vs_config_dirs('storage/myisam', 'myisampack'), vs_config_dirs('myisam', 'myisampack'), "$path_client_bindir/myisampack", - "$glob_basedir/storage/myisam/myisampack", - "$glob_basedir/myisam/myisampack")); + "$basedir/storage/myisam/myisampack", + "$basedir/myisam/myisampack")); # ---------------------------------------------------- - # We are nice and report a bit about our settings + # perror # ---------------------------------------------------- - 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"; - if ( ! $opt_skip_ndbcluster ) - { - print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; - if ( ! $opt_skip_ndbcluster_slave ) - { - print "Using NDBCLUSTER_PORT_SLAVE = $ENV{NDBCLUSTER_PORT_SLAVE}\n"; - } - } - if ( ! $opt_skip_im ) - { - print "Using IM_PORT = $ENV{IM_PORT}\n"; - print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n"; - print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; - } - } + my $exe_perror= mtr_exe_exists(vs_config_dirs('extra', 'perror'), + "$basedir/extra/perror", + "$path_client_bindir/perror"); + $ENV{'MY_PERROR'}= native_path($exe_perror); # Create an environment variable to make it possible # to detect that valgrind is being used from test cases @@ -2249,52 +1857,6 @@ sub environment_setup () { } -############################################################################## -# -# 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 @@ -2302,11 +1864,11 @@ sub kill_running_servers () { # sub remove_stale_vardir () { - mtr_report("Removing Stale Files"); + mtr_report("Removing old var directory..."); # Safety! mtr_error("No, don't remove the vardir when running with --extern") - if $opt_extern; + if using_extern(); mtr_verbose("opt_vardir: $opt_vardir"); if ( $opt_vardir eq $default_vardir ) @@ -2318,30 +1880,22 @@ sub remove_stale_vardir () { { # var is a symlink - if ( $opt_mem and readlink($opt_vardir) eq $opt_mem ) + if ( $opt_mem ) { # Remove the directory which the link points at mtr_verbose("Removing " . readlink($opt_vardir)); - mtr_rmtree(readlink($opt_vardir)); + 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"); + mtr_report(" - WARNING: Using the 'mysql-test/var' symlink"); # Make sure the directory where it points exist mtr_error("The destination for symlink $opt_vardir does not exist") @@ -2350,7 +1904,7 @@ sub remove_stale_vardir () { foreach my $bin ( glob("$opt_vardir/*") ) { mtr_verbose("Removing bin $bin"); - mtr_rmtree($bin); + rmtree($bin); } } } @@ -2358,7 +1912,7 @@ sub remove_stale_vardir () { { # Remove the entire "var" dir mtr_verbose("Removing $opt_vardir/"); - mtr_rmtree("$opt_vardir/"); + rmtree("$opt_vardir/"); } if ( $opt_mem ) @@ -2367,7 +1921,7 @@ sub remove_stale_vardir () { # 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); + rmtree($opt_mem); } } @@ -2380,19 +1934,24 @@ sub remove_stale_vardir () { # 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); + rmtree($default_vardir); # Remove the "var" dir mtr_verbose("Removing $opt_vardir/"); - mtr_rmtree("$opt_vardir/"); + rmtree("$opt_vardir/"); } + # Remove the "tmp" dir + mtr_verbose("Removing $opt_tmpdir/"); + rmtree("$opt_tmpdir/"); } + + # # Create var and the directories needed in var # sub setup_vardir() { - mtr_report("Creating Directories"); + mtr_report("Creating var directory '$opt_vardir'..."); if ( $opt_vardir eq $default_vardir ) { @@ -2413,7 +1972,7 @@ sub setup_vardir() { mtr_verbose("Creating $opt_mem"); mkpath($opt_mem); - mtr_report("Symlinking 'var' to '$opt_mem'"); + mtr_report(" - symlinking 'var' to '$opt_mem'"); symlink($opt_mem, $opt_vardir); } } @@ -2433,33 +1992,23 @@ sub setup_vardir() { mkpath("$opt_vardir/log"); mkpath("$opt_vardir/run"); + + # Create var/tmp and tmp - they might be different mkpath("$opt_vardir/tmp"); - mkpath($opt_tmpdir) if $opt_tmpdir ne "$opt_vardir/tmp"; + mkpath($opt_tmpdir) if ($opt_tmpdir ne "$opt_vardir/tmp"); - if ($master->[0]->{'path_sock'} !~ m/^$opt_tmpdir/) - { - mtr_report("Symlinking $master->[0]->{'path_sock'}"); - symlink($master->[0]->{'path_sock'}, "$opt_tmpdir/master.sock"); + # On some operating systems, there is a limit to the length of a + # UNIX domain socket's path far below PATH_MAX. + # Don't allow that to happen + if (check_socket_path_length("$opt_tmpdir/testsocket.sock")){ + mtr_error("Socket path '$opt_tmpdir' too long, it would be ", + "truncated and thus not possible to use for connection to ", + "MySQL Server. Set a shorter with --tmpdir=<path> option"); } - # 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"); - } + # copy all files from std_data into var/std_data + # and make them world readable + copytree("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data", "0022"); # Remove old log files foreach my $name (glob("r/*.progress r/*.log r/*.warnings")) @@ -2469,9 +2018,11 @@ sub setup_vardir() { } +# +# Check if running as root +# i.e a file can be read regardless what mode we set it to +# 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); @@ -2488,7 +2039,6 @@ sub check_running_as_root () { # 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) { @@ -2499,19 +2049,15 @@ sub check_running_as_root () { chmod(oct("0755"), $test_file); unlink($test_file); - } sub check_ssl_support ($) { my $mysqld_variables= shift; - if ($opt_skip_ssl || $opt_extern) + if ($opt_skip_ssl) { - if (!$opt_extern) - { - mtr_report("Skipping SSL"); - } + mtr_report(" - skipping SSL"); $opt_ssl_supported= 0; $opt_ssl= 0; return; @@ -2524,12 +2070,12 @@ sub check_ssl_support ($) { mtr_error("Couldn't find support for SSL"); return; } - mtr_report("Skipping SSL, mysqld not compiled with SSL"); + 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"); + mtr_report(" - SSL connections supported"); $opt_ssl_supported= 1; } @@ -2539,7 +2085,7 @@ sub check_debug_support ($) { if ( ! $mysqld_variables->{'debug'} ) { - #mtr_report("Binaries are not debug compiled"); + #mtr_report(" - binaries are not debug compiled"); $debug_compiled_binaries= 0; if ( $opt_debug ) @@ -2548,11 +2094,11 @@ sub check_debug_support ($) { } return; } - mtr_report("Binaries are debug compiled"); + 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 @@ -2561,155 +2107,57 @@ sub check_debug_support ($) { # # $exe can be undefined, if the directory itself will be used # -############################################################################### - sub vs_config_dirs ($$) { my ($path_part, $exe) = @_; $exe = "" if not defined $exe; + # Don't look in these dirs when not on windows + return () unless IS_WINDOWS; + if ($opt_vs_config) { - return ("$glob_basedir/$path_part/$opt_vs_config/$exe"); + return ("$basedir/$path_part/$opt_vs_config/$exe"); } - return ("$glob_basedir/$path_part/release/$exe", - "$glob_basedir/$path_part/relwithdebinfo/$exe", - "$glob_basedir/$path_part/debug/$exe"); + return ("$basedir/$path_part/release/$exe", + "$basedir/$path_part/relwithdebinfo/$exe", + "$basedir/$path_part/debug/$exe"); } -############################################################################## -# -# Start the ndb cluster -# -############################################################################## sub check_ndbcluster_support ($) { my $mysqld_variables= shift; - if ($opt_skip_ndbcluster || $opt_extern) + if ($opt_skip_ndbcluster) { - if (!$opt_extern) - { - mtr_report("Skipping ndbcluster"); - } - $opt_skip_ndbcluster_slave= 1; + mtr_report(" - skipping ndbcluster"); return; } - if ( ! $mysqld_variables->{'ndb-connectstring'} ) + if ( ! $mysqld_variables{'ndb-connectstring'} ) { - mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster"); - $opt_skip_ndbcluster= 1; - $opt_skip_ndbcluster_slave= 1; + mtr_report(" - skipping ndbcluster, mysqld not compiled with ndbcluster"); + $opt_skip_ndbcluster= 2; return; } - $glob_ndbcluster_supported= 1; - mtr_report("Using ndbcluster when necessary, mysqld supports it"); - if ( $mysql_version_id < 50100 ) - { - # Slave cluster is not supported until 5.1 - $opt_skip_ndbcluster_slave= 1; - - } + mtr_report(" - using ndbcluster when necessary, mysqld supports it"); return; } -sub ndbcluster_start_install ($) { - my $cluster= shift; - - mtr_report("Installing $cluster->{'name'} Cluster"); - - mkdir($cluster->{'data_dir'}); - - # Create a config file from template - my $ndb_no_ord=512; - my $ndb_no_attr=2048; - my $ndb_con_op=105000; - my $ndb_dmem="80M"; - my $ndb_imem="24M"; - my $ndb_pbmem="32M"; - my $nodes= $cluster->{'nodes'}; - my $ndb_host= "localhost"; - my $ndb_diskless= 0; - - if (!$opt_bench) - { - # Use a smaller configuration - if ( $mysql_version_id < 50100 ) - { - # 4.1 and 5.0 is using a "larger" --small configuration - $ndb_no_ord=128; - $ndb_con_op=10000; - $ndb_dmem="40M"; - $ndb_imem="12M"; - } - else - { - $ndb_no_ord=32; - $ndb_con_op=10000; - $ndb_dmem="20M"; - $ndb_imem="1M"; - $ndb_pbmem="4M"; - } - } - - my $config_file_template= "ndb/ndb_config_${nodes}_node.ini"; - my $config_file= "$cluster->{'data_dir'}/config.ini"; - - open(IN, $config_file_template) - or mtr_error("Can't open $config_file_template: $!"); - open(OUT, ">", $config_file) - or mtr_error("Can't write to $config_file: $!"); - while (<IN>) - { - chomp; - - s/CHOOSE_MaxNoOfAttributes/$ndb_no_attr/; - s/CHOOSE_MaxNoOfOrderedIndexes/$ndb_no_ord/; - s/CHOOSE_MaxNoOfConcurrentOperations/$ndb_con_op/; - s/CHOOSE_DataMemory/$ndb_dmem/; - s/CHOOSE_IndexMemory/$ndb_imem/; - s/CHOOSE_Diskless/$ndb_diskless/; - s/CHOOSE_HOSTNAME_.*/$ndb_host/; - s/CHOOSE_FILESYSTEM/$cluster->{'data_dir'}/; - s/CHOOSE_PORT_MGM/$cluster->{'port'}/; - if ( $mysql_version_id < 50000 ) - { - my $base_port= $cluster->{'port'} + 1; - s/CHOOSE_PORT_TRANSPORTER/$base_port/; - } - s/CHOOSE_DiskPageBufferMemory/$ndb_pbmem/; - - print OUT "$_ \n"; - } - close OUT; - close IN; - - - # Start cluster with "--initial" - - ndbcluster_start($cluster, "--initial"); - - return 0; -} - - sub ndbcluster_wait_started($$){ my $cluster= shift; my $ndb_waiter_extra_opt= shift; - my $path_waiter_log= "$cluster->{'data_dir'}/ndb_waiter.log"; - my $args; + my $path_waitlog= join('/', $opt_vardir, $cluster->name(), "ndb_waiter.log"); + my $args; mtr_init_args(\$args); - - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--core"); - mtr_add_arg($args, "--ndb-connectstring=%s", $cluster->{'connect_string'}); - mtr_add_arg($args, "--timeout=60"); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix()); + mtr_add_arg($args, "--timeout=%d", $opt_start_timeout); if ($ndb_waiter_extra_opt) { @@ -2719,29 +2167,45 @@ sub ndbcluster_wait_started($$){ # Start the ndb_waiter which will connect to the ndb_mgmd # and poll it for state of the ndbd's, will return when # all nodes in the cluster is started - my $res= mtr_run($exe_ndb_waiter, $args, - "", $path_waiter_log, $path_waiter_log, ""); - mtr_verbose("ndbcluster_wait_started, returns: $res") if $res; - return $res; -} - + my $res= My::SafeProcess->run + ( + name => "ndb_waiter ".$cluster->name(), + path => $exe_ndb_waiter, + args => \$args, + output => $path_waitlog, + error => $path_waitlog, + append => 1, + ); + + # Check that ndb_mgmd(s) are still alive + foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) ) + { + my $proc= $ndb_mgmd->{proc}; + if ( ! $proc->wait_one(0) ) + { + mtr_warning("$proc died"); + return 2; + } + } -sub mysqld_wait_started($){ - my $mysqld= shift; + # Check that all started ndbd(s) are still alive + foreach my $ndbd ( in_cluster($cluster, ndbds()) ) + { + my $proc= $ndbd->{proc}; + next unless defined $proc; + if ( ! $proc->wait_one(0) ) + { + mtr_warning("$proc died"); + return 3; + } + } - if (sleep_until_file_created($mysqld->{'path_pid'}, - $mysqld->{'start_timeout'}, - $mysqld->{'pid'}) == 0) + if ($res) { - # Failed to wait for pid file + mtr_verbose("ndbcluster_wait_started failed"); 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; } @@ -2750,267 +2214,252 @@ sub ndb_mgmd_wait_started($) { my ($cluster)= @_; my $retries= 100; - while (ndbcluster_wait_started($cluster, "--no-contact") and - $retries) + while ($retries) { - # Millisceond sleep emulated with select - select(undef, undef, undef, (0.1)); + my $result= ndbcluster_wait_started($cluster, "--no-contact"); + if ($result == 0) + { + # ndb_mgmd is started + mtr_verbose("ndb_mgmd is started"); + return 0; + } + elsif ($result > 1) + { + mtr_warning("Cluster process failed while waiting for start"); + return $result; + } + mtr_milli_sleep(100); $retries--; } - return $retries == 0; - + return 1; } -sub ndb_mgmd_start ($) { - my $cluster= shift; - my $args; # Arg vector - my $pid= -1; +sub ndb_mgmd_start ($$) { + my ($cluster, $ndb_mgmd)= @_; + + mtr_verbose("ndb_mgmd_start"); + my $dir= $ndb_mgmd->value("DataDir"); + mkpath($dir) unless -d $dir; + + my $args; mtr_init_args(\$args); - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix()); + mtr_add_arg($args, "--mycnf"); mtr_add_arg($args, "--nodaemon"); - mtr_add_arg($args, "--config-file=%s", "$cluster->{'data_dir'}/config.ini"); + my $path_ndb_mgmd_log= "$dir/ndb_mgmd.log"; - my $path_ndb_mgmd_log= "$cluster->{'data_dir'}/\l$cluster->{'name'}_ndb_mgmd.log"; - $pid= mtr_spawn($exe_ndb_mgmd, $args, "", - $path_ndb_mgmd_log, - $path_ndb_mgmd_log, - "", - { append_log_file => 1 }); + $ndb_mgmd->{'proc'}= My::SafeProcess->new + ( + name => $ndb_mgmd->after('cluster_config.'), + path => $exe_ndb_mgmd, + args => \$args, + output => $path_ndb_mgmd_log, + error => $path_ndb_mgmd_log, + append => 1, + verbose => $opt_verbose, + ); + mtr_verbose("Started $ndb_mgmd->{proc}"); # FIXME Should not be needed # Unfortunately the cluster nodes will fail to start # if ndb_mgmd has not started properly if (ndb_mgmd_wait_started($cluster)) { - mtr_error("Failed to wait for start of ndb_mgmd"); + mtr_warning("Failed to wait for start of ndb_mgmd"); + return 1; } - # Remember pid of ndb_mgmd - $cluster->{'pid'}= $pid; - - mtr_verbose("ndb_mgmd_start, pid: $pid"); - - return $pid; + return 0; } -sub ndbd_start ($$$) { - my $cluster= shift; - my $idx= shift; - my $extra_args= shift; +sub ndbd_start { + my ($cluster, $ndbd)= @_; + + mtr_verbose("ndbd_start"); - my $args; # Arg vector - my $pid= -1; + my $dir= $ndbd->value("DataDir"); + mkpath($dir) unless -d $dir; + my $args; mtr_init_args(\$args); - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--core"); - mtr_add_arg($args, "--ndb-connectstring=%s", "$cluster->{'connect_string'}"); - if ( $mysql_version_id >= 50000) - { - mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); - } + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix()); mtr_add_arg($args, "--nodaemon"); - mtr_add_arg($args, "$extra_args"); - my $nodeid= $cluster->{'ndbds'}->[$idx]->{'nodeid'}; - my $path_ndbd_log= "$cluster->{'data_dir'}/ndb_${nodeid}.log"; - $pid= mtr_spawn($exe_ndbd, $args, "", - $path_ndbd_log, - $path_ndbd_log, - "", - { append_log_file => 1 }); +# > 5.0 { 'character-sets-dir' => \&fix_charset_dir }, - # Add pid to list of pids for this cluster - $cluster->{'ndbds'}->[$idx]->{'pid'}= $pid; - # Rememeber options used when starting - $cluster->{'ndbds'}->[$idx]->{'start_extra_args'}= $extra_args; - $cluster->{'ndbds'}->[$idx]->{'idx'}= $idx; + my $path_ndbd_log= "$dir/ndbd.log"; + my $proc= My::SafeProcess->new + ( + name => $ndbd->after('cluster_config.'), + path => $exe_ndbd, + args => \$args, + output => $path_ndbd_log, + error => $path_ndbd_log, + append => 1, + verbose => $opt_verbose, + ); + mtr_verbose("Started $proc"); - mtr_verbose("ndbd_start, pid: $pid"); + $ndbd->{proc}= $proc; - return $pid; + return; } -sub ndbcluster_start ($$) { +sub ndbcluster_start ($) { my $cluster= shift; - my $extra_args= shift; - mtr_verbose("ndbcluster_start '$cluster->{'name'}'"); + mtr_verbose("ndbcluster_start '".$cluster->name()."'"); - if ( $cluster->{'use_running'} ) + foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) ) { - return 0; + next if started($ndb_mgmd); + ndb_mgmd_start($cluster, $ndb_mgmd); } - if ( $cluster->{'pid'} ) + foreach my $ndbd ( in_cluster($cluster, ndbds()) ) { - mtr_error("Cluster '$cluster->{'name'}' already started"); - } - - ndb_mgmd_start($cluster); - - for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ ) - { - ndbd_start($cluster, $idx, $extra_args); + next if started($ndbd); + ndbd_start($cluster, $ndbd); } return 0; } -sub rm_ndbcluster_tables ($) { - my $dir= shift; - foreach my $bin ( glob("$dir/mysql/ndb_apply_status*"), - glob("$dir/mysql/ndb_schema*")) - { - unlink($bin); - } -} - - -############################################################################## -# -# Run the benchmark suite -# -############################################################################## +sub create_config_file_for_extern { + my %opts= + ( + socket => '/tmp/mysqld.sock', + port => 3306, + user => $opt_user, + password => '', + @_ + ); -sub run_benchmarks ($) { - my $benchmark= shift; + mtr_report("Creating my.cnf file for extern server..."); + my $F= IO::File->new($path_config_file, "w") + or mtr_error("Can't write to $path_config_file: $!"); - my $args; - - if ( ! $glob_use_embedded_server ) - { - mysqld_start($master->[0],[],[]); - if ( ! $master->[0]->{'pid'} ) - { - mtr_error("Can't start the mysqld server"); - } + print $F "[client]\n"; + while (my ($option, $value)= each( %opts )) { + print $F "$option= $value\n"; + mtr_report(" $option= $value"); } - mtr_init_args(\$args); - - mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); - mtr_add_arg($args, "--user=%s", $opt_user); + print $F <<EOF - if ( $opt_small_bench ) - { - mtr_add_arg($args, "--small-test"); - mtr_add_arg($args, "--small-tables"); - } +# binlog reads from [client] and [mysqlbinlog] +[mysqlbinlog] +character-sets-dir= $path_charsetsdir - if ( $opt_with_ndbcluster ) - { - mtr_add_arg($args, "--create-options=TYPE=ndb"); - } - - chdir($glob_mysql_bench_dir) - or mtr_error("Couldn't chdir to '$glob_mysql_bench_dir': $!"); +# mysql_fix_privilege_tables.sh don't read from [client] +[mysql_fix_privilege_tables] +socket = $opts{'socket'} +port = $opts{'port'} +user = $opts{'user'} +password = $opts{'password'} - 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 +EOF +; - if ( ! $glob_use_embedded_server ) - { - stop_masters(); - } + $F= undef; # Close file } -############################################################################## # -# Run the tests +# Kill processes left from previous runs, normally +# there should be none so make sure to warn +# if there is one # -############################################################################## +sub kill_leftovers ($) { + my $rundir= shift; + return unless ( -d $rundir ); -sub run_tests () { - my ($tests)= @_; + mtr_report("Checking leftover processes..."); - 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 ) + # Scan the "run" directory for process id's to kill + opendir(RUNDIR, $rundir) + or mtr_error("kill_leftovers, can't open dir \"$rundir\": $!"); + while ( my $elem= readdir(RUNDIR) ) { - if (run_testcase_check_skip_test($tinfo)) + # Only read pid from files that end with .pid + if ( $elem =~ /.*[.]pid$/ ) { - next; - } - - mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout); - run_testcase($tinfo); - mtr_timer_stop($glob_timers,"testcase"); - } - - mtr_print_line(); + my $pidfile= "$rundir/$elem"; + next unless -f $pidfile; + my $pid= mtr_fromfile($pidfile); + unlink($pidfile); + unless ($pid=~ /^(\d+)/){ + # The pid was not a valid number + mtr_warning("Got invalid pid '$pid' from '$elem'"); + next; + } + mtr_report(" - found old pid $pid in '$elem', killing it..."); - if ( ! $glob_debugger and - ! $opt_extern and - ! $glob_use_embedded_server ) - { - stop_all_servers(); - } + my $ret= kill("KILL", $pid); + if ($ret == 0) { + mtr_report(" process did not exist!"); + next; + } - if ( $opt_gcov ) - { - gcov_collect(); # collect coverage information - } - if ( $opt_gprof ) - { - gprof_collect(); # collect coverage information + my $check_counter= 100; + while ($ret > 0 and $check_counter--) { + mtr_milli_sleep(100); + $ret= kill(0, $pid); + } + mtr_report($check_counter ? " ok!" : " failed!"); + } + else + { + mtr_warning("Found non pid file '$elem' in '$rundir'") + if -f "$rundir/$elem"; + } } - - mtr_report_stats($tests); - - mtr_timer_stop($glob_timers,"suite"); + closedir(RUNDIR); } - -############################################################################## # -# Initiate the test databases +# Check that all the ports that are going to +# be used are free # -############################################################################## +sub check_ports_free +{ + my @ports_to_check; + for ($baseport..$baseport+9){ + push(@ports_to_check, $_); + } + #mtr_report("Checking ports..."); + # print "@ports_to_check\n"; + foreach my $port (@ports_to_check){ + if (mtr_ping_port($port)){ + mtr_report(" - 'localhost:$port' was not free"); + return 1; # One port was not free + } + } -sub initialize_servers () { + return 0; # All ports free +} - datadir_list_setup(); - if ( $opt_extern ) +sub initialize_servers { + + if ( using_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 @@ -3020,208 +2469,225 @@ sub initialize_servers () { } else { - kill_running_servers(); + # Kill leftovers from previous run + # using any pidfiles found in var/run + kill_leftovers("$opt_vardir/run"); 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(); - } + mysql_install_db(default_mysqld(), "$opt_vardir/install.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'}); - } - - if ( ! $opt_skip_im ) - { - im_prepare_env($instance_manager); - } - - my $cluster_started_ok= 1; # Assume it can be started - - my $cluster= $clusters->[0]; # Master cluster - if ($opt_skip_ndbcluster || - $cluster->{'use_running'} || - $cluster->{executable_setup_failed}) - { - # Don't install master cluster - } - elsif (ndbcluster_start_install($cluster)) - { - mtr_warning("Failed to start install of $cluster->{name}"); - $cluster_started_ok= 0; - } - - $cluster= $clusters->[1]; # Slave cluster - if ($max_slave_num == 0 || - $opt_skip_ndbcluster_slave || - $cluster->{'use_running'} || - $cluster->{executable_setup_failed}) - { - # Don't install slave cluster - } - elsif (ndbcluster_start_install($cluster)) - { - mtr_warning("Failed to start install of $cluster->{name}"); - $cluster_started_ok= 0; - } - foreach $cluster (@{$clusters}) - { - - next if !$cluster->{'pid'}; - - $cluster->{'installed_ok'}= 1; # Assume install suceeds - - if (ndbcluster_wait_started($cluster, "")) - { - # failed to install, disable usage and flag that its no ok - mtr_report("ndbcluster_install of $cluster->{'name'} failed"); - $cluster->{"installed_ok"}= 0; - - $cluster_started_ok= 0; +# +# Remove all newline characters expect after semicolon +# +sub sql_to_bootstrap { + my ($sql) = @_; + my @lines= split(/\n/, $sql); + my $result= "\n"; + my $delimiter= ';'; + + foreach my $line (@lines) { + + # Change current delimiter if line starts with "delimiter" + if ( $line =~ /^delimiter (.*)/ ) { + my $new= $1; + # Remove old delimiter from end of new + $new=~ s/\Q$delimiter\E$//; + $delimiter = $new; + mtr_debug("changed delimiter to $delimiter"); + # No need to add the delimiter to result + next; } - } - if ( ! $cluster_started_ok ) - { - if ( $opt_force) - { - # Continue without cluster + # Add newline if line ends with $delimiter + # and convert the current delimiter to semicolon + if ( $line =~ /\Q$delimiter\E$/ ){ + $line =~ s/\Q$delimiter\E$/;/; + $result.= "$line\n"; + mtr_debug("Added default delimiter"); + next; } - else - { - mtr_error("To continue, re-run with '--force'."); + + # Remove comments starting with -- + if ( $line =~ /^\s*--/ ) { + mtr_debug("Discarded $line"); + next; } - } - return 0; -} + # Replace @HOSTNAME with localhost + $line=~ s/\'\@HOSTNAME\@\'/localhost/; + # Default, just add the line without newline + # but with a space as separator + $result.= "$line "; -sub copy_install_db ($$) { - my $type= shift; - my $data_dir= shift; + } + return $result; +} - mtr_report("Installing \u$type Database"); - # Just copy the installed db from first master - mtr_copy_dir($master->[0]->{'path_myddir'}, $data_dir); +sub default_mysqld { + # Generate new config file from template + my $config= My::ConfigFactory->new_config + ( { + basedir => $basedir, + template_path => "include/default_my.cnf", + vardir => $opt_vardir, + tmpdir => $opt_tmpdir, + baseport => 0, + user => $opt_user, + password => '', + } + ); + my $mysqld= $config->group('mysqld.1') + or mtr_error("Couldn't find mysqld.1 in default config"); + return $mysqld; } -sub install_db ($$) { - my $type= shift; - my $data_dir= shift; +sub mysql_install_db { + my ($mysqld, $datadir)= @_; - mtr_report("Installing \u$type Database"); + my $install_datadir= $datadir || $mysqld->value('datadir'); + my $install_basedir= $mysqld->value('basedir'); + my $install_lang= $mysqld->value('language'); + my $install_chsdir= $mysqld->value('character-sets-dir'); + mtr_report("Installing system database..."); my $args; mtr_init_args(\$args); mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--bootstrap"); - mtr_add_arg($args, "--basedir=%s", $path_my_basedir); - mtr_add_arg($args, "--datadir=%s", $data_dir); + mtr_add_arg($args, "--basedir=%s", $install_basedir); + mtr_add_arg($args, "--datadir=%s", $install_datadir); mtr_add_arg($args, "--loose-skip-innodb"); + mtr_add_arg($args, "--loose-skip-falcon"); mtr_add_arg($args, "--loose-skip-ndbcluster"); - mtr_add_arg($args, "--tmpdir=."); + mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/"); mtr_add_arg($args, "--core-file"); 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, "--debug=d:t:i:A,%s/log/bootstrap.trace", + $path_vardir_trace); } - if ( ! $glob_netware ) - { - mtr_add_arg($args, "--language=%s", $path_language); - mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); - } + mtr_add_arg($args, "--language=%s", $install_lang); + mtr_add_arg($args, "--character-sets-dir=%s", $install_chsdir); # 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; + my $exe_mysqld_bootstrap = + $ENV{'MYSQLD_BOOTSTRAP'} || find_mysqld($install_basedir); # ---------------------------------------------------------------------- # export MYSQLD_BOOTSTRAP_CMD variable containing <path>/mysqld <args> # ---------------------------------------------------------------------- $ENV{'MYSQLD_BOOTSTRAP_CMD'}= "$exe_mysqld_bootstrap " . join(" ", @$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"); + my $path_sql= my_find_file($install_basedir, + ["mysql", "sql/share", "share/mysql", + "share", "scripts"], + "mysql_system_tables.sql", + NOT_REQUIRED); - # Add the offical mysql system tables - # for a production system - mtr_appendfile_to_file("$path_sql_dir/mysql_system_tables.sql", - $bootstrap_sql_file); + if (-f $path_sql ) + { + my $sql_dir= dirname($path_sql); + # Use the mysql database for system tables + mtr_tofile($bootstrap_sql_file, "use mysql\n"); - # 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 the offical mysql system tables + # for a production system + mtr_appendfile_to_file("$sql_dir/mysql_system_tables.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); + # Add the mysql system tables initial data + # for a production system + mtr_appendfile_to_file("$sql_dir/mysql_system_tables_data.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); + # 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("$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("$sql_dir/fill_help_tables.sql", + $bootstrap_sql_file); + + } + else + { + # Install db from init_db.sql that exist in early 5.1 and 5.0 + # versions of MySQL + my $init_file= "$install_basedir/mysql-test/lib/init_db.sql"; + mtr_report(" - from '$init_file'"); + my $text= mtr_grab_file($init_file) or + mtr_error("Can't open '$init_file': $!"); + + mtr_tofile($bootstrap_sql_file, + sql_to_bootstrap($text)); + } # Remove anonymous users mtr_tofile($bootstrap_sql_file, - "DELETE FROM mysql.user where user= '';"); + "DELETE FROM mysql.user where user= '';\n"); + + # Create mtr database + mtr_tofile($bootstrap_sql_file, + "CREATE DATABASE mtr;\n"); + + # Add help tables and data for warning detection and supression + mtr_tofile($bootstrap_sql_file, + sql_to_bootstrap(mtr_grab_file("include/mtr_warnings.sql"))); + + # Add procedures for checking server is restored after testcase + mtr_tofile($bootstrap_sql_file, + sql_to_bootstrap(mtr_grab_file("include/mtr_check.sql"))); # 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 ) - + # Create directories mysql and test + mkpath("$install_datadir/mysql"); + mkpath("$install_datadir/test"); + + if ( My::SafeProcess->run + ( + name => "bootstrap", + path => $exe_mysqld_bootstrap, + args => \$args, + input => $bootstrap_sql_file, + output => $path_bootstrap_log, + error => $path_bootstrap_log, + append => 1, + verbose => $opt_verbose, + ) != 0) { mtr_error("Error executing mysqld --bootstrap\n" . "Could not install system database from $bootstrap_sql_file\n" . @@ -3230,284 +2696,327 @@ sub install_db ($$) { } -sub im_prepare_env($) { - my $instance_manager = shift; +sub run_testcase_check_skip_test($) +{ + my ($tinfo)= @_; - im_create_passwd_file($instance_manager); - im_prepare_data_dir($instance_manager); -} + # ---------------------------------------------------------------------- + # 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_skipped($tinfo); + return 1; + } -sub im_create_passwd_file($) { - my $instance_manager = shift; + return 0; +} - my $pwd_file_path = $instance_manager->{'password_file'}; - mtr_report("Creating IM password file ($pwd_file_path)"); +sub run_query { + my ($tinfo, $mysqld, $query)= @_; - open(OUT, ">", $pwd_file_path) - or mtr_error("Can't write to $pwd_file_path: $!"); + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld')); - print OUT $instance_manager->{'admin_login'}, ":", - $instance_manager->{'admin_sha1'}, "\n"; + mtr_add_arg($args, "-e %s", $query); - close(OUT); -} + my $res= My::SafeProcess->run + ( + name => "run_query -> ".$mysqld->name(), + path => $exe_mysql, + args => \$args, + output => '/dev/null', + error => '/dev/null' + ); + return $res +} -sub im_create_defaults_file($) { - my $instance_manager = shift; - my $defaults_file = $instance_manager->{'defaults_file'}; +sub do_before_run_mysqltest($) +{ + my $tinfo= shift; - open(OUT, ">", $defaults_file) - or mtr_error("Can't write to $defaults_file: $!"); + # Remove old files produced by mysqltest + my $base_file= mtr_match_extension($tinfo->{result_file}, + "result"); # Trim extension + if (defined $base_file ){ + unlink("$base_file.reject"); + unlink("$base_file.progress"); + unlink("$base_file.log"); + unlink("$base_file.warnings"); + } + + if ( $mysql_version_id < 50000 ) { + # Set environment variable NDB_STATUS_OK to 1 + # if script decided to run mysqltest cluster _is_ installed ok + $ENV{'NDB_STATUS_OK'} = "1"; + } elsif ( $mysql_version_id < 50100 ) { + # Set environment variable NDB_STATUS_OK to YES + # if script decided to run mysqltest cluster _is_ installed ok + $ENV{'NDB_STATUS_OK'} = "YES"; + } +} - print OUT <<EOF -[mysql] -[manager] -pid-file = $instance_manager->{path_pid} -angel-pid-file = $instance_manager->{path_angel_pid} -socket = $instance_manager->{path_sock} -port = $instance_manager->{port} -password-file = $instance_manager->{password_file} -default-mysqld-path = $exe_mysqld +# +# Check all server for sideffects +# +# RETURN VALUE +# 0 ok +# 1 Check failed +# >1 Fatal errro -EOF -; +sub check_testcase($$) +{ + my ($tinfo, $mode)= @_; + my $tname= $tinfo->{name}; - foreach my $instance (@{$instance_manager->{'instances'}}) - { - my $server_id = $instance->{'server_id'}; - - print OUT <<EOF -[mysqld$server_id] -socket = $instance->{path_sock} -pid-file = $instance->{path_pid} -port = $instance->{port} -datadir = $instance->{path_datadir} -log = $instance->{path_datadir}/mysqld$server_id.log -log-error = $instance->{path_datadir}/mysqld$server_id.err.log -log-slow-queries = $instance->{path_datadir}/mysqld$server_id.slow.log -language = $path_language -character-sets-dir = $path_charsetsdir -basedir = $path_my_basedir -server_id = $server_id -shutdown-delay = 10 -skip-stack-trace -loose-skip-innodb -loose-skip-ndbcluster -EOF -; - if ( $mysql_version_id < 50100 ) - { - print OUT "skip-bdb\n"; - } - print OUT "nonguarded\n" if $instance->{'nonguarded'}; - if ( $mysql_version_id >= 50100 ) + # Start the mysqltest processes in parallel to save time + # also makes it possible to wait for any process to exit during the check + my %started; + foreach my $mysqld ( mysqlds() ) + { + if ( defined $mysqld->{'proc'} ) { - print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; + my $proc= start_check_testcase($tinfo, $mode, $mysqld); + $started{$proc->pid()}= $proc; } - print OUT "\n"; } - close(OUT); -} + # Return immediately if no check proceess was started + return 0 unless ( keys %started ); + my $timeout_proc= My::SafeProcess->timer(check_timeout()); -sub im_prepare_data_dir($) { - my $instance_manager = shift; + while (1){ + my $result; + my $proc= My::SafeProcess->wait_any(); + mtr_report("Got $proc"); - foreach my $instance (@{$instance_manager->{'instances'}}) - { - copy_install_db( - 'im_mysqld_' . $instance->{'server_id'}, - $instance->{'path_datadir'}); - } -} + if ( delete $started{$proc->pid()} ) { + my $err_file= $proc->user_data(); + my $base_file= mtr_match_extension($err_file, "err"); # Trim extension + # One check testcase process returned + my $res= $proc->exit_status(); -# -# Restore snapshot of the installed slave databases -# if the snapshot exists -# -sub restore_slave_databases ($) { - my ($num_slaves)= @_; + if ( $res == 0){ + # Check completed without problem - 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); - } - } -} + # Remove the .err file the check generated + unlink($err_file); + # Remove the .result file the check generated + if ( $mode eq 'after' ){ + unlink("$base_file.result"); + } -sub run_testcase_check_skip_test($) -{ - my ($tinfo)= @_; + if ( keys(%started) == 0){ + # All checks completed - # ---------------------------------------------------------------------- - # 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; - } + $timeout_proc->kill(); - if ($tinfo->{'ndb_test'}) - { - foreach my $cluster (@{$clusters}) - { - # Slave cluster is skipped and thus not - # installed, no need to perform checks - last if ($opt_skip_ndbcluster_slave and - $cluster->{'name'} eq 'Slave'); - - # Using running cluster - no need - # to check if test should be skipped - # will be done by test itself - last if ($cluster->{'use_running'}); - - # If test needs this cluster, check binaries was found ok - if ( $cluster->{'executable_setup_failed'} ) - { - mtr_report_test_name($tinfo); - $tinfo->{comment}= - "Failed to find cluster binaries"; - mtr_report_test_failed($tinfo); - return 1; + return 0; + } + # Wait for next process to exit + next; } - - # If test needs this cluster, check it was installed ok - if ( !$cluster->{'installed_ok'} ) + else { - mtr_report_test_name($tinfo); - $tinfo->{comment}= - "Cluster $cluster->{'name'} was not installed ok"; - mtr_report_test_failed($tinfo); - return 1; - } + if ( $mode eq "after" and $res == 1 ) + { + # Test failed, grab the report mysqltest has created + my $report= mtr_grab_file($err_file); + $tinfo->{check}.= + "\nMTR's internal check of the test case '$tname' failed. +This means that the test case does not preserve the state that existed +before the test case was executed. Most likely the test case did not +do a proper clean-up. +This is the diff of the states of the servers before and after the +test case was executed:\n"; + $tinfo->{check}.= $report; - } - } + # Check failed, mark the test case with that info + $tinfo->{'check_testcase_failed'}= 1; + $result= 1; + } + elsif ( $res ) + { + my $report= mtr_grab_file($err_file); + $tinfo->{comment}.= + "Could not execute 'check-testcase' $mode ". + "testcase '$tname' (res: $res):\n"; + $tinfo->{comment}.= $report; - if ( $tinfo->{'component_id'} eq 'im' ) - { - # If test needs im, check binaries was found ok - if ( $instance_manager->{'executable_setup_failed'} ) - { - mtr_report_test_name($tinfo); + $result= 2; + } + + # Remove the .err file the check generated + unlink($err_file); + + # Remove the .result file the check generated + unlink("$base_file.result"); + + } + } + elsif ( $proc eq $timeout_proc ) { + $tinfo->{comment}.= "Timeout $timeout_proc for ". + "'check-testcase' expired after ".check_timeout(). + " seconds"; + $result= 4; + } + else { + # Unknown process returned, most likley a crash, abort everything $tinfo->{comment}= - "Failed to find MySQL manager binaries"; - mtr_report_test_failed($tinfo); - return 1; + "The server $proc crashed while running ". + "'check testcase $mode test'"; + $result= 3; } + + # Kill any check processes still running + map($_->kill(), values(%started)); + + $timeout_proc->kill(); + + return $result; } - return 0; + mtr_error("INTERNAL_ERROR: check_testcase"); } -sub do_before_run_mysqltest($) -{ - my $tinfo= shift; +# Start run mysqltest on one server +# +# RETURN VALUE +# 0 OK +# 1 Check failed +# +sub start_run_one ($$) { + my ($mysqld, $run)= @_; + + my $name= "$run-".$mysqld->name(); + my $args; + mtr_init_args(\$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 ( $mysql_version_id < 50000 ) { - # Set environment variable NDB_STATUS_OK to 1 - # if script decided to run mysqltest cluster _is_ installed ok - $ENV{'NDB_STATUS_OK'} = "1"; - } elsif ( $mysql_version_id < 50100 ) { - # Set environment variable NDB_STATUS_OK to YES - # if script decided to run mysqltest cluster _is_ installed ok - $ENV{'NDB_STATUS_OK'} = "YES"; - } - 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_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld')); - 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'}"); + mtr_add_arg($args, "--silent"); + mtr_add_arg($args, "--skip-safemalloc"); + mtr_add_arg($args, "--test-file=%s", "include/$run.test"); + + my $errfile= "$opt_vardir/tmp/$name.err"; + my $proc= My::SafeProcess->new + ( + name => $name, + path => $exe_mysqltest, + error => $errfile, + output => $errfile, + args => \$args, + user_data => $errfile, + verbose => $opt_verbose, + ); + mtr_verbose("Started $proc"); + return $proc; +} - 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"); - } - } + +# +# Run script on all servers, collect results +# +# RETURN VALUE +# 0 ok +# 1 Failure + +sub run_on_all($$) +{ + my ($tinfo, $run)= @_; + + # Start the mysqltest processes in parallel to save time + # also makes it possible to wait for any process to exit during the check + # and to have a timeout process + my %started; + foreach my $mysqld ( mysqlds() ) + { + if ( defined $mysqld->{'proc'} ) + { + my $proc= start_run_one($mysqld, $run); + $started{$proc->pid()}= $proc; } } -} -sub do_after_run_mysqltest($) -{ - my $tinfo= shift; + # Return immediately if no check proceess was started + return 0 unless ( keys %started ); - # 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; -} + my $timeout_proc= My::SafeProcess->timer(check_timeout()); + while (1){ + my $result; + my $proc= My::SafeProcess->wait_any(); + mtr_report("Got $proc"); -sub run_testcase_mark_logs($$) -{ - my ($tinfo, $log_msg)= @_; + if ( delete $started{$proc->pid()} ) { - # Write a marker to all log files + # One mysqltest process returned + my $err_file= $proc->user_data(); + my $res= $proc->exit_status(); - # The file indicating current test name - mtr_tonewfile($path_current_test_log, $log_msg); + # Append the report from .err file + $tinfo->{comment}.= " == $err_file ==\n"; + $tinfo->{comment}.= mtr_grab_file($err_file); + $tinfo->{comment}.= "\n"; - # each mysqld's .err file - foreach my $mysqld (@{$master}, @{$slave}) - { - mtr_tofile($mysqld->{path_myerr}, $log_msg); - } + # Remove the .err file + unlink($err_file); - if ( $tinfo->{'component_id'} eq 'im') - { - mtr_tofile($instance_manager->{path_err}, $log_msg); - mtr_tofile($instance_manager->{path_log}, $log_msg); + if ( keys(%started) == 0){ + # All completed + $timeout_proc->kill(); + return 0; + } + + # Wait for next process to exit + next; + } + elsif ( $proc eq $timeout_proc ) { + $tinfo->{comment}.= "Timeout $timeout_proc for '$run' ". + "expired after ". check_timeout(). + " seconds"; + } + else { + # Unknown process returned, most likley a crash, abort everything + $tinfo->{comment}.= + "The server $proc crashed while running '$run'"; + } + + # Kill any check processes still running + map($_->kill(), values(%started)); + + $timeout_proc->kill(); + + return 1; } + mtr_error("INTERNAL_ERROR: run_on_all"); +} - # ndbcluster log file - mtr_tofile($path_ndb_testrun_log, $log_msg); +sub mark_log { + my ($log, $tinfo)= @_; + my $log_msg= "CURRENT_TEST: $tinfo->{name}\n"; + mtr_tofile($log, $log_msg); } + sub find_testcase_skipped_reason($) { my ($tinfo)= @_; @@ -3515,8 +3024,8 @@ sub find_testcase_skipped_reason($) # 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) + # Open the test log file + my $F= IO::File->new($path_current_testlog) or return; my $reason; @@ -3531,573 +3040,893 @@ sub find_testcase_skipped_reason($) if ( ! $reason ) { - mtr_warning("Could not find reason for skipping test in $path_timefile"); + mtr_warning("Could not find reason for skipping test in $path_current_testlog"); $reason= "Detected by testcase(reason unknown) "; } $tinfo->{'comment'}= $reason; } -############################################################################## -# -# Run a single test case -# -############################################################################## +sub find_analyze_request +{ + # Open the test log file + my $F= IO::File->new($path_current_testlog) + or return; + my $analyze; -# 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. + while ( my $line= <$F> ) + { + # Look for "reason: <reason for skipping test>" + if ( $line =~ /analyze: (.*)/ ) + { + $analyze= $1; + } + } + + return $analyze; +} -# 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. + +# Return timezone value of tinfo or default value +sub timezone { + my ($tinfo)= @_; + return $tinfo->{timezone} || "GMT-3"; +} + + +# Storage for changed environment variables +my %old_env; + +# +# Run a single test case +# +# RETURN VALUE +# 0 OK +# > 0 failure +# sub run_testcase ($) { my $tinfo= shift; + mtr_verbose("Running test:", $tinfo->{name}); + # ------------------------------------------------------- # Init variables that can change between each test case # ------------------------------------------------------- + my $timezone= timezone($tinfo); + $ENV{'TZ'}= $timezone; + mtr_verbose("Setting timezone: $timezone"); - $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) + if ( ! using_extern() ) { - # 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; + my @restart= servers_need_restart($tinfo); + if ( @restart != 0) { + stop_servers($tinfo, @restart ); } - run_testcase_stop_servers($tinfo, $master_restart, $slave_restart); - } + if ( started(all_servers()) == 0 ) + { - # Write to all log files to indicate start of testcase - run_testcase_mark_logs($tinfo, "CURRENT_TEST: $tinfo->{name}\n"); + # Remove old datadirs + clean_datadir(); - my $died= mtr_record_dead_children(); - if ($died or $master_restart or $slave_restart) - { - if (run_testcase_start_servers($tinfo)) + # Restore old ENV + while (my ($option, $value)= each( %old_env )) { + if (defined $value){ + mtr_verbose("Restoring $option to $value"); + $ENV{$option}= $value; + + } else { + mtr_verbose("Removing $option"); + delete($ENV{$option}); + } + } + %old_env= (); + + mtr_verbose("Generating my.cnf from '$tinfo->{template_path}'"); + + # Generate new config file from template + $config= My::ConfigFactory->new_config + ( { + basedir => $basedir, + template_path => $tinfo->{template_path}, + extra_template_path => $tinfo->{extra_template_path}, + vardir => $opt_vardir, + tmpdir => $opt_tmpdir, + baseport => $baseport, + #hosts => [ 'host1', 'host2' ], + user => $opt_user, + password => '', + ssl => $opt_ssl_supported, + embedded => $opt_embedded_server, + } + ); + + # Write the new my.cnf + $config->save($path_config_file); + + # Remember current config so a restart can occur when a test need + # to use a different one + $current_config_name= $tinfo->{template_path}; + + # + # Set variables in the ENV section + # + foreach my $option ($config->options_in_group("ENV")) + { + # Save old value to restore it before next time + $old_env{$option->name()}= $ENV{$option->name()}; + + mtr_verbose($option->name(), "=",$option->value()); + $ENV{$option->name()}= $option->value(); + } + } + + # Write start of testcase to log + mark_log($path_current_testlog, $tinfo); + + if (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 + # -------------------------------------------------------------------- + # If --start or --start-dirty given, stop here to let user manually # run tests # ---------------------------------------------------------------------- - if ( $opt_start_and_exit or $opt_start_dirty ) + if ( $opt_start 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 + mtr_print("\nStarted", started(all_servers())); + mtr_print("Waiting for server(s) to exit..."); + my $proc= My::SafeProcess->wait_any(); + if ( grep($proc eq $_, started(all_servers())) ) { - exit(0); + mtr_print("Server $proc died"); + exit(1); } + mtr_print("Unknown process $proc died"); + exit(1); } - { - do_before_run_mysqltest($tinfo); + my $test_timeout_proc= My::SafeProcess->timer(testcase_timeout()); - my $res= run_mysqltest($tinfo); - mtr_report_test_name($tinfo); + do_before_run_mysqltest($tinfo); - do_after_run_mysqltest($tinfo); + if ( $opt_check_testcases and check_testcase($tinfo, "before") ){ + # Failed to record state of server or server crashed + report_failure_and_restart($tinfo); - if ( $res == 0 ) + # Stop the test case timer + $test_timeout_proc->kill(); + + return 1; + } + + my $test= start_mysqltest($tinfo); + + while (1) + { + my $proc= My::SafeProcess->wait_any(); + unless ( defined $proc ) { - mtr_report_test_passed($tinfo); + mtr_error("wait_any failed"); } - elsif ( $res == 62 ) + mtr_verbose("Got $proc"); + + # ---------------------------------------------------- + # Was it the test program that exited + # ---------------------------------------------------- + if ($proc eq $test) { - # Testcase itself tell us to skip this one + # Stop the test case timer + $test_timeout_proc->kill(); + + my $res= $test->exit_status(); + + if ($res == 0 and $opt_warnings and check_warnings($tinfo) ) + { + # Test case suceeded, but it has produced unexpected + # warnings, continue in $res == 1 + $res= 1; + } + + if ( $res == 0 ) + { + my $check_res; + if ( $opt_check_testcases and + $check_res= check_testcase($tinfo, "after")) + { + if ($check_res == 1) { + # Test case had sideeffects, not fatal error, just continue + stop_all_servers(); + mtr_report("Resuming tests...\n"); + } + else { + # Test case check failed fatally, probably a server crashed + report_failure_and_restart($tinfo); + return 1; + } + } + mtr_report_test_passed($tinfo); + } + elsif ( $res == 62 ) + { + # Testcase itself tell us to skip this one + $tinfo->{skip_detected_by_test}= 1; + # Try to get reason from test log file + find_testcase_skipped_reason($tinfo); + mtr_report_test_skipped($tinfo); + } + elsif ( $res == 65 ) + { + # Testprogram killed by signal + $tinfo->{comment}= + "testprogram crashed(returned code $res)"; + report_failure_and_restart($tinfo); + } + elsif ( $res == 1 ) + { + # Check if the test tool requests that + # an analyze script should be run + my $analyze= find_analyze_request(); + if ($analyze){ + run_on_all($tinfo, "analyze-$analyze"); + } + + # Test case failure reported by mysqltest + report_failure_and_restart($tinfo); + } + else + { + # mysqltest failed, probably crashed + $tinfo->{comment}= + "mysqltest failed with unexpected return code $res"; + report_failure_and_restart($tinfo); + } + + # Save info from this testcase run to mysqltest.log + if( -f $path_current_testlog) + { + mtr_appendfile_to_file($path_current_testlog, $path_testlog); + unlink($path_current_testlog); + } + + return ($res == 62) ? 0 : $res; - # Try to get reason from mysqltest.log - find_testcase_skipped_reason($tinfo); - mtr_report_test_skipped($tinfo); } - elsif ( $res == 63 ) + + # ---------------------------------------------------- + # Check if it was an expected crash + # ---------------------------------------------------- + if ( check_expected_crash_and_restart($proc) ) { - $tinfo->{'timeout'}= 1; # Mark as timeout - report_failure_and_restart($tinfo); + next; } - elsif ( $res == 1 ) + + # ---------------------------------------------------- + # Stop the test case timer + # ---------------------------------------------------- + $test_timeout_proc->kill(); + + # ---------------------------------------------------- + # Check if it was a server that died + # ---------------------------------------------------- + if ( grep($proc eq $_, started(all_servers())) ) { - # Test case failure reported by mysqltest + # Server failed, probably crashed + $tinfo->{comment}= + "Server $proc failed during test run"; + + # ---------------------------------------------------- + # It's not mysqltest that has exited, kill it + # ---------------------------------------------------- + $test->kill(); + report_failure_and_restart($tinfo); + return 1; } - else + + # Try to dump core for mysqltest and all servers + foreach my $proc ($test, started(all_servers())) + { + mtr_print("Trying to dump core for $proc"); + if ($proc->dump_core()) + { + $proc->wait_one(20); + } + } + + # ---------------------------------------------------- + # It's not mysqltest that has exited, kill it + # ---------------------------------------------------- + $test->kill(); + + # ---------------------------------------------------- + # Check if testcase timer expired + # ---------------------------------------------------- + if ( $proc eq $test_timeout_proc ) { - # mysqltest failed, probably crashed + my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log"; $tinfo->{comment}= - "mysqltest returned unexpected code $res, it has probably crashed"; + "Test case timeout after ".testcase_timeout(). + " seconds\n\n"; + # Add 20 last executed commands from test case log file + if (-e $log_file_name) + { + $tinfo->{comment}.= + "== $log_file_name == \n". + mtr_lastlinesfromfile($log_file_name, 20)."\n"; + } + $tinfo->{'timeout'}= testcase_timeout(); # Mark as timeout + run_on_all($tinfo, 'analyze-timeout'); + report_failure_and_restart($tinfo); + return 1; } - } - - # Remove the file that mysqltest writes info to - unlink($path_timefile); - # ---------------------------------------------------------------------- - # Stop Instance Manager if we are processing an IM-test case. - # ---------------------------------------------------------------------- - if ( $tinfo->{'component_id'} eq 'im' and - !mtr_im_stop($instance_manager, $tinfo->{'name'})) - { - mtr_error("Failed to stop Instance Manager.") + mtr_error("Unhandled process $proc exited"); } + mtr_error("Should never come here"); } # -# Save a snapshot of the installed test db(s) -# I.e take a snapshot of the var/ dir +# Perform a rough examination of the servers +# error log and write all lines that look +# suspicious into $error_log.warnings # -sub save_installed_db () { +sub extract_warning_lines ($) { + my ($error_log) = @_; + + # Open the servers .err log file and read all lines + # belonging to current tets into @lines + my $Ferr = IO::File->new($error_log) + or mtr_error("Could not open file '$error_log' for reading: $!"); - mtr_report("Saving snapshot of installed databases"); - mtr_rmtree($path_snapshot); + my @lines; + while ( my $line = <$Ferr> ) + { + if ( $line =~ /^CURRENT_TEST:/ ) + { + # Throw away lines from previous tests + @lines = (); + } + push(@lines, $line); + } + $Ferr = undef; # Close error log file - foreach my $data_dir (@data_dir_lst) + # mysql_client_test.test sends a COM_DEBUG packet to the server + # to provoke a SAFEMALLOC leak report, ignore any warnings + # between "Begin/end safemalloc memory dump" + if ( grep(/Begin safemalloc memory dump:/, @lines) > 0) { - my $name= basename($data_dir); - mtr_copy_dir("$data_dir", "$path_snapshot/$name"); + my $discard_lines= 1; + foreach my $line ( @lines ) + { + if ($line =~ /Begin safemalloc memory dump:/){ + $discard_lines = 1; + } elsif ($line =~ /End safemalloc memory dump./){ + $discard_lines = 0; + } + + if ($discard_lines){ + $line = "ignored"; + } + } + } + + # Write all suspicious lines to $error_log.warnings file + my $warning_log = "$error_log.warnings"; + my $Fwarn = IO::File->new($warning_log, "w") + or die("Could not open file '$warning_log' for writing: $!"); + print $Fwarn "Suspicious lines from $error_log\n"; + + my @patterns = + ( + # The patterns for detection of [Warning] and [ERROR] + # in the server log files have been faulty for a longer period + # and correcting them shows a few additional harmless warnings. + # Thus those patterns are temporarily removed from the list + # of patterns. For more info see BUG#42408 + # qr/^Warning:|mysqld: Warning|\[Warning\]/, + # qr/^Error:|\[ERROR\]/, + qr/^Warning:|mysqld: Warning/, + qr/^Error:/, + qr/^==.* at 0x/, + qr/InnoDB: Warning|InnoDB: Error/, + qr/^safe_mutex:|allocated at line/, + qr/missing DBUG_RETURN/, + qr/Attempting backtrace/, + qr/Assertion .* failed/, + ); + + foreach my $line ( @lines ) + { + foreach my $pat ( @patterns ) + { + if ( $line =~ /$pat/ ) + { + print $Fwarn $line; + last; + } + } } + $Fwarn = undef; # Close file + } +# Run include/check-warnings.test # -# Save any interesting files in the data_dir -# before the data dir is removed. +# RETURN VALUE +# 0 OK +# 1 Check failed # -sub save_files_before_restore($$) { - my $test_name= shift; - my $data_dir= shift; - my $save_name= "$opt_vardir/log/$test_name"; +sub start_check_warnings ($$) { + my $tinfo= shift; + my $mysqld= shift; + + my $name= "warnings-".$mysqld->name(); + + extract_warning_lines($mysqld->value('log-error')); + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld')); + + mtr_add_arg($args, "--skip-safemalloc"); + mtr_add_arg($args, "--test-file=%s", "include/check-warnings.test"); - # Look for core files - foreach my $core_file ( glob("$data_dir/core*") ) + if ( $opt_embedded_server ) { - 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; - } + + # Get the args needed for the embedded server + # and append them to args prefixed + # with --sever-arg= + + my $mysqld= $config->group('embedded') + or mtr_error("Could not get [embedded] section"); + + my $mysqld_args; + mtr_init_args(\$mysqld_args); + my $extra_opts= get_extra_opts($mysqld, $tinfo); + mysqld_arguments($mysqld_args, $mysqld, $extra_opts); + mtr_add_arg($args, "--server-arg=%s", $_) for @$mysqld_args; + } + + my $errfile= "$opt_vardir/tmp/$name.err"; + my $proc= My::SafeProcess->new + ( + name => $name, + path => $exe_mysqltest, + error => $errfile, + output => $errfile, + args => \$args, + user_data => $errfile, + verbose => $opt_verbose, + ); + mtr_verbose("Started $proc"); + return $proc; } # -# Restore snapshot of the installed test db(s) -# if the snapshot exists +# Loop through our list of processes and check the error log +# for unexepcted errors and warnings # -sub restore_installed_db ($) { - my $test_name= shift; +sub check_warnings ($) { + my ($tinfo)= @_; + my $res= 0; - if ( -d $path_snapshot) - { - mtr_report("Restoring snapshot of databases"); + my $tname= $tinfo->{name}; - 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"); - } + # Clear previous warnings + delete($tinfo->{warnings}); - # Remove the ndb_*_fs dirs for all ndbd nodes - # forcing a clean start of ndb - foreach my $cluster (@{$clusters}) + # Start the mysqltest processes in parallel to save time + # also makes it possible to wait for any process to exit during the check + my %started; + foreach my $mysqld ( mysqlds() ) + { + if ( defined $mysqld->{'proc'} ) { - foreach my $ndbd (@{$cluster->{'ndbds'}}) - { - mtr_rmtree("$ndbd->{'path_fs'}" ); - } + my $proc= start_check_warnings($tinfo, $mysqld); + $started{$proc->pid()}= $proc; } } - else - { - # No snapshot existed - mtr_error("No snapshot existed"); - } -} -sub report_failure_and_restart ($) { - my $tinfo= shift; + # Return immediately if no check proceess was started + return 0 unless ( keys %started ); - mtr_report_test_failed($tinfo); - print "\n"; - if ( $opt_force ) - { - # Stop all servers that are known to be running - stop_all_servers(); + my $timeout_proc= My::SafeProcess->timer(check_timeout()); - # Restore the snapshot of the installed test db - restore_installed_db($tinfo->{'name'}); - mtr_report("Resuming Tests\n"); - return; - } + while (1){ + my $result= 0; + my $proc= My::SafeProcess->wait_any(); + mtr_report("Got $proc"); - 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); + if ( delete $started{$proc->pid()} ) { + # One check warning process returned + my $res= $proc->exit_status(); + my $err_file= $proc->user_data(); -} + if ( $res == 0 or $res == 62 ){ + if ( $res == 0 ) { + # Check completed with problem + my $report= mtr_grab_file($err_file); + # Log to var/log/warnings file + mtr_tofile("$opt_vardir/log/warnings", + $tname."\n".$report); -sub run_master_init_script ($) { - my ($tinfo)= @_; - my $init_script= $tinfo->{'master_sh'}; + $tinfo->{'warnings'}.= $report; + $result= 1; + } - # 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"); + if ( $res == 62 ) { + # Test case was ok and called "skip" + ; + } + # Remove the .err file the check generated + unlink($err_file); + + if ( keys(%started) == 0){ + # All checks completed + + $timeout_proc->kill(); + + return $result; + } + # Wait for next process to exit + next; + } + else + { + my $report= mtr_grab_file($err_file); + $tinfo->{comment}.= + "Could not execute 'check-warnings' for ". + "testcase '$tname' (res: $res):\n"; + $tinfo->{comment}.= $report; + + $result= 2; + } + # Remove the .err file the check generated + unlink($err_file); + } + elsif ( $proc eq $timeout_proc ) { + $tinfo->{comment}.= "Timeout $timeout_proc for ". + "'check warnings' expired after ".check_timeout(). + " seconds"; + $result= 4; + } + else { + # Unknown process returned, most likley a crash, abort everything + $tinfo->{comment}= + "The server $proc crashed while running 'check warnings'"; + $result= 3; } + + # Kill any check processes still running + map($_->kill(), values(%started)); + + $timeout_proc->kill(); + + return $result; } + + mtr_error("INTERNAL_ERROR: check_warnings"); } -############################################################################## # -# Start and stop servers +# Loop through our list of processes and look for and entry +# with the provided pid, if found check for the file indicating +# expected crash and restart it. # -############################################################################## +sub check_expected_crash_and_restart { + my ($proc)= @_; + foreach my $mysqld ( mysqlds() ) + { + next unless ( $mysqld->{proc} eq $proc ); -sub do_before_start_master ($) { - my ($tinfo)= @_; + # Check if crash expected by looking at the .expect file + # in var/tmp + my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file '$expect_file' exists"); + + while (1){ - my $tname= $tinfo->{'name'}; + # If last line in expect file starts with "wait" + # sleep a little and try again, thus allowing the + # test script to control when the server should start + # up again + my $last_line= mtr_lastlinesfromfile($expect_file, 1); + if ($last_line =~ /^wait/ ) + { + mtr_verbose("Test says wait before restart"); + mtr_milli_sleep(100); + next; + } - # FIXME what about second master..... + unlink($expect_file); - # Don't delete anything if starting dirty - return if ($opt_start_dirty); + # Start server with same settings as last time + mysqld_start($mysqld, $mysqld->{'started_opts'}); - foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) - { - unlink($bin); + last; + } + } + + return 1; } - # 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"); + # Not an expected crash + return 0; +} + - run_master_init_script($tinfo); +# Remove all files and subdirectories of a directory +sub clean_dir { + my ($dir)= @_; + mtr_verbose("clean_dir: $dir"); + finddepth( + { no_chdir => 1, + wanted => sub { + if (-d $_){ + # A dir + if ($_ eq $dir){ + # The dir to clean + return; + } else { + mtr_verbose("rmdir: '$_'"); + rmdir($_) or mtr_warning("rmdir($_) failed: $!"); + } + } else { + # Hopefully a file + mtr_verbose("unlink: '$_'"); + unlink($_) or mtr_warning("unlink($_) failed: $!"); + } + } + }, + $dir); } -sub do_before_start_slave ($) { - my ($tinfo)= @_; +sub clean_datadir { - my $tname= $tinfo->{'name'}; - my $init_script= $tinfo->{'master_sh'}; + mtr_verbose("Cleaning datadirs..."); - # Don't delete anything if starting dirty - return if ($opt_start_dirty); + if (started(all_servers()) != 0){ + mtr_error("Trying to clean datadir before all servers stopped"); + } - foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) + foreach my $cluster ( clusters() ) { - unlink($bin); - } + my $cluster_dir= "$opt_vardir/".$cluster->{name}; + mtr_verbose(" - removing '$cluster_dir'"); + rmtree($cluster_dir); - 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 ) + foreach my $mysqld ( mysqlds() ) { - 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"); + my $mysqld_dir= dirname($mysqld->value('datadir')); + if (-d $mysqld_dir ) { + mtr_verbose(" - removing '$mysqld_dir'"); + rmtree($mysqld_dir); } } - foreach my $bin ( glob("$slave->[0]->{'path_myddir'}/log.*") ) - { - unlink($bin); + # Remove all files in tmp and var/tmp + clean_dir("$opt_vardir/tmp"); + if ($opt_tmpdir ne "$opt_vardir/tmp"){ + clean_dir($opt_tmpdir); } } -sub mysqld_arguments ($$$$) { - my $args= shift; - my $mysqld= shift; - my $extra_opt= shift; - my $slave_master_info= shift; +# +# Save datadir before it's removed +# +sub save_datadir_after_failure($$) { + my ($dir, $savedir)= @_; - my $idx= $mysqld->{'idx'}; - my $sidx= ""; # Index as string, 0 is empty string - if ( $idx> 0 ) - { - $sidx= $idx; - } + mtr_report(" - saving '$dir'"); + my $dir_name= basename($dir); + rename("$dir", "$savedir/$dir_name"); +} - my $prefix= ""; # If mysqltest server arg - if ( $glob_use_embedded_server ) + +sub remove_ndbfs_from_ndbd_datadir { + my ($ndbd_datadir)= @_; + # Remove the ndb_*_fs directory from ndbd.X/ dir + foreach my $ndbfs_dir ( glob("$ndbd_datadir/ndb_*_fs") ) { - $prefix= "--server-arg="; + next unless -d $ndbfs_dir; # Skip if not a directory + rmtree($ndbfs_dir); } +} - mtr_add_arg($args, "%s--no-defaults", $prefix); - mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); - mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); +sub after_failure ($) { + my ($tinfo)= @_; - 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); - } + mtr_report("Saving datadirs..."); - if ( $mysql_version_id >= 50000 ) - { - mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); - } + my $save_dir= "$opt_vardir/log/"; + $save_dir.= $tinfo->{name}; + # Add combination name if any + $save_dir.= "-$tinfo->{combination}" + if defined $tinfo->{combination}; - 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); + # Save savedir path for server + $tinfo->{savedir}= $save_dir; - # 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); + mkpath($save_dir) if ! -d $save_dir; + # Save the used my.cnf file + copy($path_config_file, $save_dir); - # 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); - } + # Copy the tmp dir + copytree("$opt_vardir/tmp/", "$save_dir/tmp/"); - if ( $opt_valgrind_mysqld ) - { - mtr_add_arg($args, "%s--skip-safemalloc", $prefix); + if ( clusters() ) { + foreach my $cluster ( clusters() ) { + my $cluster_dir= "$opt_vardir/".$cluster->{name}; - if ( $mysql_version_id < 50100 ) - { - mtr_add_arg($args, "%s--skip-bdb", $prefix); + # Remove the fileystem of each ndbd + foreach my $ndbd ( in_cluster($cluster, ndbds()) ) + { + my $ndbd_datadir= $ndbd->value("DataDir"); + remove_ndbfs_from_ndbd_datadir($ndbd_datadir); + } + + save_datadir_after_failure($cluster_dir, $save_dir); + } + } + else { + foreach my $mysqld ( mysqlds() ) { + my $data_dir= $mysqld->value('datadir'); + save_datadir_after_failure(dirname($data_dir), $save_dir); } } +} - mtr_add_arg($args, "%s--pid-file=%s", $prefix, - $mysqld->{'path_pid'}); - mtr_add_arg($args, "%s--port=%d", $prefix, - $mysqld->{'port'}); +sub report_failure_and_restart ($) { + my $tinfo= shift; - mtr_add_arg($args, "%s--socket=%s", $prefix, - $mysqld->{'path_sock'}); + stop_all_servers(); - mtr_add_arg($args, "%s--datadir=%s", $prefix, - $mysqld->{'path_myddir'}); + $tinfo->{'result'}= 'MTR_RES_FAILED'; + my $test_failures= $tinfo->{'failures'} || 0; + $tinfo->{'failures'}= $test_failures + 1; - if ( $mysql_version_id >= 50106 ) + + if ( $tinfo->{comment} ) { - # Turn on logging to bothe tables and file - mtr_add_arg($args, "%s--log-output=table,file", $prefix); + # The test failure has been detected by mysql-test-run.pl + # when starting the servers or due to other error, the reason for + # failing the test is saved in "comment" + ; } - my $log_base_path= "$opt_vardir/log/$mysqld->{'type'}$sidx"; - mtr_add_arg($args, "%s--log=%s.log", $prefix, $log_base_path); - mtr_add_arg($args, - "%s--log-slow-queries=%s-slow.log", $prefix, $log_base_path); - - # 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 ( !defined $tinfo->{logfile} ) { - if (! ($opt_skip_master_binlog || $skip_binlog) ) + my $logfile= $path_current_testlog; + if ( defined $logfile ) { - mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, - $opt_vardir, $sidx); + if ( -f $logfile ) + { + # Test failure was detected by test tool and its report + # about what failed has been saved to file. Save the report + # in tinfo + $tinfo->{logfile}= mtr_fromfile($logfile); + } + else + { + # The test tool report didn't exist, display an + # error message + $tinfo->{logfile}= "Could not open test tool report '$logfile'"; + } } + } - mtr_add_arg($args, "%s--server-id=%d", $prefix, - $idx > 0 ? $idx + 101 : 1); + after_failure($tinfo); - mtr_add_arg($args, "%s--loose-innodb_data_file_path=ibdata1:10M:autoextend", - $prefix); + mtr_report_test($tinfo); - mtr_add_arg($args, "%s--local-infile", $prefix); +} - if ( $idx > 0 or !$use_innodb) - { - mtr_add_arg($args, "%s--loose-skip-innodb", $prefix); - } - my $cluster= $clusters->[$mysqld->{'cluster'}]; - if ( $cluster->{'pid'} || # Cluster is started - $cluster->{'use_running'} ) # Using running cluster - { - mtr_add_arg($args, "%s--ndbcluster", $prefix); - mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, - $cluster->{'connect_string'}); - if ( $mysql_version_id >= 50100 ) - { - mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); - } - } - else - { - mtr_add_arg($args, "%s--loose-skip-ndbcluster", $prefix); - } - } - else - { - mtr_error("unknown mysqld type") - unless $mysqld->{'type'} eq 'slave'; +sub run_sh_script { + my ($script)= @_; - 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); - } + return 0 unless defined $script; - 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--set-variable=slave_net_timeout=120", $prefix); - - if ( @$slave_master_info ) - { - foreach my $arg ( @$slave_master_info ) - { - mtr_add_arg($args, "%s%s", $prefix, $arg); - } - } - else - { - 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); - } + mtr_verbose("Running '$script'"); + my $ret= system("/bin/sh $script") >> 8; + return $ret; +} - my $cluster= $clusters->[$mysqld->{'cluster'}]; - if ( $cluster->{'pid'} || # Slave cluster is started - $cluster->{'use_running'} ) # Using running slave cluster - { - mtr_add_arg($args, "%s--ndbcluster", $prefix); - mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, - $cluster->{'connect_string'}); - if ( $mysql_version_id >= 50100 ) - { - mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); - } - } - else - { - mtr_add_arg($args, "%s--loose-skip-ndbcluster", $prefix); - } +sub mysqld_stop { + my $mysqld= shift or die "usage: mysqld_stop(<mysqld>)"; - } # end slave + my $args; + mtr_init_args(\$args); - 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); - } + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--password="); + mtr_add_arg($args, "--port=%d", $mysqld->value('port')); + mtr_add_arg($args, "--host=%s", $mysqld->value('#host')); + mtr_add_arg($args, "--connect_timeout=20"); + mtr_add_arg($args, "--protocol=tcp"); + + mtr_add_arg($args, "shutdown"); + + My::SafeProcess->run + ( + name => "mysqladmin shutdown ".$mysqld->name(), + path => $exe_mysqladmin, + args => \$args, + error => "/dev/null", + + ); +} - 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_ssl_supported ) +sub mysqld_arguments ($$$) { + my $args= shift; + my $mysqld= shift; + my $extra_opts= shift; + + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + + # 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 (!IS_WINDOWS and $euid == 0 and + (grep(/^--user/, @$extra_opts)) == 0) { + mtr_add_arg($args, "--user=root"); + } + + if ( $opt_valgrind_mysqld ) { - 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); + mtr_add_arg($args, "--skip-safemalloc"); + + if ( $mysql_version_id < 50100 ) + { + mtr_add_arg($args, "--skip-bdb"); + } } - if ( $opt_warnings ) + if ( $mysql_version_id >= 50106 ) { - mtr_add_arg($args, "%s--log-warnings", $prefix); + # Turn on logging to both tables and file + mtr_add_arg($args, "--log-output=table,file"); } - # Indicate to "mysqld" it will be debugged in debugger + # Check if "extra_opt" contains skip-log-bin + my $skip_binlog= grep(/^(--|--loose-)skip-log-bin/, @$extra_opts); + + # Indicate to mysqld it will be debugged in debugger if ( $glob_debugger ) { - mtr_add_arg($args, "%s--gdb", $prefix); + mtr_add_arg($args, "--gdb"); } my $found_skip_core= 0; - foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt ) + foreach my $arg ( @$extra_opts ) { # Allow --skip-core-file to be set in <testname>-[master|slave].opt file if ($arg eq "--skip-core-file") @@ -4108,65 +3937,39 @@ sub mysqld_arguments ($$$$) { { ; # Dont add --binlog-format when running without binlog } + elsif ($arg eq "--loose-skip-log-bin" and + $mysqld->option("log-slave-updates")) + { + ; # Dont add --skip-log-bin when mysqld have --log-slave-updates in config + } else { - mtr_add_arg($args, "%s%s", $prefix, $arg); + mtr_add_arg($args, "%s", $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); + mtr_add_arg($args, "%s", "--core-file"); } return $args; } -############################################################################## -# -# Start mysqld and return the PID -# -############################################################################## -sub mysqld_start ($$$) { +sub mysqld_start ($$) { my $mysqld= shift; - my $extra_opt= shift; - my $slave_master_info= shift; + my $extra_opts= shift; - my $args; # Arg vector - my $exe; - my $pid= -1; - my $wait_for_pid_file= 1; + mtr_verbose(My::Options::toStr("mysqld_start", @$extra_opts)); - my $type= $mysqld->{'type'}; - my $idx= $mysqld->{'idx'}; + my $exe= find_mysqld($mysqld->value('basedir')); + my $wait_for_pid_file= 1; 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"); - } + if $opt_embedded_server; + my $args; mtr_init_args(\$args); if ( $opt_valgrind_mysqld ) @@ -4174,23 +3977,30 @@ sub mysqld_start ($$$) { valgrind_arguments($args, \$exe); } - mysqld_arguments($args,$mysqld,$extra_opt,$slave_master_info); + mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld')); + mysqld_arguments($args,$mysqld,$extra_opts); - if ( $opt_gdb || $opt_manual_gdb) + if ( $opt_debug ) { - gdb_arguments(\$args, \$exe, "$type"."_$idx"); + mtr_add_arg($args, "--debug=d:t:i:A,%s/log/%s.trace", + $path_vardir_trace, $mysqld->name()); + } + + if ( $opt_gdb || $opt_manual_gdb ) + { + gdb_arguments(\$args, \$exe, $mysqld->name()); } elsif ( $opt_ddd || $opt_manual_ddd ) { - ddd_arguments(\$args, \$exe, "$type"."_$idx"); + ddd_arguments(\$args, \$exe, $mysqld->name()); } elsif ( $opt_debugger ) { - debugger_arguments(\$args, \$exe, "$type"."_$idx"); + debugger_arguments(\$args, \$exe, $mysqld->name()); } elsif ( $opt_manual_debug ) { - print "\nStart $type in your debugger\n" . + print "\nStart " .$mysqld->name()." in your debugger\n" . "dir: $glob_mysql_test_dir\n" . "exe: $exe\n" . "args: " . join(" ", @$args) . "\n\n" . @@ -4205,629 +4015,506 @@ sub mysqld_start ($$$) { $wait_for_pid_file= 0; } - # Remove the pidfile - unlink($mysqld->{'path_pid'}); + # Remove the old pidfile if any + unlink($mysqld->value('pid-file')); - if ( defined $exe ) + my $output= $mysqld->value('log-error'); + if ( $opt_valgrind and $opt_debug ) { - $pid= mtr_spawn($exe, $args, "", - $mysqld->{'path_myerr'}, - $mysqld->{'path_myerr'}, - "", - { append_log_file => 1 }); + # 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 + $output= "$opt_vardir/log/".$mysqld->name().".trace"; } - - if ( $wait_for_pid_file && !sleep_until_file_created($mysqld->{'path_pid'}, - $mysqld->{'start_timeout'}, - $pid)) + if ( defined $exe ) { - - mtr_error("Failed to start mysqld $mysqld->{'type'}"); + $mysqld->{'proc'}= My::SafeProcess->new + ( + name => $mysqld->name(), + path => $exe, + args => \$args, + output => $output, + error => $output, + append => 1, + verbose => $opt_verbose, + host => undef, + shutdown => sub { mysqld_stop($mysqld) }, + ); + mtr_verbose("Started $mysqld->{proc}"); } - - # Remember pid of the started process - $mysqld->{'pid'}= $pid; + if ( $wait_for_pid_file && + !sleep_until_file_created($mysqld->value('pid-file'), + $opt_start_timeout, + $mysqld->{'proc'})) + { + mtr_error("Failed to start mysqld $mysqld->name()"); + } # Remember options used when starting - $mysqld->{'start_opts'}= $extra_opt; - $mysqld->{'start_slave_master_info'}= $slave_master_info; + $mysqld->{'started_opts'}= $extra_opts; - mtr_verbose("mysqld pid: $pid"); - return $pid; + return; } sub stop_all_servers () { - mtr_report("Stopping All Servers"); + mtr_verbose("Stopping all servers..."); - if ( ! $opt_skip_im ) - { - mtr_report("Shutting-down Instance Manager"); - unless (mtr_im_stop($instance_manager, "stop_all_servers")) - { - mtr_error("Failed to stop Instance Manager.") - } - } + # Kill all started servers + My::SafeProcess::shutdown(0, # shutdown timeout 0 => kill + started(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}) + # Remove pidfiles + foreach my $server ( all_servers() ) { - 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 - } - } - - # Start shutdown of clusters - foreach my $cluster (@{$clusters}) - { - if ( $cluster->{'pid'} ) - { - $pid= mtr_ndbmgm_start($cluster, "shutdown"); - $admin_pids{$pid}= 1; - - push(@kill_pids,{ - pid => $cluster->{'pid'}, - pidfile => $cluster->{'path_pid'} - }); - - $cluster->{'pid'}= 0; # Assume we are done with it - - foreach my $ndbd (@{$cluster->{'ndbds'}}) - { - if ( $ndbd->{'pid'} ) - { - push(@kill_pids,{ - pid => $ndbd->{'pid'}, - pidfile => $ndbd->{'path_pid'}, - }); - $ndbd->{'pid'}= 0; - } - } - } + my $pid_file= $server->if_exist('pid-file'); + unlink($pid_file) if defined $pid_file; } - # Wait blocking until all shutdown processes has completed - mtr_wait_blocking(\%admin_pids); + # Mark servers as stopped + map($_->{proc}= undef, all_servers()); - # Make sure that process has shutdown else try to kill them - mtr_check_stop_servers(\@kill_pids); - - foreach my $mysqld (@{$master}, @{$slave}) - { - rm_ndbcluster_tables($mysqld->{'path_myddir'}); - } } -sub run_testcase_need_master_restart($) -{ - my ($tinfo)= @_; +# Find out if server should be restarted for this test +sub server_need_restart { + my ($tinfo, $server)= @_; - # 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'} ) + if ( using_extern() ) { - $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"); + mtr_verbose_restart($server, "no restart for --extern server"); + return 0; } - elsif ( ! $opt_skip_ndbcluster and - !$tinfo->{'ndb_test'} and - $clusters->[0]->{'pid'} != 0 ) + + if ( $opt_embedded_server ) { - $do_restart= 1; # Restart without cluster - mtr_verbose("Restart master: Test does not need cluster"); + mtr_verbose_restart($server, "no start or restart for embedded server"); + return 0; } - elsif ( ! $opt_skip_ndbcluster and - $tinfo->{'ndb_test'} and - $clusters->[0]->{'pid'} == 0 ) - { - $do_restart= 1; # Restart with cluster - mtr_verbose("Restart master: Test need cluster"); + + if ( $tinfo->{'force_restart'} ) { + mtr_verbose_restart($server, "forced in .opt file"); + return 1; } - elsif( $tinfo->{'component_id'} eq 'im' ) + + if ( $tinfo->{template_path} ne $current_config_name) { - $do_restart= 1; - mtr_verbose("Restart master: Always restart for im tests"); + mtr_verbose_restart($server, "using different config file"); + return 1; } - elsif ( $master->[0]->{'running_master_options'} and - $master->[0]->{'running_master_options'}->{'timezone'} ne - $tinfo->{'timezone'}) + + if ( $tinfo->{'master_sh'} || $tinfo->{'slave_sh'} ) { - $do_restart= 1; - mtr_verbose("Restart master: Different timezone"); + mtr_verbose_restart($server, "sh script to run"); + return 1; } - # 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'}) ) + + if ( ! started($server) ) { - $do_restart= 1; - mtr_verbose("Restart master: running with different options '" . - join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . - join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); + mtr_verbose_restart($server, "not started"); + return 1; } - elsif( ! $master->[0]->{'pid'} ) + + my $started_tinfo= $server->{'started_tinfo'}; + if ( defined $started_tinfo ) { - if ( $opt_extern ) - { - $do_restart= 0; - mtr_verbose("No restart: using extern master"); - } - else + + # Check if timezone of test that server was started + # with differs from timezone of next test + if ( timezone($started_tinfo) ne timezone($tinfo) ) { - $do_restart= 1; - mtr_verbose("Restart master: master is not started"); + mtr_verbose_restart($server, "different timezone"); + return 1; } } - 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"); + # Temporary re-enable the "always restart slave" hack + # this should be removed asap, but will require that each rpl + # testcase cleanup better after itself - ie. stop and reset + # replication + # Use the "#!use-slave-opt" marker to detect that this is a "slave" + # server + if ( $server->option("#!use-slave-opt") ){ + mtr_verbose_restart($server, "Always restart slave(s)"); + return 1; } - else + + my $is_mysqld= grep ($server eq $_, mysqlds()); + if ($is_mysqld) { - # Check if any slave is currently started - my $any_slave_started= 0; - foreach my $mysqld (@{$slave}) + # Check that running process was started with same options + # as the current test requires + my $extra_opts= get_extra_opts($server, $tinfo); + my $started_opts= $server->{'started_opts'}; + + if (!My::Options::same($started_opts, $extra_opts) ) { - if ( $mysqld->{'pid'} ) + my $use_dynamic_option_switch= 0; + if (!$use_dynamic_option_switch) { - $any_slave_started= 1; - last; + mtr_verbose_restart($server, "running with different options '" . + join(" ", @{$extra_opts}) . "' != '" . + join(" ", @{$started_opts}) . "'" ); + return 1; } - } - 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; + mtr_verbose(My::Options::toStr("started_opts", @$started_opts)); + mtr_verbose(My::Options::toStr("extra_opts", @$extra_opts)); + + # Get diff and check if dynamic switch is possible + my @diff_opts= My::Options::diff($started_opts, $extra_opts); + mtr_verbose(My::Options::toStr("diff_opts", @diff_opts)); + + my $query= My::Options::toSQL(@diff_opts); + mtr_verbose("Attempting dynamic switch '$query'"); + if (run_query($tinfo, $server, $query)){ + mtr_verbose("Restart: running with different options '" . + join(" ", @{$extra_opts}) . "' != '" . + join(" ", @{$started_opts}) . "'" ); + return 1; + } + + # Remember the dynamically set options + $server->{'started_opts'}= $extra_opts; } } - return $do_slave_restart; - + # Default, no restart + return 0; } -# ---------------------------------------------------------------------- -# 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 +sub servers_need_restart($) { + my ($tinfo)= @_; + return grep { server_need_restart($tinfo, $_); } all_servers(); +} - # 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); +# +# Return list of specific servers +# - there is no servers in an empty config +# +sub _like { return $config ? $config->like($_[0]) : (); } +sub mysqlds { return _like('mysqld.'); } +sub ndbds { return _like('cluster_config.ndbd.');} +sub ndb_mgmds { return _like('cluster_config.ndb_mgmd.'); } +sub clusters { return _like('mysql_cluster.'); } +sub all_servers { return ( mysqlds(), ndb_mgmds(), ndbds() ); } - $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'}, - }); +# +# Filter a list of servers and return only those that are part +# of the specified cluster +# +sub in_cluster { + my ($cluster)= shift; + # Return only processes for a specific cluster + return grep { $_->suffix() eq $cluster->suffix() } @_; +} - $mysqld->{'pid'}= 0; # Assume we are done with it - } - } - # Start shutdown of master cluster - my $cluster= $clusters->[0]; - if ( $cluster->{'pid'} ) - { - $pid= mtr_ndbmgm_start($cluster, "shutdown"); - $admin_pids{$pid}= 1; - push(@kill_pids,{ - pid => $cluster->{'pid'}, - pidfile => $cluster->{'path_pid'} - }); +# +# Filter a list of servers and return the SafeProcess +# for only those that are started or stopped +# +sub started { return grep(defined $_, map($_->{proc}, @_)); } +sub stopped { return grep(!defined $_, map($_->{proc}, @_)); } - $cluster->{'pid'}= 0; # Assume we are done with it - foreach my $ndbd (@{$cluster->{'ndbds'}}) - { - push(@kill_pids,{ - pid => $ndbd->{'pid'}, - pidfile => $ndbd->{'path_pid'}, - }); - $ndbd->{'pid'}= 0; # Assume we are done with it - } - } - } +sub envsubst { + my $string= shift; - if ( $do_restart || $do_slave_restart ) + if ( ! defined $ENV{$string} ) { + mtr_error(".opt file references '$string' which is not set"); + } - 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; + return $ENV{$string}; +} - 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'}, - }); +sub get_extra_opts { + my ($mysqld, $tinfo)= @_; - $mysqld->{'pid'}= 0; # Assume we are done with it - } - } + my $opts= + $mysqld->option("#!use-slave-opt") ? + $tinfo->{slave_opt} : $tinfo->{master_opt}; - # Start shutdown of slave cluster - my $cluster= $clusters->[1]; - if ( $cluster->{'pid'} ) - { - $pid= mtr_ndbmgm_start($cluster, "shutdown"); + # Expand environment variables + foreach my $opt ( @$opts ) + { + $opt =~ s/\$\{(\w+)\}/envsubst($1)/ge; + $opt =~ s/\$(\w+)/envsubst($1)/ge; + } + return $opts; +} - $admin_pids{$pid}= 1; - push(@kill_pids,{ - pid => $cluster->{'pid'}, - pidfile => $cluster->{'path_pid'} - }); +sub stop_servers($$) { + my ($tinfo, @servers)= @_; - $cluster->{'pid'}= 0; # Assume we are done with it + # Remember if we restarted for this test case (count restarts) + $tinfo->{'restarted'}= 1; - foreach my $ndbd (@{$cluster->{'ndbds'}} ) - { - push(@kill_pids,{ - pid => $ndbd->{'pid'}, - pidfile => $ndbd->{'path_pid'}, - }); - $ndbd->{'pid'}= 0; # Assume we are done with it - } - } - } + if ( join('|', @servers) eq join('|', all_servers()) ) + { + # All servers are going down, use some kind of order to + # avoid too many warnings in the log files - # ---------------------------------------------------------------------- - # Shutdown has now been started and lists for the shutdown processes - # and the processes to be killed has been created - # ---------------------------------------------------------------------- + mtr_report("Restarting all servers"); - # Wait blocking until all shutdown processes has completed - mtr_wait_blocking(\%admin_pids); + # mysqld processes + My::SafeProcess::shutdown( $opt_shutdown_timeout, started(mysqlds()) ); + # cluster processes + My::SafeProcess::shutdown( $opt_shutdown_timeout, + started(ndbds(), ndb_mgmds()) ); + } + else + { + mtr_report("Restarting ", started(@servers)); - # Make sure that process has shutdown else try to kill them - mtr_check_stop_servers(\@kill_pids); + # Stop only some servers + My::SafeProcess::shutdown( $opt_shutdown_timeout, + started(@servers) ); + } - foreach my $mysqld (@{$master}, @{$slave}) + foreach my $server (@servers) { - if ( ! $mysqld->{'pid'} ) - { - # Remove ndbcluster tables if server is stopped - rm_ndbcluster_tables($mysqld->{'path_myddir'}); - } + # Mark server as stopped + $server->{proc}= undef; + + # Forget history + delete $server->{'started_tinfo'}; + delete $server->{'started_opts'}; + delete $server->{'started_cnf'}; } } # -# run_testcase_start_servers +# start_servers # -# Start the servers needed by this test case +# Start servers not already started # # RETURN # 0 OK # 1 Start failed # +sub start_servers($) { + my ($tinfo)= @_; -sub run_testcase_start_servers($) { - my $tinfo= shift; - my $tname= $tinfo->{'name'}; + # Start clusters + foreach my $cluster ( clusters() ) + { + ndbcluster_start($cluster); + } - if ( $tinfo->{'component_id'} eq 'mysqld' ) + # Start mysqlds + foreach my $mysqld ( mysqlds() ) { - if ( ! $opt_skip_ndbcluster and - !$clusters->[0]->{'pid'} and - $tinfo->{'ndb_test'} ) + if ( $mysqld->{proc} ) { - # Test need cluster, cluster is not started, start it - ndbcluster_start($clusters->[0], ""); + # Already started + + # Write start of testcase to log file + mark_log($mysqld->value('log-error'), $tinfo); + + next; } - if ( !$master->[0]->{'pid'} ) + my $datadir= $mysqld->value('datadir'); + if ($opt_start_dirty) { - # Master mysqld is not started - do_before_start_master($tinfo); + # Don't delete anything if starting dirty + ; + } + else + { + + my @options= ('log-bin', 'relay-log'); + foreach my $option_name ( @options ) { + next unless $mysqld->option($option_name); - mysqld_start($master->[0],$tinfo->{'master_opt'},[]); + my $file_name= $mysqld->value($option_name); + next unless + defined $file_name and + -e $file_name; + mtr_debug(" -removing '$file_name'"); + unlink($file_name) or die ("unable to remove file '$file_name'"); + } + + if (-d $datadir ) { + mtr_verbose(" - removing '$datadir'"); + rmtree($datadir); + } } - if ( $clusters->[0]->{'pid'} || $clusters->[0]->{'use_running'} - and ! $master->[1]->{'pid'} and - $tinfo->{'master_num'} > 1 ) + my $mysqld_basedir= $mysqld->value('basedir'); + if ( $basedir eq $mysqld_basedir ) { - # Test needs cluster, start an extra mysqld connected to cluster + # Copy datadir from installed system db + for my $path ( "$opt_vardir", "$opt_vardir/..") { + my $install_db= "$path/install.db"; + copytree($install_db, $datadir) + if -d $install_db; + } + mtr_error("Failed to copy system db to '$datadir'") + unless -d $datadir; + } + else + { + mysql_install_db($mysqld); # For versional testing - if ( $mysql_version_id >= 50100 ) - { - # First wait for first mysql server to have created ndb system - # tables ok FIXME This is a workaround so that only one mysqld - # create the tables - if ( ! sleep_until_file_created( - "$master->[0]->{'path_myddir'}/mysql/ndb_apply_status.ndb", - $master->[0]->{'start_timeout'}, - $master->[0]->{'pid'})) - { + mtr_error("Failed to install system db to '$datadir'") + unless -d $datadir; - $tinfo->{'comment'}= "Failed to create 'mysql/ndb_apply_status' table"; - return 1; - } - } - mysqld_start($master->[1],$tinfo->{'master_opt'},[]); } - # Save this test case information, so next can examine it - $master->[0]->{'running_master_options'}= $tinfo; - } - elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) - { - # We have to create defaults file every time, in order to ensure that it - # will be the same for each test. The problem is that test can change the - # file (by SET/UNSET commands), so w/o recreating the file, execution of - # one test can affect the other. + # Create the servers tmpdir + my $tmpdir= $mysqld->value('tmpdir'); + mkpath($tmpdir) unless -d $tmpdir; - im_create_defaults_file($instance_manager); + # Write start of testcase to log file + mark_log($mysqld->value('log-error'), $tinfo); - if ( ! mtr_im_start($instance_manager, $tinfo->{im_opts}) ) + # Run <tname>-master.sh + if ($mysqld->option('#!run-master-sh') and + run_sh_script($tinfo->{master_sh}) ) { - $tinfo->{'comment'}= "Failed to start Instance Manager. "; + $tinfo->{'comment'}= "Failed to execute '$tinfo->{master_sh}'"; return 1; } - } - - # ---------------------------------------------------------------------- - # Start slaves - if needed - # ---------------------------------------------------------------------- - if ( $tinfo->{'slave_num'} ) - { - restore_slave_databases($tinfo->{'slave_num'}); - do_before_start_slave($tinfo); - - if ( ! $opt_skip_ndbcluster_slave and - !$clusters->[1]->{'pid'} and - $tinfo->{'ndb_test'} ) + # Run <tname>-slave.sh + if ($mysqld->option('#!run-slave-sh') and + run_sh_script($tinfo->{slave_sh})) { - # Test need slave cluster, cluster is not started, start it - ndbcluster_start($clusters->[1], ""); + $tinfo->{'comment'}= "Failed to execute '$tinfo->{slave_sh}'"; + return 1; } - for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) + if (!$opt_embedded_server) { - if ( ! $slave->[$idx]->{'pid'} ) - { - mysqld_start($slave->[$idx],$tinfo->{'slave_opt'}, - $tinfo->{'slave_mi'}); + my $extra_opts= get_extra_opts($mysqld, $tinfo); + mysqld_start($mysqld,$extra_opts); - } + # Save this test case information, so next can examine it + $mysqld->{'started_tinfo'}= $tinfo; } - # Save this test case information, so next can examine it - $slave->[0]->{'running_slave_options'}= $tinfo; } # Wait for clusters to start - foreach my $cluster (@{$clusters}) + foreach my $cluster ( clusters() ) { - - next if !$cluster->{'pid'}; - if (ndbcluster_wait_started($cluster, "")) { # failed to start - $tinfo->{'comment'}= "Start of $cluster->{'name'} cluster failed"; + $tinfo->{'comment'}= "Start of '".$cluster->name()."' cluster failed"; return 1; } } - # Wait for mysqld's to start - foreach my $mysqld (@{$master},@{$slave}) + # Wait for mysqlds to start + foreach my $mysqld ( mysqlds() ) { + next if !started($mysqld); - next if !$mysqld->{'pid'}; + if (sleep_until_file_created($mysqld->value('pid-file'), + $opt_start_timeout, + $mysqld->{'proc'}) == 0) { + $tinfo->{comment}= + "Failed to start ".$mysqld->name(); - if (mysqld_wait_started($mysqld)) - { - # failed to start - $tinfo->{'comment'}= - "Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"; + my $logfile= $mysqld->value('log-error'); + if ( defined $logfile and -f $logfile ) + { + $tinfo->{logfile}= mtr_fromfile($logfile); + } + else + { + $tinfo->{logfile}= "Could not open server logfile: '$logfile'"; + } return 1; } } return 0; } + # # Run include/check-testcase.test -# Before a testcase, run in record mode, save result file to var +# Before a testcase, run in record mode and save result file to var/tmp # After testcase, run and compare with the recorded file, they should be equal! # # RETURN VALUE -# 0 OK -# 1 Check failed +# The newly started process # -sub run_check_testcase ($$) { - +sub start_check_testcase ($$$) { + my $tinfo= shift; my $mode= shift; my $mysqld= shift; - my $name= "check-" . $mysqld->{'type'} . $mysqld->{'idx'}; + my $name= "check-".$mysqld->name(); + # Replace dots in name with underscore to avoid that mysqltest + # misinterpret's what the filename extension is :( + $name=~ s/\./_/g; my $args; mtr_init_args(\$args); - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--silent"); - mtr_add_arg($args, "--skip-safemalloc"); - mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); - mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld')); - 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, "--skip-safemalloc"); - mtr_add_arg($args, "-R"); - mtr_add_arg($args, "$opt_vardir/tmp/$name.result"); + mtr_add_arg($args, "--result-file=%s", "$opt_vardir/tmp/$name.result"); + mtr_add_arg($args, "--test-file=%s", "include/check-testcase.test"); 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; + my $errfile= "$opt_vardir/tmp/$name.err"; + my $proc= My::SafeProcess->new + ( + name => $name, + path => $exe_mysqltest, + error => $errfile, + output => $errfile, + args => \$args, + user_data => $errfile, + verbose => $opt_verbose, + ); + + mtr_report("Started $proc"); + return $proc; } -############################################################################## -# -# 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 $proc= start_mysqltest(@_); + $proc->wait(); } -sub run_mysqltest ($) { +sub start_mysqltest ($) { my ($tinfo)= @_; my $exe= $exe_mysqltest; my $args; mtr_init_args(\$args); - mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); mtr_add_arg($args, "--silent"); mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); @@ -4838,21 +4525,7 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--mark-progress") if $opt_mark_progress; - if ($tinfo->{'component_id'} eq 'im') - { - mtr_add_arg($args, "--socket=%s", $instance_manager->{'path_sock'}); - mtr_add_arg($args, "--port=%d", $instance_manager->{'port'}); - mtr_add_arg($args, "--user=%s", $instance_manager->{'admin_login'}); - mtr_add_arg($args, "--password=%s", $instance_manager->{'admin_password'}); - } - else # 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="); - } + mtr_add_arg($args, "--database=test"); if ( $opt_ps_protocol ) { @@ -4876,16 +4549,13 @@ sub run_mysqltest ($) { if ( $opt_strace_client ) { - $exe= "strace"; # FIXME there are ktrace, .... + $exe= $opt_strace_client || "strace"; 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); - } + mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir); if ( $opt_compress ) { @@ -4897,51 +4567,43 @@ sub run_mysqltest ($) { 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 ) + + if ( $opt_embedded_server ) { - mtr_add_arg($args, "--skip-ssl"); - } - # ---------------------------------------------------------------------- - # If embedded server, we create server args to give mysqltest to pass on - # ---------------------------------------------------------------------- + # Get the args needed for the embedded server + # and append them to args prefixed + # with --sever-arg= - if ( $glob_use_embedded_server ) - { - mysqld_arguments($args,$master->[0],$tinfo->{'master_opt'},[]); + my $mysqld= $config->group('embedded') + or mtr_error("Could not get [embedded] section"); + + my $mysqld_args; + mtr_init_args(\$mysqld_args); + my $extra_opts= get_extra_opts($mysqld, $tinfo); + mysqld_arguments($mysqld_args, $mysqld, $extra_opts); + mtr_add_arg($args, "--server-arg=%s", $_) for @$mysqld_args; + + if (IS_WINDOWS) + { + # Trick the server to send output to stderr, with --console + mtr_add_arg($args, "--server-arg=--console"); + } } # ---------------------------------------------------------------------- # export MYSQL_TEST variable containing <path>/mysqltest <args> # ---------------------------------------------------------------------- - $ENV{'MYSQL_TEST'}= - mtr_native_path($exe_mysqltest) . " " . join(" ", @$args); + $ENV{'MYSQL_TEST'}= mtr_args2str($exe_mysqltest, @$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. @@ -4962,9 +4624,17 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'}); } + client_debug_arg($args, "mysqltest"); + if ( $opt_record ) { mtr_add_arg($args, "--record"); + + # When recording to a non existing result file + # the name of that file is in "record_file" + if ( defined $tinfo->{'record_file'} ) { + mtr_add_arg($args, "--result-file=%s", $tinfo->{record_file}); + } } if ( $opt_client_gdb ) @@ -4978,38 +4648,20 @@ sub run_mysqltest ($) { 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; - + } + + + my $proc= My::SafeProcess->new + ( + name => "mysqltest", + path => $exe, + args => \$args, + append => 1, + error => $path_current_testlog, + verbose => $opt_verbose, + ); + mtr_verbose("Started $proc"); + return $proc; } @@ -5023,7 +4675,7 @@ sub gdb_arguments { # Write $args to gdb init file my $str= join(" ", @$$args); - my $gdb_init_file= "$opt_tmpdir/gdbinit.$type"; + my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type"; # Remove the old gdbinit file unlink($gdb_init_file); @@ -5087,7 +4739,7 @@ sub ddd_arguments { # Write $args to ddd init file my $str= join(" ", @$$args); - my $gdb_init_file= "$opt_tmpdir/gdbinit.$type"; + my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type"; # Remove the old gdbinit file unlink($gdb_init_file); @@ -5227,14 +4879,11 @@ sub valgrind_arguments { } -############################################################################## # -# Usage +# Usage # -############################################################################## - sub usage ($) { - my $message= shift; + my ($message)= @_; if ( $message ) { @@ -5256,15 +4905,15 @@ Options to control what engine/variation to run 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 - ndb|with-ndbcluster Use cluster as default table type vs-config Visual Studio configuration used to create executables (default: MTR_VS_CONFIG environment variable) + config|defaults-file=<config template> Use fixed config template for all + tests + defaults_extra_file=<config template> Extra config template to add to + all generated configs + 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 @@ -5276,6 +4925,9 @@ Options to control directories to use for tmpfs (/dev/shm) The option can also be set using environment variable MTR_MEM=[DIR] + client-bindir=PATH Path to the directory where client binaries are located + client-libdir=PATH Path to the directory where client libraries are located + Options to control what test suites or cases to run @@ -5283,33 +4935,27 @@ Options to control what test suites or cases to run with-ndbcluster-only Run only tests that include "ndb" in the filename skip-ndb[cluster] Skip all tests that need cluster skip-ndb[cluster]-slave Skip all tests that need a slave cluster - ndb-extra Run extra tests from ndb directory 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 + start-from=PREFIX Run test cases starting test prefixed with PREFIX where + prefix may be suite.testname or just testname + suite[s]=NAME1,..,NAMEN + Collect tests in suites from the comma separated list of suite names. - The default is: "$opt_suites_default" + The default is: "$DEFAULT_SUITES" skip-rpl Skip the replication test cases. - skip-im Don't start IM, and skip the IM 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 + big-test Also run tests marked as "big" 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 - ndbcluster-port=PORT Specify the port number used by cluster - ndbcluster-port-slave=PORT Specify the port number used by slave cluster - mtr-build-thread=# Specify unique collection of ports. Can also be set by - setting the environment variable MTR_BUILD_THREAD. + mtr-build-thread=# Specify unique number to calculate port number(s) from. + build-thread=# Can be set in environment variable MTR_BUILD_THREAD. + Set MTR_BUILD_THREAD="auto" to automatically aquire + a build thread id that is unique to current host Options for test case authoring @@ -5323,11 +4969,11 @@ Options that pass on options Options to run test on running server - extern Use running server for tests - ndb-connectstring=STR Use running cluster, and connect using STR - ndb-connectstring-slave=STR Use running slave cluster, and connect using STR - user=USER User for connection to extern server - socket=PATH Socket for connection to extern server + extern option=value Run only the tests against an already started server + the options to use for connection to the extern server + must be specified using name-value pair notation + For example: + ./$0 --extern socket=/tmp/mysqld.sock Options for debugging the product @@ -5344,17 +4990,24 @@ Options for debugging the product 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 + strace-client=[path] Create strace output for mysqltest client, optionally + specifying name and path to the trace program to use. + Example: $0 --strace-client=ktrace 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. + $opt_max_save_core, set to 0 for no limit. Set + it's default with MTR_MAX_SAVE_CORE + max-save-datadir Limit the number of datadir saved (to avoid filling + up disks for heavily crashing server). Defaults to + $opt_max_save_datadir, set to 0 for no limit. Set + it's default with MTR_MAX_SAVE_DATDIR + max-test-fail Limit the number of test failurs before aborting + the current test run. Defaults to + $opt_max_test_fail, set to 0 for no limit. Set + it's default with MTR_MAX_TEST_FAIL -Options for coverage, profiling etc +Options for valgrind - gcov FIXME - gprof FIXME valgrind Run the "mysqltest" and "mysqld" executables using valgrind with default options valgrind-all Synonym for --valgrind @@ -5368,32 +5021,36 @@ Options for coverage, profiling etc callgrind Instruct valgrind to use callgrind Misc options - + user=USER User for connecting to mysqld(default: $opt_user) 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) + verbose More verbose output(use multiple times for even more) + start Only initialize and start the servers, using the + startup settings for the first specified test case + Example: + $0 --start alias & 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 + the first specified test case + fast Run as fast as possible, dont't wait for servers + to shutdown etc. + repeat=N Run each test N number of times + retry=N Retry tests that fail N times, limit number of failures + to $opt_retry_failure + retry-failure=N Limit number of retries for a failed test 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 + testcase-timeout=MINUTES Max test case run time (default $opt_testcase_timeout) + suite-timeout=MINUTES Max test suite run time (default $opt_suite_timeout) + shutdown-timeout=SECONDS Max number of seconds to wait for server shutdown + before killing servers (default $opt_shutdown_timeout) + warnings Scan the log files for warnings. Use --nowarnings + to turn off. 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); + exit(1); } + |