Commit 1476a524 authored by kent@mysql.com's avatar kent@mysql.com

mtr_timer.pl, mysql-test-run.pl, mtr_report.pl, mtr_process.pl:

  Added suite and test case timeout
mtr_timer.pl:
  new file
parent adb94df2
...@@ -210,6 +210,7 @@ sub spawn_parent_impl { ...@@ -210,6 +210,7 @@ sub spawn_parent_impl {
# normally from running a test case? # normally from running a test case?
my $exit_value= -1; my $exit_value= -1;
my $saved_exit_value;
my $ret_pid; # What waitpid() returns my $ret_pid; # What waitpid() returns
while ( ($ret_pid= waitpid(-1,0)) != -1 ) while ( ($ret_pid= waitpid(-1,0)) != -1 )
...@@ -219,6 +220,24 @@ sub spawn_parent_impl { ...@@ -219,6 +220,24 @@ sub spawn_parent_impl {
# but not $exit_value, this is flagged from # but not $exit_value, this is flagged from
# #
my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid);
if ( $timer_name )
{
if ( $timer_name eq "suite" )
{
# We give up here
# FIXME we should only give up the suite, not all of the run?
print STDERR "\n";
mtr_error("Test suite timeout");
}
elsif ( $timer_name eq "testcase" )
{
$saved_exit_value= 63; # Mark as timeout
kill(9, $pid); # Kill mysqltest
next; # Go on and catch the termination
}
}
if ( $ret_pid == $pid ) if ( $ret_pid == $pid )
{ {
# We got termination of mysqltest, we are done # We got termination of mysqltest, we are done
...@@ -270,7 +289,7 @@ sub spawn_parent_impl { ...@@ -270,7 +289,7 @@ sub spawn_parent_impl {
} }
} }
return $exit_value; return $saved_exit_value || $exit_value;
} }
} }
else else
......
...@@ -109,7 +109,14 @@ sub mtr_report_test_failed ($) { ...@@ -109,7 +109,14 @@ sub mtr_report_test_failed ($) {
my $tinfo= shift; my $tinfo= shift;
$tinfo->{'result'}= 'MTR_RES_FAILED'; $tinfo->{'result'}= 'MTR_RES_FAILED';
print "[ fail ]\n"; if ( $tinfo->{'timeout'} )
{
print "[ fail ] timeout\n";
}
else
{
print "[ fail ]\n";
}
# FIXME Instead of this test, and meaningless error message in 'else' # FIXME Instead of this test, and meaningless error message in 'else'
# we should write out into $::path_timefile when the error occurs. # we should write out into $::path_timefile when the error occurs.
......
# -*- cperl -*-
# This is a library file used by the Perl version of mysql-test-run,
# and is part of the translation of the Bourne shell script with the
# same name.
use Carp qw(cluck);
use Socket;
use Errno;
use strict;
#use POSIX ":sys_wait_h";
use POSIX 'WNOHANG';
sub mtr_init_timers ();
sub mtr_timer_start($$$);
sub mtr_timer_stop($$);
sub mtr_timer_waitpid($$$);
##############################################################################
#
# Initiate a structure shared by all timers
#
##############################################################################
sub mtr_init_timers () {
my $timers = { timers => {}, pids => {}};
return $timers;
}
##############################################################################
#
# Start, stop and poll a timer
#
# As alarm() isn't portable to Windows, we use separate processes to
# implement timers. That is why there is a mtr_timer_waitpid(), as this
# is where we catch a timeout.
#
##############################################################################
sub mtr_timer_start($$$) {
my ($timers,$name,$duration)= @_;
if ( exists $timers->{'timers'}->{$name} )
{
# We have an old running timer, kill it
mtr_timer_stop($timers,$name);
}
FORK:
{
my $tpid= fork();
if ( ! defined $tpid )
{
if ( $! == $!{EAGAIN} ) # See "perldoc Errno"
{
mtr_debug("Got EAGAIN from fork(), sleep 1 second and redo");
sleep(1);
redo FORK;
}
else
{
mtr_error("can't fork");
}
}
if ( $tpid )
{
# Parent, record the information
$timers->{'timers'}->{$name}->{'pid'}= $tpid;
$timers->{'timers'}->{$name}->{'duration'}= $duration;
$timers->{'pids'}->{$tpid}= $name;
}
else
{
# Child, redirect output and exec
# FIXME do we need to redirect streams?
$0= "mtr_timer(timers,$name,$duration)";
sleep($duration);
exit(0);
}
}
}
sub mtr_timer_stop ($$) {
my ($timers,$name)= @_;
if ( exists $timers->{'timers'}->{$name} )
{
my $tpid= $timers->{'timers'}->{$name}->{'pid'};
# FIXME as Cygwin reuses pids fast, maybe check that is
# the expected process somehow?!
kill(9, $tpid);
# As the timers are so simple programs, we trust them to terminate,
# and use blocking wait for it. We wait just to avoid a zombie.
waitpid($tpid,0);
delete $timers->{'timers'}->{$name}; # Remove the timer information
delete $timers->{'pids'}->{$tpid}; # and PID reference
return 1;
}
else
{
mtr_debug("Asked to stop timer \"$name\" not started");
return 0;
}
}
sub mtr_timer_timeout ($$) {
my ($timers,$pid)= @_;
return "" unless exists $timers->{'pids'}->{$pid};
# We got a timeout
my $name= $timers->{'pids'}->{$pid};
mtr_timer_stop($timers, $timers->{'timers'}->{$name});
return $name;
}
1;
...@@ -90,6 +90,7 @@ use strict; ...@@ -90,6 +90,7 @@ use strict;
require "lib/mtr_cases.pl"; require "lib/mtr_cases.pl";
require "lib/mtr_process.pl"; require "lib/mtr_process.pl";
require "lib/mtr_timer.pl";
require "lib/mtr_io.pl"; require "lib/mtr_io.pl";
require "lib/mtr_gcov.pl"; require "lib/mtr_gcov.pl";
require "lib/mtr_gprof.pl"; require "lib/mtr_gprof.pl";
...@@ -137,6 +138,7 @@ our $glob_mysql_test_dir= undef; ...@@ -137,6 +138,7 @@ our $glob_mysql_test_dir= undef;
our $glob_mysql_bench_dir= undef; our $glob_mysql_bench_dir= undef;
our $glob_hostname= undef; our $glob_hostname= undef;
our $glob_scriptname= undef; our $glob_scriptname= undef;
our $glob_timers= undef;
our $glob_use_running_server= 0; our $glob_use_running_server= 0;
our $glob_use_running_ndbcluster= 0; our $glob_use_running_ndbcluster= 0;
our $glob_use_embedded_server= 0; our $glob_use_embedded_server= 0;
...@@ -232,8 +234,10 @@ our $opt_skip_test; ...@@ -232,8 +234,10 @@ our $opt_skip_test;
our $opt_sleep; our $opt_sleep;
our $opt_ps_protocol; our $opt_ps_protocol;
our $opt_sleep_time_after_restart= 1; our $opt_sleep_time_after_restart= 1;
our $opt_sleep_time_for_delete= 10; our $opt_sleep_time_for_delete= 10;
our $opt_testcase_timeout= 5; # 5 min max
our $opt_suite_timeout= 120; # 2 hours max
our $opt_socket; our $opt_socket;
...@@ -435,6 +439,8 @@ sub initial_setup () { ...@@ -435,6 +439,8 @@ sub initial_setup () {
$path_my_basedir= $path_my_basedir=
$opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir;
$glob_timers= mtr_init_timers();
} }
...@@ -530,6 +536,8 @@ sub command_line_setup () { ...@@ -530,6 +536,8 @@ sub command_line_setup () {
'vardir=s' => \$opt_vardir, 'vardir=s' => \$opt_vardir,
'verbose' => \$opt_verbose, 'verbose' => \$opt_verbose,
'wait-timeout=i' => \$opt_wait_timeout, 'wait-timeout=i' => \$opt_wait_timeout,
'testcase-timeout=i' => \$opt_testcase_timeout,
'suite-timeout=i' => \$opt_suite_timeout,
'warnings|log-warnings' => \$opt_warnings, 'warnings|log-warnings' => \$opt_warnings,
'with-openssl' => \$opt_with_openssl, 'with-openssl' => \$opt_with_openssl,
...@@ -1197,6 +1205,8 @@ sub run_suite () { ...@@ -1197,6 +1205,8 @@ sub run_suite () {
mtr_report("Finding Tests in the '$suite' suite"); mtr_report("Finding Tests in the '$suite' suite");
mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout);
my $tests= collect_test_cases($suite); my $tests= collect_test_cases($suite);
mtr_report("Starting Tests in the '$suite' suite"); mtr_report("Starting Tests in the '$suite' suite");
...@@ -1205,7 +1215,9 @@ sub run_suite () { ...@@ -1205,7 +1215,9 @@ sub run_suite () {
foreach my $tinfo ( @$tests ) foreach my $tinfo ( @$tests )
{ {
mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout);
run_testcase($tinfo); run_testcase($tinfo);
mtr_timer_stop($glob_timers,"testcase");
} }
mtr_print_line(); mtr_print_line();
...@@ -1226,6 +1238,8 @@ sub run_suite () { ...@@ -1226,6 +1238,8 @@ sub run_suite () {
} }
mtr_report_stats($tests); mtr_report_stats($tests);
mtr_timer_stop($glob_timers,"suite");
} }
...@@ -1523,6 +1537,11 @@ sub run_testcase ($) { ...@@ -1523,6 +1537,11 @@ sub run_testcase ($) {
# Testcase itself tell us to skip this one # Testcase itself tell us to skip this one
mtr_report_test_skipped($tinfo); mtr_report_test_skipped($tinfo);
} }
elsif ( $res == 63 )
{
$tinfo->{'timeout'}= 1; # Mark as timeout
report_failure_and_restart($tinfo);
}
else else
{ {
# Test case failed, if in control mysqltest returns 1 # Test case failed, if in control mysqltest returns 1
...@@ -1657,8 +1676,6 @@ sub mysqld_arguments ($$$$$) { ...@@ -1657,8 +1676,6 @@ sub mysqld_arguments ($$$$$) {
my $extra_opt= shift; my $extra_opt= shift;
my $slave_master_info= shift; my $slave_master_info= shift;
# print STDERR Dumper($extra_opt);
my $sidx= ""; # Index as string, 0 is empty string my $sidx= ""; # Index as string, 0 is empty string
if ( $idx > 0 ) if ( $idx > 0 )
{ {
...@@ -2262,6 +2279,10 @@ Misc options ...@@ -2262,6 +2279,10 @@ Misc options
help Get this help text help Get this help text
unified-diff | udiff When presenting differences, use unified diff unified-diff | udiff When presenting differences, use unified diff
testcase-timeout=MINUTES Max test case run time (default 5)
suite-timeout=MINUTES Max test suite run time (default 120)
Options not yet described, or that I want to look into more Options not yet described, or that I want to look into more
big-test big-test
...@@ -2281,4 +2302,5 @@ Options not yet described, or that I want to look into more ...@@ -2281,4 +2302,5 @@ Options not yet described, or that I want to look into more
HERE HERE
mtr_exit(1); mtr_exit(1);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment