summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <msvensson@pilot.mysql.com>2008-04-24 13:02:53 +0200
committerunknown <msvensson@pilot.mysql.com>2008-04-24 13:02:53 +0200
commitadc257481c543b978018c0e0cf640fc2cb3f61eb (patch)
tree2f87d7c7149d89733058436d02f5bbf0b4dcb5b7
parent3536675068b1615d1d8e0359421c81d143a6d56c (diff)
downloadmariadb-git-adc257481c543b978018c0e0cf640fc2cb3f61eb.tar.gz
Add support for running in parallel
mysql-test/lib/My/Options.pm: Allow $VAR as option mysql-test/lib/My/SafeProcess.pm: Remove printouts mysql-test/lib/My/Test.pm: New BitKeeper file ``mysql-test/lib/My/Test.pm''
-rw-r--r--mysql-test/lib/My/Options.pm3
-rw-r--r--mysql-test/lib/My/SafeProcess.pm6
-rw-r--r--mysql-test/lib/My/Test.pm122
-rw-r--r--mysql-test/lib/mtr_cases.pm103
-rw-r--r--mysql-test/lib/mtr_report.pm126
-rwxr-xr-xmysql-test/mysql-test-run.pl576
6 files changed, 678 insertions, 258 deletions
diff --git a/mysql-test/lib/My/Options.pm b/mysql-test/lib/My/Options.pm
index f0fc4ba75b5..40f05c41d1c 100644
--- a/mysql-test/lib/My/Options.pm
+++ b/mysql-test/lib/My/Options.pm
@@ -61,6 +61,9 @@ sub _split_option {
elsif ($option=~ /^--(.*)$/){
return ($1, undef)
}
+ elsif ($option=~ /^\$(.*)$/){ # $VAR
+ return ($1, undef)
+ }
elsif ($option=~ /^(.*)=(.*)$/){
return ($1, $2)
}
diff --git a/mysql-test/lib/My/SafeProcess.pm b/mysql-test/lib/My/SafeProcess.pm
index 4d703d73b9a..eccc0fcdeed 100644
--- a/mysql-test/lib/My/SafeProcess.pm
+++ b/mysql-test/lib/My/SafeProcess.pm
@@ -65,7 +65,7 @@ END {
# Kill any children still running
for my $proc (values %running){
if ( $proc->is_child($$) ){
- print "Killing: $proc\n";
+ #print "Killing: $proc\n";
$proc->kill();
}
}
@@ -461,8 +461,8 @@ sub wait_one {
return 1;
}
- warn "wait_one: expected pid $pid but got $retpid"
- unless( $retpid == $pid );
+ #warn "wait_one: expected pid $pid but got $retpid"
+ # unless( $retpid == $pid );
$self->_collect();
return 0;
diff --git a/mysql-test/lib/My/Test.pm b/mysql-test/lib/My/Test.pm
new file mode 100644
index 00000000000..890ae76b282
--- /dev/null
+++ b/mysql-test/lib/My/Test.pm
@@ -0,0 +1,122 @@
+# -*- cperl -*-
+
+
+#
+# One test
+#
+package My::Test;
+
+use strict;
+use warnings;
+use Carp;
+
+
+sub new {
+ my $class= shift;
+ my $self= bless {
+ @_,
+ }, $class;
+ return $self;
+}
+
+
+#
+# Return a unique key that can be used to
+# identify this test in a hash
+#
+sub key {
+ my ($self)= @_;
+ my $key= $self->{name};
+ $key.= "+".$self->{combination} if $self->{combination};
+ return $key;
+}
+
+
+sub _encode {
+ my ($value)= @_;
+ $value =~ s/([|\\\x{0a}\x{0d}])/sprintf('\%02X', ord($1))/eg;
+ return $value;
+}
+
+sub _decode {
+ my ($value)= @_;
+ $value =~ s/\\([0-9a-fA-F]{2})/chr(hex($1))/ge;
+ return $value;
+}
+
+sub is_failed {
+ my ($self)= @_;
+ my $result= $self->{result};
+ croak "'is_failed' can't be called until test has been run!"
+ unless defined $result;
+
+ return ($result eq 'MTR_RES_FAILED');
+}
+
+
+sub write_test {
+ my ($test, $sock, $header)= @_;
+
+ print $sock $header, "\n";
+ while ((my ($key, $value)) = each(%$test)) {
+ print $sock $key, "= ";
+ if (ref $value eq "ARRAY") {
+ print $sock "[", _encode(join(", ", @$value)), "]";
+ } else {
+ print $sock _encode($value);
+ }
+ print $sock "\n";
+ }
+ print $sock "\n";
+}
+
+
+sub read_test {
+ my ($sock)= @_;
+ my $test= My::Test->new();
+ # Read the : separated key value pairs until a
+ # single newline on it's own line
+ my $line;
+ while (defined($line= <$sock>)) {
+ # List is terminated by newline on it's own
+ if ($line eq "\n") {
+ # Correctly terminated reply
+ # print "Got newline\n";
+ last;
+ }
+ chomp($line);
+
+ # Split key/value on the first "="
+ my ($key, $value)= split("= ", $line, 2);
+
+ if ($value =~ /^\[(.*)\]/){
+ my @values= split(", ", _decode($1));
+ push(@{$test->{$key}}, @values);
+ }
+ else
+ {
+ $test->{$key}= _decode($value);
+ }
+ }
+ return $test;
+}
+
+
+sub print_test {
+ my ($self)= @_;
+
+ print "[", $self->{name}, "]", "\n";
+ while ((my ($key, $value)) = each(%$self)) {
+ print " ", $key, "= ";
+ if (ref $value eq "ARRAY") {
+ print "[", join(", ", @$value), "]";
+ } else {
+ print $value;
+ }
+ print "\n";
+ }
+ print "\n";
+}
+
+
+1;
diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm
index 0f8329f2f31..4e10066c176 100644
--- a/mysql-test/lib/mtr_cases.pm
+++ b/mysql-test/lib/mtr_cases.pm
@@ -40,7 +40,7 @@ our $default_storage_engine;
our $opt_with_ndbcluster_only;
our $defaults_file;
our $defaults_extra_file;
-our $reorder;
+our $reorder= 1;
sub collect_option {
my ($opt, $value)= @_;
@@ -55,6 +55,7 @@ use File::Basename;
use IO::File();
use My::Config;
use My::Platform;
+use My::Test;
use My::Find;
require "mtr_misc.pl";
@@ -135,52 +136,16 @@ sub collect_test_cases ($$) {
{
my @criteria = ();
- # Look for tests that must be run in a defined order - that is
- # defined by test having the same name except for the ending digit
+ #
+ # Append the criteria for sorting, in order of importance.
+ #
+ push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "A" : "B"));
+ # Group test with equal options together.
+ # Ending with "~" makes empty sort later than filled
+ my $opts= $tinfo->{'master_opt'} ? $tinfo->{'master_opt'} : [];
+ push(@criteria, join("!", sort @{$opts}) . "~");
- # Put variables into hash
- my $test_name= $tinfo->{'name'};
- my $depend_on_test_name;
- if ( $test_name =~ /^([\D]+)([0-9]{1})$/ )
- {
- my $base_name= $1;
- my $idx= $2;
- mtr_verbose("$test_name => $base_name idx=$idx");
- if ( $idx > 1 )
- {
- $idx-= 1;
- $base_name= "$base_name$idx";
- mtr_verbose("New basename $base_name");
- }
-
- foreach my $tinfo2 (@$cases)
- {
- if ( $tinfo2->{'name'} eq $base_name )
- {
- mtr_verbose("found dependent test $tinfo2->{'name'}");
- $depend_on_test_name=$base_name;
- }
- }
- }
-
- if ( defined $depend_on_test_name )
- {
- mtr_verbose("Giving $test_name same critera as $depend_on_test_name");
- $sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name};
- }
- else
- {
- #
- # Append the criteria for sorting, in order of importance.
- #
- push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0"));
- # Group test with equal options together.
- # Ending with "~" makes empty sort later than filled
- my $opts= $tinfo->{'master_opt'} ? $tinfo->{'master_opt'} : [];
- push(@criteria, join("!", sort @{$opts}) . "~");
-
- $sort_criteria{$test_name} = join(" ", @criteria);
- }
+ $sort_criteria{$tinfo->{name}} = join(" ", @criteria);
}
@$cases = sort {
@@ -454,7 +419,7 @@ sub collect_one_suite($)
}
# Copy test options
- my $new_test= {};
+ my $new_test= My::Test->new();
while (my ($key, $value) = each(%$test)) {
if (ref $value eq "ARRAY") {
push(@{$new_test->{$key}}, @$value);
@@ -682,13 +647,16 @@ sub collect_one_test_case {
# ----------------------------------------------------------------------
# Set defaults
# ----------------------------------------------------------------------
- my $tinfo= {};
- $tinfo->{'name'}= $suitename . ".$tname";
- $tinfo->{'path'}= "$testdir/$filename";
+ my $tinfo= My::Test->new
+ (
+ name => "$suitename.$tname",
+ path => "$testdir/$filename",
- # TODO allow nonexistsing result file
- # in that case .test must issue "exit" otherwise test should fail by default
- $tinfo->{'result_file'}= "$resdir/$tname.result";
+ # TODO allow nonexistsing result file
+ # in that case .test must issue "exit" otherwise test
+ # should fail by default
+ result_file => "$resdir/$tname.result",
+ );
# ----------------------------------------------------------------------
# Skip some tests but include in list, just mark them as skipped
@@ -1034,19 +1002,6 @@ sub unspace {
}
-
-sub envsubst {
- my $string= shift;
-
- if ( ! defined $ENV{$string} )
- {
- mtr_error(".opt file references '$string' which is not set");
- }
-
- return $ENV{$string};
-}
-
-
sub opts_from_file ($) {
my $file= shift;
@@ -1083,10 +1038,6 @@ sub opts_from_file ($) {
or $arg =~ s/^([^\'\"]*)\"(.*)\"([^\'\"]*)$/$1$2$3/;
$arg =~ s/\\\\/\\/g;
- # Expand environment variables
- $arg =~ s/\$\{(\w+)\}/envsubst($1)/ge;
- $arg =~ s/\$(\w+)/envsubst($1)/ge;
-
# Do not pass empty string since my_getopt is not capable to handle it.
if (length($arg)) {
push(@args, $arg);
@@ -1102,17 +1053,7 @@ sub print_testcases {
print "=" x 60, "\n";
foreach my $test (@cases){
- print "[", $test->{name}, "]", "\n";
- while ((my ($key, $value)) = each(%$test)) {
- print " ", $key, "= ";
- if (ref $value eq "ARRAY") {
- print "[", join(", ", @$value), "]";
- } else {
- print $value;
- }
- print "\n";
- }
- print "\n";
+ $test->print_test();
}
print "=" x 60, "\n";
}
diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm
index a3c0f26c8fd..f749168c64a 100644
--- a/mysql-test/lib/mtr_report.pm
+++ b/mysql-test/lib/mtr_report.pm
@@ -27,7 +27,7 @@ our @EXPORT= qw(report_option mtr_print_line mtr_print_thick_line
mtr_warning mtr_error mtr_debug mtr_verbose
mtr_verbose_restart mtr_report_test_passed
mtr_report_test_failed mtr_report_test_skipped
- mtr_report_stats);
+ mtr_report_stats mtr_report_test);
use mtr_match;
require "mtr_io.pl";
@@ -35,6 +35,10 @@ require "mtr_io.pl";
my $tot_real_time= 0;
our $timestamp= 0;
+our $name;
+our $verbose;
+our $verbose_restart= 0;
+
sub report_option {
my ($opt, $value)= @_;
@@ -43,6 +47,8 @@ sub report_option {
$opt =~ s/-/_/;
no strict 'refs';
${$opt}= $value;
+
+ #print $name, " setting $opt to ", (defined $value? $value : "undef") ,"\n";
}
sub SHOW_SUITE_NAME() { return 1; };
@@ -51,6 +57,8 @@ sub _mtr_report_test_name ($) {
my $tinfo= shift;
my $tname= $tinfo->{name};
+ return unless defined $verbose;
+
# Remove suite part of name
$tname =~ s/.*\.// unless SHOW_SUITE_NAME;
@@ -58,7 +66,7 @@ sub _mtr_report_test_name ($) {
$tname.= " '$tinfo->{combination}'"
if defined $tinfo->{combination};
- print _timestamp();
+ print $name, _timestamp();
printf "%-30s ", $tname;
}
@@ -100,12 +108,19 @@ sub mtr_report_test_passed ($$) {
$timer= mtr_fromfile("$::opt_vardir/log/timer");
$tot_real_time += ($timer/1000);
$timer= sprintf "%12s", $timer;
+ $tinfo->{timer}= $timer;
}
# Set as passed unless already set
if ( not defined $tinfo->{'result'} ){
$tinfo->{'result'}= 'MTR_RES_PASSED';
}
mtr_report("[ pass ] $timer");
+
+ # Show any problems check-testcase found
+ if ( defined $tinfo->{'check'} )
+ {
+ mtr_report($tinfo->{'check'});
+ }
}
@@ -143,9 +158,7 @@ sub mtr_report_test_failed ($$) {
{
# Test failure was detected by test tool and its report
# about what failed has been saved to file. Display the report.
- print "\n";
- mtr_printfile($logfile);
- print "\n";
+ $tinfo->{logfile}= mtr_fromfile($logfile);
}
else
{
@@ -156,6 +169,83 @@ sub mtr_report_test_failed ($$) {
}
+sub mtr_report_test ($) {
+ my ($tinfo)= @_;
+ _mtr_report_test_name($tinfo);
+
+ if ($tinfo->{'result'} eq 'MTR_RES_FAILED'){
+
+ #my $test_failures= $tinfo->{'failures'} || 0;
+ #$tinfo->{'failures'}= $test_failures + 1;
+ if ( defined $tinfo->{'warnings'} )
+ {
+ mtr_report("[ fail ] Found warnings in server log file!");
+ mtr_report($tinfo->{'warnings'});
+ return;
+ }
+ if ( defined $tinfo->{'timeout'} )
+ {
+ mtr_report("[ fail ] timeout");
+ return;
+ }
+ else
+ {
+ mtr_report("[ fail ]");
+ }
+
+ if ( $tinfo->{'comment'} )
+ {
+ # 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"
+ mtr_report("\nERROR: $tinfo->{'comment'}");
+ }
+ elsif ( $tinfo->{logfile} )
+ {
+ # Test failure was detected by test tool and its report
+ # about what failed has been saved to file. Display the report.
+ mtr_report("\n");
+ mtr_report($tinfo->{logfile}, "\n");
+
+ }
+ else
+ {
+ # Neither this script or the test tool has recorded info
+ # about why the test has failed. Should be debugged.
+ mtr_report("\nUnexpected termination, probably when starting mysqld");;
+ }
+ }
+ elsif ($tinfo->{'result'} eq 'MTR_RES_SKIPPED')
+ {
+ if ( $tinfo->{'disable'} )
+ {
+ mtr_report("[ disabled ] $tinfo->{'comment'}");
+ }
+ elsif ( $tinfo->{'comment'} )
+ {
+ if ( $tinfo->{skip_detected_by_test} )
+ {
+ mtr_report("[ skip ]. $tinfo->{'comment'}");
+ }
+ else
+ {
+ mtr_report("[ skip ] $tinfo->{'comment'}");
+ }
+ }
+ else
+ {
+ mtr_report("[ skip ]");
+ }
+ }
+ elsif ($tinfo->{'result'} eq 'MTR_RES_PASSED')
+ {
+ my $timer= $tinfo->{timer} || "";
+ mtr_report("[ pass ] $timer");
+ }
+
+}
+
+
sub mtr_report_stats ($) {
my $tests= shift;
@@ -342,35 +432,42 @@ sub _timestamp {
# Print message to screen
sub mtr_report (@) {
- print join(" ", @_), "\n";
+ if (defined $verbose)
+ {
+ print join(" ", @_), "\n";
+ }
}
# Print warning to screen
sub mtr_warning (@) {
- print STDERR _timestamp(), "mysql-test-run: WARNING: ", join(" ", @_), "\n";
+ print STDERR $name, _timestamp(),
+ "mysql-test-run: WARNING: ", join(" ", @_), "\n";
}
# Print error to screen and then exit
sub mtr_error (@) {
- print STDERR _timestamp(), "mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
+ print STDERR $name, _timestamp(),
+ "mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
exit(1);
}
sub mtr_debug (@) {
- if ( $::opt_verbose > 1 )
+ if ( $verbose > 2 )
{
- print STDERR _timestamp(), "####: ", join(" ", @_), "\n";
+ print STDERR $name,
+ _timestamp(), "####: ", join(" ", @_), "\n";
}
}
sub mtr_verbose (@) {
- if ( $::opt_verbose )
+ if ( $verbose )
{
- print STDERR _timestamp(), "> ",join(" ", @_),"\n";
+ print STDERR $name, _timestamp(),
+ "> ",join(" ", @_),"\n";
}
}
@@ -378,9 +475,10 @@ sub mtr_verbose (@) {
sub mtr_verbose_restart (@) {
my ($server, @args)= @_;
my $proc= $server->{proc};
- if ( $::opt_verbose_restart )
+ if ( $verbose_restart )
{
- print STDERR _timestamp(), "> Restart $proc - ",join(" ", @args),"\n";
+ print STDERR $name,_timestamp(),
+ "> Restart $proc - ",join(" ", @args),"\n";
}
}
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index cf23d63ee13..3b252b9dde3 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -51,6 +51,8 @@ use My::Find;
use mtr_cases;
use mtr_report;
use mtr_match;
+use IO::Socket::INET;
+use IO::Select;
require "lib/mtr_process.pl";
require "lib/mtr_io.pl";
@@ -88,7 +90,6 @@ my $DEFAULT_SUITES= "main,binlog,federated,rpl,rpl_ndb,ndb";
my $opt_suites;
our $opt_verbose= 0; # Verbose output, enable with --verbose
-our $opt_verbose_restart= 0; # Verbose output for restarts
our $exe_mysql;
our $exe_mysqladmin;
@@ -141,7 +142,7 @@ my $config; # The currently running config
my $current_config_name; # The currently running config file template
my $opt_baseport;
-my $opt_mtr_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto";
+my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto";
my $opt_record;
my $opt_report_features;
@@ -161,6 +162,8 @@ my $opt_repeat= 1;
my $opt_retry= 3;
my $opt_retry_failure= 2;
+my $opt_parallel= 1;
+
my $opt_strace_client;
our $opt_timer= 1;
@@ -203,25 +206,46 @@ main();
sub main {
- command_line_setup();
+ # 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));
- mtr_report("Checking supported features...");
+ Getopt::Long::Configure("pass_through");
+ GetOptions('parallel=i' => \$opt_parallel) or usage("Can't read options");
- check_ndbcluster_support(\%mysqld_variables);
- check_ssl_support(\%mysqld_variables);
- check_debug_support(\%mysqld_variables);
+ # 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
+ run_worker($server_port, $child_num);
+ exit(1);
+ }
- executable_setup();
+ mtr_report("Started worker, pid: $child_pid");
+ $children{$child_pid}= 1;
+ }
- environment_setup();
+ command_line_setup(0);
- if ( $opt_gcov )
- {
+ if ( $opt_gcov ) {
gcov_prepare();
}
- if (!$opt_suites)
- {
+ if (!$opt_suites) {
$opt_suites= $DEFAULT_SUITES;
# Check for any extra suites to enable based on the path name
@@ -235,10 +259,9 @@ sub main {
"mysql-6.0-ndb" => "ndb_team",
);
- foreach my $dir ( reverse splitdir($basedir) )
- {
+ foreach my $dir ( reverse splitdir($basedir) ) {
my $extra_suite= $extra_suites{$dir};
- if (defined $extra_suite){
+ if (defined $extra_suite) {
mtr_report("Found extra suite: $extra_suite");
$opt_suites= "$extra_suite,$opt_suites";
last;
@@ -249,26 +272,289 @@ sub main {
mtr_report("Collecting tests...");
my $tests= collect_test_cases($opt_suites, \@opt_cases);
- initialize_servers();
-
if ( $opt_report_features ) {
# Put "report features" as the first test to run
- my $tinfo = {};
- $tinfo->{'name'} = 'report_features';
- $tinfo->{'result_file'} = undef; # Prints result
- $tinfo->{'path'} = 'include/report-features.test';
- $tinfo->{'master_opt'} = [];
- $tinfo->{'slave_opt'} = [];
+ my $tinfo = My::Test->new
+ (
+ name => 'report_features',
+ result_file => undef, # Prints result
+ path => 'include/report-features.test'.
+ master_opt => [],
+ slave_opt => [],
+ );
unshift(@$tests, $tinfo);
}
+ initialize_servers();
+
+ mtr_report();
+ mtr_print_thick_line();
+ mtr_print_header();
+
+ 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)
+ {
+ my $ret_pid= waitpid($pid, 0);
+ if ($ret_pid != $pid){
+ mtr_report("Unknown process $ret_pid exited");
+ }
+ else {
+ delete $children{$ret_pid};
+ }
+ }
+
+ mtr_verbose("Server exit\n");
+
+ mtr_print_line();
+
+ mtr_report_stats($completed);
+
+ exit(0);
+}
+
+
+sub run_test_server {
+ my ($server, $tests, $childs) = @_;
+
+ # Scheduler variables
+ my $max_ndb= $opt_parallel / 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 $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){
+ 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() and !$opt_force){
+ # Test has failed, force is off
+ push(@$completed, $result);
+ return $completed;
+ }
+
+ # Retry test run after test failure
+ my $retries= $result->{retries} || 1;
+ 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("Test has failed $failures times,",
+ "no more retries!\n");
+ }
+ else {
+ mtr_report("\nRetrying test, attempt($retries/$opt_retry)...\n");
+ $result->{retries}= $retries+1;
+ $result->write_test($sock, 'TESTCASE');
+ next;
+ }
+ }
+
+ # Repeat test $opt_repeat number of times
+ my $repeat= $result->{repeat} || 1;
+ if ($repeat < $opt_repeat)
+ {
+ $result->{retries}= 0;
+ $result->{failures}= 0;
+
+ $result->{repeat}= $repeat+1;
+ $result->write_test($sock, 'TESTCASE');
+ next;
+ }
+
+ # Remove from list of running
+ mtr_error("'", $result->{name},"' is not known to be running")
+ unless delete $running{$result->key()};
+
+ # Update scheduler variables
+ $num_ndb_tests-- if ($result->{ndb_test});
+
+ # Save result in completed list
+ push(@$completed, $result);
+
+ }
+ 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];
+
+ 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));
+ redo; # Start over again
+ }
+
+ # 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")
+ 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";
+ }
+ }
+ }
+ }
+}
+
+
+sub run_worker ($) {
+ my ($server_port, $thread_num)= @_;
+
+ $SIG{INT}= sub { exit(1); };
+
+ report_option('name',"worker[$thread_num]");
+
+ # 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;
+
+ # Read hello from server which it will send when shared
+ # resources have been setup
+ my $hello= <$server>;
+
+ command_line_setup($thread_num);
+
+ if ( $opt_gcov )
+ {
+ gcov_prepare();
+ }
+
+ setup_vardir();
+ mysql_install_db($thread_num);
+
if ( using_extern() ) {
create_config_file_for_extern(%opts_extern);
}
- run_tests($tests);
+ # Ask server for first test
+ print $server "START\n";
- exit(0);
+ while(my $line= <$server>){
+ chomp($line);
+ if ($line eq 'TESTCASE'){
+ my $test= My::Test::read_test($server);
+ #$test->print_test();
+ 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'");
+ }
+ }
+
+ stop_all_servers();
+
+ if ( $opt_gcov )
+ {
+ gcov_collect(); # collect coverage information
+ }
+
+ if ( $opt_gcov )
+ {
+ gcov_collect(); # collect coverage information
+ }
+
+ exit(1);
}
@@ -278,14 +564,11 @@ sub ignore_option {
}
sub command_line_setup {
+ my ($thread_num)= @_;
+
my $opt_comment;
my $opt_usage;
- # 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));
-
# 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");
@@ -325,7 +608,7 @@ sub command_line_setup {
'skip-im' => \&ignore_option,
# Specify ports
- 'build-thread|mtr-build-thread=i' => \$opt_mtr_build_thread,
+ 'build-thread|mtr-build-thread=i' => \$opt_build_thread,
# Test case authoring
'record' => \$opt_record,
@@ -383,10 +666,10 @@ sub command_line_setup {
'report-features' => \$opt_report_features,
'comment=s' => \$opt_comment,
'fast' => \$opt_fast,
- 'reorder' => \&collect_option,
+ 'reorder!' => \&collect_option,
'enable-disabled' => \&collect_option,
'verbose+' => \$opt_verbose,
- 'verbose-restart' => \$opt_verbose_restart,
+ 'verbose-restart' => \&report_option,
'sleep=i' => \$opt_sleep,
'start-dirty' => \$opt_start_dirty,
'start' => \$opt_start,
@@ -408,9 +691,21 @@ sub command_line_setup {
usage("") if $opt_usage;
# --------------------------------------------------------------------------
- # Check mtr_build_thread and calculate baseport
+ # Setup verbosity
# --------------------------------------------------------------------------
- set_mtr_build_thread_ports($opt_mtr_build_thread);
+ if ($thread_num == 0){
+ # The server should by default have verbose on
+ report_option('verbose', $opt_verbose ? $opt_verbose : 0);
+ } else {
+ # Worker should by default have verbose off
+ report_option('verbose', $opt_verbose ? $opt_verbose : undef);
+ }
+
+ # --------------------------------------------------------------------------
+ # Check build_thread and calculate baseport
+ # Use auto build thread in all but first worker
+ # --------------------------------------------------------------------------
+ set_build_thread_ports($thread_num > 1 ? 'auto' : $opt_build_thread);
if ( -d "../sql" )
{
@@ -537,8 +832,9 @@ sub command_line_setup {
# --------------------------------------------------------------------------
# Check if we should speed up tests by trying to run on tmpfs
+ # - Dont check in workers
# --------------------------------------------------------------------------
- if ( defined $opt_mem )
+ if ( defined $opt_mem and $thread_num == 0)
{
mtr_error("Can't use --mem and --vardir at the same time ")
if $opt_vardir;
@@ -554,7 +850,7 @@ sub command_line_setup {
{
if ( -d $fs )
{
- my $template= "var_${opt_mtr_build_thread}_XXXX";
+ my $template= "var_${opt_build_thread}_XXXX";
$opt_mem= tempdir( $template, DIR => $fs, CLEANUP => 0);
last;
}
@@ -569,21 +865,11 @@ sub command_line_setup {
{
$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 ( ! IS_WINDOWS )
- {
- # 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;
- }
+ # If more than one parallel run, use a subdir of the selected var
+ if ($thread_num && $opt_parallel > 1) {
+ $opt_vardir.= "/".$thread_num;
+ }
$path_vardir_trace= $opt_vardir;
# Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/...
@@ -738,6 +1024,16 @@ sub command_line_setup {
$path_testlog= "$opt_vardir/log/mysqltest.log";
$path_current_testlog= "$opt_vardir/log/current_test";
+ mtr_report("Checking supported features...");
+
+ check_ndbcluster_support(\%mysqld_variables);
+ check_ssl_support(\%mysqld_variables);
+ check_debug_support(\%mysqld_variables);
+
+ executable_setup();
+
+ environment_setup();
+
}
@@ -756,19 +1052,20 @@ 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 || 0;
+sub set_build_thread_ports($) {
+ my $build_thread= shift || 0;
- if ( lc($mtr_build_thread) eq 'auto' ) {
- print "Requesting build thread... ";
- $mtr_build_thread=
+ if ( lc($build_thread) eq 'auto' ) {
+ mtr_report("Requesting build thread... ");
+ $build_thread=
mtr_require_unique_id_and_wait("/tmp/mysql-test-ports", 200, 299);
- print "got ".$mtr_build_thread."\n";
+ mtr_report(" - got $build_thread");
}
- $ENV{MTR_BUILD_THREAD}= $mtr_build_thread;
+ $ENV{MTR_BUILD_THREAD}= $build_thread;
+ $opt_build_thread= $build_thread;
# Calculate baseport
- $opt_baseport= $mtr_build_thread * 10 + 10000;
+ $opt_baseport= $build_thread * 10 + 10000;
if ( $opt_baseport < 5001 or $opt_baseport + 9 >= 32767 )
{
mtr_error("MTR_BUILD_THREAD number results in a port",
@@ -776,7 +1073,7 @@ sub set_mtr_build_thread_ports($) {
"($opt_baseport - $opt_baseport + 9)");
}
- mtr_report("Using MR_BUILD_THREAD $mtr_build_thread,",
+ mtr_report("Using MTR_BUILD_THREAD $build_thread,",
"with reserved ports $opt_baseport..".($opt_baseport+9));
}
@@ -1383,7 +1680,7 @@ sub remove_stale_vardir () {
# Create var and the directories needed in var
#
sub setup_vardir() {
- mtr_report("Creating var directory...");
+ mtr_report("Creating var directory '$opt_vardir'...");
if ( $opt_vardir eq $default_vardir )
{
@@ -1773,76 +2070,6 @@ sub ndbcluster_start ($) {
}
-#
-# Run the collected tests
-#
-my $suite_timeout_proc;
-sub run_tests {
- my ($tests)= @_;
-
- mtr_report();
- mtr_print_thick_line();
- mtr_print_header();
-
- $suite_timeout_proc= My::SafeProcess->timer($opt_suite_timeout* 60);
- foreach my $tinfo ( @$tests )
- {
- if (run_testcase_check_skip_test($tinfo))
- {
- next;
- }
-
- for my $repeat (1..$opt_repeat){
-
- if (run_testcase($tinfo))
- {
- # Testcase failed, enter retry mode
- my $retries= 1;
- while ($retries < $opt_retry){
- mtr_report("\nRetrying, attempt($retries/$opt_retry)...\n");
-
- if (run_testcase($tinfo) <= 0)
- {
- # Testcase suceeded
-
- my $test_has_failed= $tinfo->{failures} || 0;
- if (!$test_has_failed){
- last;
- }
- }
- else
- {
- # Testcase failed
-
- # Limit number of test failures
- my $failures= $tinfo->{failures};
- if ($opt_retry > 1 and $failures >= $opt_retry_failure){
- mtr_report("Test has failed $failures times, no more retries!\n");
- last;
- }
- }
- $retries++;
- }
- }
- }
- }
- # Kill the test suite timer
- $suite_timeout_proc->kill();
-
- mtr_print_line();
-
- stop_all_servers();
-
- if ( $opt_gcov )
- {
- gcov_collect(); # collect coverage information
- }
-
- mtr_report_stats($tests);
-
-}
-
-
sub create_config_file_for_extern {
my %opts=
(
@@ -1990,7 +2217,7 @@ sub initialize_servers {
remove_stale_vardir();
setup_vardir();
- mysql_install_db();
+ mysql_install_db(0);
}
}
check_running_as_root();
@@ -2044,6 +2271,7 @@ sub sql_to_bootstrap {
sub mysql_install_db {
+ my ($thread_num)= @_;
my $data_dir= "$opt_vardir/install.db";
mtr_report("Installing system database...");
@@ -2080,6 +2308,8 @@ sub mysql_install_db {
# ----------------------------------------------------------------------
$ENV{'MYSQLD_BOOTSTRAP_CMD'}= "$exe_mysqld_bootstrap " . join(" ", @$args);
+ return if $thread_num > 0; # Only generate MYSQLD_BOOTSTRAP_CMD in workers
+
# ----------------------------------------------------------------------
# Create the bootstrap.sql file
# ----------------------------------------------------------------------
@@ -2387,7 +2617,7 @@ sub run_testcase ($) {
# ----------------------------------------------------------------------
if ( $opt_start or $opt_start_dirty )
{
- $suite_timeout_proc->kill();
+# MASV $suite_timeout_proc->kill();
mtr_report("\nStarted", started(all_servers()));
mtr_report("Waiting for server(s) to exit...");
my $proc= My::SafeProcess->wait_any();
@@ -2538,11 +2768,12 @@ sub run_testcase ($) {
# ----------------------------------------------------
# Check if test suite timer expired
# ----------------------------------------------------
- if ( $proc eq $suite_timeout_proc )
- {
- mtr_report("Test suite timeout! Terminating...");
- exit(1);
- }
+# MASV
+# if ( $proc eq $suite_timeout_proc )
+# {
+# mtr_report("Test suite timeout! Terminating...");
+# exit(1);
+# }
mtr_error("Unhandled process $proc exited");
}
@@ -2617,7 +2848,7 @@ sub check_warnings ($) {
my $res= 0;
# Clear previous warnings
- $tinfo->{warnings}= undef;
+ delete($tinfo->{warnings});
# Parallell( mysqlds(), run_check_warning, check_warning_failed);
foreach my $mysqld ( mysqlds() )
@@ -2727,18 +2958,14 @@ sub report_failure_and_restart ($) {
my $tinfo= shift;
mtr_report_test_failed($tinfo, $path_current_testlog);
- print "\n";
- if ( $opt_force )
- {
- # Stop all servers that are known to be running
- stop_all_servers();
- after_test_failure($tinfo->{'name'});
- mtr_report("Resuming tests...\n");
- return;
- }
- mtr_error("Test '$tinfo->{'name'}' failed.",
- "To continue, re-run with '--force'");
+ # Stop all servers that are known to be running
+ stop_all_servers();
+
+ # Collect and clean files
+ after_test_failure($tinfo->{'name'});
+
+ mtr_report("Resuming tests...\n");
}
@@ -3118,12 +3345,32 @@ sub started { return grep(defined $_, map($_->{proc}, @_)); }
sub stopped { return grep(!defined $_, map($_->{proc}, @_)); }
+sub envsubst {
+ my $string= shift;
+
+ if ( ! defined $ENV{$string} )
+ {
+ mtr_error(".opt file references '$string' which is not set");
+ }
+
+ return $ENV{$string};
+}
+
+
sub get_extra_opts {
my ($mysqld, $tinfo)= @_;
- return
+ my $opts=
$mysqld->option("#!use-slave-opt") ?
$tinfo->{slave_opt} : $tinfo->{master_opt};
+
+ # Expand environment variables
+ foreach my $opt ( @$opts )
+ {
+ $opt =~ s/\$\{(\w+)\}/envsubst($1)/ge;
+ $opt =~ s/\$(\w+)/envsubst($1)/ge;
+ }
+ return $opts;
}
@@ -3227,7 +3474,12 @@ sub start_servers($) {
}
# Copy datadir from installed system db
- copytree("$opt_vardir/install.db", $datadir)
+ 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;
# Write start of testcase to log file
@@ -3332,16 +3584,20 @@ sub run_check_testcase ($$$) {
if ( $mode eq "after" and $res == 1 )
{
- mtr_report("\nThe check of testcase '$tname' failed, this is the\n",
- "diff between before and after:\n");
- # Test failed, display the report mysqltest has created
- mtr_printfile($errfile);
+ # Test failed, grab the report mysqltest has created
+ my $report= mtr_grab_file($errfile);
+ $tinfo->{check}.=
+ "\nThe check of testcase '$tname' failed, this is the\n".
+ "diff between before and after:\n";
+ $tinfo->{check}.= $report;
+
}
elsif ( $res )
{
- mtr_report("\nCould not execute 'check-testcase' $mode testcase '$tname':");
- mtr_printfile($errfile);
- mtr_report();
+ my $report= mtr_grab_file($errfile);
+ $tinfo->{'check'}.=
+ "\nCould not execute 'check-testcase' $mode testcase '$tname':\n";
+ $tinfo->{check}.= $report;
}
return $res;
}