diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am index 60679e5b06d..5e3582d5e16 100644 --- a/mysql-test/Makefile.am +++ b/mysql-test/Makefile.am @@ -71,11 +71,11 @@ SUBDIRS = lib/My/SafeProcess EXTRA_DIST = README \ valgrind.supp \ $(test_SCRIPTS) \ - $(nobase_test_DATA) + $(nobase_test_DATA) # List of directories containing test + result files and the # related test data files that should be copied -TEST_DIRS = t r include std_data std_data/parts \ +TEST_DIRS = t r include std_data std_data/parts collections \ std_data/ndb_backup50 std_data/ndb_backup51 \ std_data/ndb_backup51_data_be std_data/ndb_backup51_data_le \ std_data/funcs_1 \ diff --git a/mysql-test/collections/README b/mysql-test/collections/README new file mode 100644 index 00000000000..9af84646a40 --- /dev/null +++ b/mysql-test/collections/README @@ -0,0 +1,30 @@ +This directory contains collections of test runs that we run during our +integration and release testing. Each file contains zero or more lines, +with one invocation of mysql-test-run.pl on each. These invocations are +written so that, with the assumption that perl is in your search path, +any collection can run as a shell script or a batch file, with the parent +mysql-test directory being the current working directory. + +During integration testing, we choose the collection to run by following +these steps: + +1) We choose the extension to look for, based on these rules: + - If we're running a per-push test, we choose ".push" as the extension. + - If we're running a daily test, we choose ".daily" as the extension. + - If we're running a weekly test, we choose ".weekly" as the extension. + +2) If there is a collection that has the same name as the branch we're + testing plus the extension as determined in step 1, we choose that + collection. + +3) If the branch is unknown or we have removed all characters from it + and still not found a matching collection, we choose the name "default" + plus the extension determined in step 1. If there is no such file, + we give up and don't test anything at all. + +4) If we haven't found a collection yet, we remove the last character from + the branch name and go back to step 2. + +5) The commands from the collection are run line by line via execv() or + similar system calls. They are not run as a shell script. Shell + expansions are not guaranteed to work and most likely won't. diff --git a/mysql-test/collections/README.experimental b/mysql-test/collections/README.experimental new file mode 100644 index 00000000000..9eee2394423 --- /dev/null +++ b/mysql-test/collections/README.experimental @@ -0,0 +1,25 @@ +The .experimental files in this directory contain names of test cases that +are still in development and whose failures should be considered expected, +instead of regressions. + +These files are to be used with the --experimental option of +mysql-test-run.pl. Please look at its help screen for usage information. + +The syntax is as follows: + +1) One line per test case. + +2) Empty lines and lines starting with a hash (#) are ignored. + +3) If any other line contains a blank followed by a hash (#), the hash + and any subsequent characters are ignored. + +4) The full test case name including the suite and execution mode + must be specified, for example: + main.alias 'row' # bug#00000 + +5) As an exception to item 4, the last character of the test case + specification may be an asterisk (*). In that case, all test cases that + start with the same characters up to the last letter before the asterisk + are considered experimental: + main.a* # get rid of main.alias, main.alibaba and main.agliolio diff --git a/mysql-test/collections/default.daily b/mysql-test/collections/default.daily new file mode 100644 index 00000000000..194cc2aad59 --- /dev/null +++ b/mysql-test/collections/default.daily @@ -0,0 +1 @@ +perl mysql-test-run.pl --timer --force --comment=rpl_ndb_row --suite=rpl_ndb,ndb --mysqld=--binlog-format=row --experimental=collections/default.experimental diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental new file mode 100644 index 00000000000..103069f79cf --- /dev/null +++ b/mysql-test/collections/default.experimental @@ -0,0 +1 @@ +funcs_1.charset_collation_1 # depends on compile-time decisions diff --git a/mysql-test/collections/default.push b/mysql-test/collections/default.push new file mode 100644 index 00000000000..0879b6fde2c --- /dev/null +++ b/mysql-test/collections/default.push @@ -0,0 +1,5 @@ +perl mysql-test-run.pl --timer --force --comment=n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --comment=ps_row --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --comment=embedded --embedded --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --comment=rpl_binlog_row --suite=rpl,binlog --mysqld=--binlog-format=row --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --comment=funcs_1 --suite=funcs_1 --experimental=collections/default.experimental diff --git a/mysql-test/collections/default.weekly b/mysql-test/collections/default.weekly new file mode 100644 index 00000000000..e69de29bb2d diff --git a/mysql-test/include/check-warnings.test b/mysql-test/include/check-warnings.test index 2144957f742..5295dd51a85 100644 --- a/mysql-test/include/check-warnings.test +++ b/mysql-test/include/check-warnings.test @@ -26,7 +26,7 @@ create temporary table error_log ( ) engine=myisam; # Get the name of servers error log -let $log_error= query_get_value(show variables like 'log_error', Value, 1); +let $log_error= $MTR_LOG_ERROR; let $log_warning= $log_error.warnings; # Try tload the warnings into a temporary table, diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm index 567a05ac7a1..852f706c858 100644 --- a/mysql-test/lib/My/ConfigFactory.pm +++ b/mysql-test/lib/My/ConfigFactory.pm @@ -116,8 +116,8 @@ sub fix_tmpdir { sub fix_log_error { my ($self, $config, $group_name, $group)= @_; - my $dir= dirname($group->value('datadir')); - return "$dir/mysqld.err"; + my $dir= $self->{ARGS}->{vardir}; + return "$dir/log/$group_name.err"; } sub fix_log { @@ -203,7 +203,7 @@ my @mysqld_rules= { '#host' => \&fix_host }, { 'port' => \&fix_port }, { 'socket' => \&fix_socket }, - { 'log-error' => \&fix_log_error }, + { '#log-error' => \&fix_log_error }, { 'log' => \&fix_log }, { 'log-slow-queries' => \&fix_log_slow_queries }, { '#user' => sub { return shift->{ARGS}->{user} || ""; } }, @@ -389,7 +389,7 @@ sub post_check_embedded_group { my @no_copy = ( - 'log-error', # Embedded server writes stderr to mysqltest's log file + '#log-error', # Embedded server writes stderr to mysqltest's log file 'slave-net-timeout', # Embedded server are not build with replication ); diff --git a/mysql-test/lib/My/Platform.pm b/mysql-test/lib/My/Platform.pm index 3dd5c552b10..69ffdfbb4ce 100644 --- a/mysql-test/lib/My/Platform.pm +++ b/mysql-test/lib/My/Platform.pm @@ -113,8 +113,8 @@ sub check_socket_path_length { # Create a tempfile name with same length as "path" my $tmpdir = tempdir( CLEANUP => 0); - my $len = length($path) - length($tmpdir); - my $testfile = $tmpdir . "x" x ($len > 0 ? $len : 1); + my $len = length($path) - length($tmpdir) - 1; + my $testfile = $tmpdir . "/" . "x" x ($len > 0 ? $len : 1); my $sock; eval { $sock= new IO::Socket::UNIX @@ -126,17 +126,15 @@ sub check_socket_path_length { die "Could not create UNIX domain socket: $!" unless defined $sock; - die "UNIX domain socket patch was truncated" + die "UNIX domain socket path was truncated" unless ($testfile eq $sock->hostpath()); $truncated= 0; # Yes, it worked! }; - #print "check_socket_path_length, failed: ", $@, '\n' if ($@); $sock= undef; # Close socket - unlink($testfile); # Remove the physical file - rmdir($tmpdir); # Remove the tempdir + rmtree($tmpdir); # Remove the tempdir and any socket file created return $truncated; } diff --git a/mysql-test/lib/My/SafeProcess.pm b/mysql-test/lib/My/SafeProcess.pm index 0e3aa968052..5ef3286ad8e 100644 --- a/mysql-test/lib/My/SafeProcess.pm +++ b/mysql-test/lib/My/SafeProcess.pm @@ -117,6 +117,7 @@ sub new { my $output = delete($opts{'output'}); my $error = delete($opts{'error'}); my $verbose = delete($opts{'verbose'}); + my $nocore = delete($opts{'nocore'}); my $host = delete($opts{'host'}); my $shutdown = delete($opts{'shutdown'}); my $user_data= delete($opts{'user_data'}); @@ -137,6 +138,7 @@ sub new { push(@safe_args, $safe_script) if defined $safe_script; push(@safe_args, "--verbose") if $verbose > 0; + push(@safe_args, "--nocore") if $nocore; # Point the safe_process at the right parent if running on cygwin push(@safe_args, "--parent-pid=".Cygwin::pid_to_winpid($$)) if IS_CYGWIN; diff --git a/mysql-test/lib/My/SafeProcess/safe_process.cc b/mysql-test/lib/My/SafeProcess/safe_process.cc index 7932f3fd2d6..6ad45a3226e 100644 --- a/mysql-test/lib/My/SafeProcess/safe_process.cc +++ b/mysql-test/lib/My/SafeProcess/safe_process.cc @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -149,7 +150,8 @@ int main(int argc, char* const argv[] ) char* const* child_argv= 0; pid_t own_pid= getpid(); pid_t parent_pid= getppid(); - + bool nocore = false; + /* Install signal handlers */ signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); @@ -181,6 +183,9 @@ int main(int argc, char* const argv[] ) start++; /* Step past = */ if ((parent_pid= atoi(start)) == 0) die("Invalid value '%s' passed to --parent-id", start); + } else if ( strcmp(arg, "--nocore") == 0 ) + { + nocore = true; // Don't allow the process to dump core } else die("Unknown option: %s", arg); @@ -218,6 +223,15 @@ int main(int argc, char* const argv[] ) // it and any childs(that hasn't changed group themself) setpgid(0, 0); + if (nocore) + { + struct rlimit corelim = { 0, 0 }; + if (setrlimit (RLIMIT_CORE, &corelim) < 0) + { + message("setrlimit failed, errno=%d", errno); + } + } + // Signal that child is ready buf= 37; write(pfd[1], &buf, 1); diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm index ce3fba87385..9c6ab35ee5e 100644 --- a/mysql-test/lib/mtr_report.pm +++ b/mysql-test/lib/mtr_report.pm @@ -69,6 +69,8 @@ sub _mtr_report_test_name ($) { print _name(), _timestamp(); printf "%-40s ", $tname; + + return $tname; } @@ -105,20 +107,48 @@ sub mtr_report_test_passed ($) { sub mtr_report_test ($) { my ($tinfo)= @_; - _mtr_report_test_name($tinfo); + my $test_name = _mtr_report_test_name($tinfo); my $comment= $tinfo->{'comment'}; my $logfile= $tinfo->{'logfile'}; my $warnings= $tinfo->{'warnings'}; my $result= $tinfo->{'result'}; + my $retry= $tinfo->{'retries'} ? "retry-" : ""; if ($result eq 'MTR_RES_FAILED'){ my $timest = format_time(); + my $fail = "fail"; + + if ( $::opt_experimental ) + { + # Find out if this test case is an experimental one, so we can treat + # the failure as an expected failure instead of a regression. + for my $exp ( @$::experimental_test_cases ) { + if ( $exp ne $test_name ) { + # if the expression is not the name of this test case, but has + # an asterisk at the end, determine if the characters up to + # but excluding the asterisk are the same + if ( $exp ne "" && substr($exp, -1, 1) eq "*" ) { + $exp = substr($exp, 0, length($exp) - 1); + if ( substr($test_name, 0, length($exp)) ne $exp ) { + # no match, try next entry + next; + } + # if yes, fall through to set the exp-fail status + } else { + # no match, try next entry + next; + } + } + $fail = "exp-fail"; + last; + } + } if ( $warnings ) { - mtr_report("[ fail ] Found warnings/errors in server log file!"); + mtr_report("[ $retry$fail ] Found warnings/errors in server log file!"); mtr_report(" Test ended at $timest"); mtr_report($warnings); return; @@ -126,14 +156,14 @@ sub mtr_report_test ($) { my $timeout= $tinfo->{'timeout'}; if ( $timeout ) { - mtr_report("[ fail ] timeout after $timeout seconds"); + mtr_report("[ $retry$fail ] timeout after $timeout seconds"); mtr_report(" Test ended at $timest"); mtr_report("\n$tinfo->{'comment'}"); return; } else { - mtr_report("[ fail ]\n Test ended at $timest"); + mtr_report("[ $retry$fail ]\n Test ended at $timest"); } if ( $logfile ) @@ -176,7 +206,7 @@ sub mtr_report_test ($) { { my $timer_str= $tinfo->{timer} || ""; $tot_real_time += ($timer_str/1000); - mtr_report("[ pass ] ", sprintf("%5s", $timer_str)); + mtr_report("[ ${retry}pass ] ", sprintf("%5s", $timer_str)); # Show any problems check-testcase found if ( defined $tinfo->{'check'} ) diff --git a/mysql-test/lib/mtr_unique.pm b/mysql-test/lib/mtr_unique.pm index 2ac172883a2..294a5d7b4d6 100644 --- a/mysql-test/lib/mtr_unique.pm +++ b/mysql-test/lib/mtr_unique.pm @@ -188,6 +188,8 @@ sub mtr_release_unique_id($) { flock SEM, LOCK_UN or warn "can't unlock $file.sem"; close SEM; + + delete $mtr_unique_ids{$$}; } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 89eed6a1736..47498026e72 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -180,12 +180,18 @@ our $opt_client_debugger; my $config; # The currently running config my $current_config_name; # The currently running config file template +our $opt_experimental; +our $experimental_test_cases; + my $baseport; my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto"; +my $build_thread= 0; my $opt_record; my $opt_report_features; +my $opt_skip_core; + our $opt_check_testcases= 1; my $opt_mark_progress; @@ -676,14 +682,9 @@ sub run_worker ($) { report_option('name',"worker[$thread_num]"); # -------------------------------------------------------------------------- - # Use auto build thread in all but first worker + # Set different ports per thread # -------------------------------------------------------------------------- - set_build_thread_ports($thread_num > 1 ? 'auto' : $opt_build_thread); - - if (check_ports_free()){ - # Some port was not free(which one has already been printed) - mtr_error("Some port(s) was not free") - } + set_build_thread_ports($thread_num); # -------------------------------------------------------------------------- # Turn off verbosity in workers, unless explicitly specified @@ -803,7 +804,7 @@ sub command_line_setup { 'big-test' => \$opt_big_test, 'combination=s' => \@opt_combinations, 'skip-combinations' => \&collect_option, - + 'experimental=s' => \$opt_experimental, 'skip-im' => \&ignore_option, # Specify ports @@ -943,12 +944,12 @@ sub command_line_setup { } # Look for language files and charsetsdir, use same share - my $path_share= mtr_path_exists("$basedir/share/mysql", - "$basedir/sql/share", - "$basedir/share"); + $path_language= mtr_path_exists("$basedir/share/mysql/english", + "$basedir/sql/share/english", + "$basedir/share/english"); - - $path_language= mtr_path_exists("$path_share/english"); + + my $path_share= dirname($path_language); $path_charsetsdir= mtr_path_exists("$path_share/charsets"); if (using_extern()) @@ -970,6 +971,33 @@ sub command_line_setup { mtr_print_thick_line('#'); } + if ( $opt_experimental ) + { + # read the list of experimental test cases from the file specified on + # the command line + open(FILE, "<", $opt_experimental) or mtr_error("Can't read experimental file: $opt_experimental"); + mtr_report("Using experimental file: $opt_experimental"); + $experimental_test_cases = []; + while() { + chomp; + # remove comments (# foo) at the beginning of the line, or after a + # blank at the end of the line + s/( +|^)#.*$//; + # remove whitespace + s/^ +//; + s/ +$//; + # if nothing left, don't need to remember this line + if ( $_ eq "" ) { + next; + } + # remember what is left as the name of another test case that should be + # treated as experimental + print " - $_\n"; + push @$experimental_test_cases, $_; + } + close FILE; + } + foreach my $arg ( @ARGV ) { if ( $arg =~ /^--skip-/ ) @@ -1093,6 +1121,14 @@ sub command_line_setup { $opt_shutdown_timeout= 0; # Kill processes instead of nice shutdown } + # -------------------------------------------------------------------------- + # Check parallel value + # -------------------------------------------------------------------------- + if ($opt_parallel < 1) + { + mtr_error("0 or negative parallel value makes no sense, use positive number"); + } + # -------------------------------------------------------------------------- # Record flag # -------------------------------------------------------------------------- @@ -1282,18 +1318,32 @@ sub command_line_setup { # But a fairly safe range seems to be 5001 - 32767 # sub set_build_thread_ports($) { - my $build_thread= shift || 0; + my $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"); + if ( lc($opt_build_thread) eq 'auto' ) { + my $found_free = 0; + $build_thread = 250; # Start attempts from here + while (! $found_free) + { + $build_thread= mtr_get_unique_id($build_thread, 299); + if ( !defined $build_thread ) { + mtr_error("Could not get a unique build thread id"); + } + $found_free= check_ports_free($build_thread); + # If not free, release and try from next number + mtr_release_unique_id($build_thread++) unless $found_free; } - #mtr_report(" - got $build_thread"); + } + else + { + $build_thread = $opt_build_thread + $thread - 1; } $ENV{MTR_BUILD_THREAD}= $build_thread; - $opt_build_thread= $build_thread; + + if (! check_ports_free($build_thread)) { + # Some port was not free(which one has already been printed) + mtr_error("Some port(s) was not free") + } # Calculate baseport $baseport= $build_thread * 10 + 10000; @@ -2447,22 +2497,18 @@ sub kill_leftovers ($) { # Check that all the ports that are going to # be used are free # -sub check_ports_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 + my $bthread= shift; + my $portbase = $bthread * 10 + 10000; + for ($portbase..$portbase+9){ + if (mtr_ping_port($_)){ + mtr_report(" - 'localhost:$_' was not free"); + return 0; # One port was not free } } - return 0; # All ports free + return 1; # All ports free } @@ -3484,7 +3530,10 @@ sub start_check_warnings ($$) { my $name= "warnings-".$mysqld->name(); - extract_warning_lines($mysqld->value('log-error')); + my $log_error= $mysqld->value('#log-error'); + # To be communicated to the test + $ENV{MTR_LOG_ERROR}= $log_error; + extract_warning_lines($log_error); my $args; mtr_init_args(\$args); @@ -3961,6 +4010,7 @@ sub mysqld_arguments ($$$) { mtr_add_arg($args, "%s", $arg); } } + $opt_skip_core = $found_skip_core; if ( !$found_skip_core ) { mtr_add_arg($args, "%s", "--core-file"); @@ -4000,6 +4050,12 @@ sub mysqld_start ($$) { $path_vardir_trace, $mysqld->name()); } + if (IS_WINDOWS) + { + # Trick the server to send output to stderr, with --console + mtr_add_arg($args, "--console"); + } + if ( $opt_gdb || $opt_manual_gdb ) { gdb_arguments(\$args, \$exe, $mysqld->name()); @@ -4032,7 +4088,7 @@ sub mysqld_start ($$) { # Remove the old pidfile if any unlink($mysqld->value('pid-file')); - my $output= $mysqld->value('log-error'); + my $output= $mysqld->value('#log-error'); if ( $opt_valgrind and $opt_debug ) { # When both --valgrind and --debug is selected, send @@ -4052,6 +4108,7 @@ sub mysqld_start ($$) { error => $output, append => 1, verbose => $opt_verbose, + nocore => $opt_skip_core, host => undef, shutdown => sub { mysqld_stop($mysqld) }, ); @@ -4104,12 +4161,6 @@ sub server_need_restart { return 0; } - if ( $opt_embedded_server ) - { - mtr_verbose_restart($server, "no start or restart for embedded server"); - return 0; - } - if ( $tinfo->{'force_restart'} ) { mtr_verbose_restart($server, "forced in .opt file"); return 1; @@ -4339,7 +4390,7 @@ sub start_servers($) { # Already started # Write start of testcase to log file - mark_log($mysqld->value('log-error'), $tinfo); + mark_log($mysqld->value('#log-error'), $tinfo); next; } @@ -4398,7 +4449,7 @@ sub start_servers($) { mkpath($tmpdir) unless -d $tmpdir; # Write start of testcase to log file - mark_log($mysqld->value('log-error'), $tinfo); + mark_log($mysqld->value('#log-error'), $tinfo); # Run -master.sh if ($mysqld->option('#!run-master-sh') and @@ -4449,7 +4500,7 @@ sub start_servers($) { $tinfo->{comment}= "Failed to start ".$mysqld->name(); - my $logfile= $mysqld->value('log-error'); + my $logfile= $mysqld->value('#log-error'); if ( defined $logfile and -f $logfile ) { $tinfo->{logfile}= mtr_fromfile($logfile);