2010-11-02 15:01:32 -04:00
#!/usr/bin/perl -w
2010-11-02 14:58:05 -04:00
#
# Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
# Licensed under the terms of the GNU GPL License version 2
#
2010-11-02 15:01:32 -04:00
use strict ;
use IPC::Open2 ;
use Fcntl qw( F_GETFL F_SETFL O_NONBLOCK ) ;
2010-11-02 14:58:22 -04:00
use File::Path qw( mkpath ) ;
use File::Copy qw( cp ) ;
2010-11-02 15:01:32 -04:00
use FileHandle ;
2010-11-02 15:13:54 -04:00
$# ARGV >= 0 || die "usage: ktest.pl config-file\n" ;
2010-11-02 15:01:32 -04:00
$| = 1 ;
my % opt ;
2010-11-02 15:13:54 -04:00
my % repeat_tests ;
my % repeats ;
2010-11-02 14:58:27 -04:00
my % default ;
2010-11-02 15:01:32 -04:00
#default opts
2010-11-02 15:13:54 -04:00
$ default { "NUM_TESTS" } = 1 ;
2010-11-02 14:58:27 -04:00
$ default { "REBOOT_TYPE" } = "grub" ;
$ default { "TEST_TYPE" } = "test" ;
$ default { "BUILD_TYPE" } = "randconfig" ;
$ default { "MAKE_CMD" } = "make" ;
$ default { "TIMEOUT" } = 120 ;
2010-11-02 15:13:54 -04:00
$ default { "TMP_DIR" } = "/tmp/ktest" ;
2010-11-02 14:58:27 -04:00
$ default { "SLEEP_TIME" } = 60 ; # sleep time between tests
$ default { "BUILD_NOCLEAN" } = 0 ;
$ default { "REBOOT_ON_ERROR" } = 0 ;
$ default { "POWEROFF_ON_ERROR" } = 0 ;
$ default { "REBOOT_ON_SUCCESS" } = 1 ;
$ default { "POWEROFF_ON_SUCCESS" } = 0 ;
$ default { "BUILD_OPTIONS" } = "" ;
$ default { "BISECT_SLEEP_TIME" } = 60 ; # sleep time between bisects
$ default { "CLEAR_LOG" } = 0 ;
$ default { "SUCCESS_LINE" } = "login:" ;
$ default { "BOOTED_TIMEOUT" } = 1 ;
$ default { "DIE_ON_FAILURE" } = 1 ;
2010-11-02 15:01:32 -04:00
my $ version ;
2010-11-02 14:58:27 -04:00
my $ machine ;
my $ tmpdir ;
my $ builddir ;
my $ outputdir ;
2010-11-08 16:43:21 -05:00
my $ output_config ;
2010-11-02 14:58:27 -04:00
my $ test_type ;
2010-11-02 14:58:22 -04:00
my $ build_type ;
2010-11-02 14:58:27 -04:00
my $ build_options ;
my $ reboot_type ;
my $ reboot_script ;
my $ power_cycle ;
my $ reboot_on_error ;
my $ poweroff_on_error ;
my $ die_on_failure ;
2010-11-02 14:58:38 -04:00
my $ powercycle_after_reboot ;
my $ poweroff_after_halt ;
2010-11-02 14:58:27 -04:00
my $ power_off ;
my $ grub_menu ;
2010-11-02 15:01:32 -04:00
my $ grub_number ;
my $ target ;
my $ make ;
2010-11-02 14:58:33 -04:00
my $ post_install ;
2010-11-02 14:57:01 -04:00
my $ noclean ;
2010-11-02 14:57:33 -04:00
my $ minconfig ;
2010-11-02 14:58:15 -04:00
my $ addconfig ;
2010-11-02 14:57:33 -04:00
my $ in_bisect = 0 ;
my $ bisect_bad = "" ;
2010-11-02 14:58:05 -04:00
my $ reverse_bisect ;
2010-11-02 14:57:58 -04:00
my $ in_patchcheck = 0 ;
2010-11-02 14:57:43 -04:00
my $ run_test ;
2010-11-02 14:57:58 -04:00
my $ redirect ;
2010-11-02 14:58:22 -04:00
my $ buildlog ;
my $ dmesg ;
my $ monitor_fp ;
my $ monitor_pid ;
my $ monitor_cnt = 0 ;
2010-11-02 14:58:27 -04:00
my $ sleep_time ;
my $ bisect_sleep_time ;
my $ store_failures ;
my $ timeout ;
my $ booted_timeout ;
my $ console ;
my $ success_line ;
my $ build_target ;
my $ target_image ;
my $ localversion ;
2010-11-02 14:58:38 -04:00
my $ iteration = 0 ;
2010-11-02 15:01:32 -04:00
2010-11-02 15:13:54 -04:00
sub set_value {
my ( $ lvalue , $ rvalue ) = @ _ ;
if ( defined ( $ opt { $ lvalue } ) ) {
die "Error: Option $lvalue defined more than once!\n" ;
}
$ opt { $ lvalue } = $ rvalue ;
2010-11-08 16:45:50 -05:00
if ( $ rvalue =~ /^\s*$/ ) {
delete $ opt { $ lvalue } ;
} else {
$ opt { $ lvalue } = $ rvalue ;
}
2010-11-02 15:13:54 -04:00
}
2010-11-02 15:01:32 -04:00
sub read_config {
my ( $ config ) = @ _ ;
open ( IN , $ config ) || die "can't read file $config" ;
2010-11-02 15:13:54 -04:00
my $ name = $ config ;
$ name =~ s , . * / ( . * ) , $ 1 , ;
my $ test_num = 0 ;
my $ default = 1 ;
my $ repeat = 1 ;
my $ num_tests_set = 0 ;
my $ skip = 0 ;
my $ rest ;
2010-11-02 15:01:32 -04:00
while ( <IN> ) {
# ignore blank lines and comments
next if ( /^\s*$/ || /\s*\#/ ) ;
2010-11-02 15:13:54 -04:00
if ( /^\s*TEST_START(.*)/ ) {
$ rest = $ 1 ;
if ( $ num_tests_set ) {
die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n" ;
}
my $ old_test_num = $ test_num ;
$ test_num += $ repeat ;
$ default = 0 ;
$ repeat = 1 ;
if ( $ rest =~ /\s+SKIP(.*)/ ) {
$ rest = $ 1 ;
$ skip = 1 ;
} else {
$ skip = 0 ;
}
if ( $ rest =~ /\s+ITERATE\s+(\d+)(.*)$/ ) {
$ repeat = $ 1 ;
$ rest = $ 2 ;
$ repeat_tests { "$test_num" } = $ repeat ;
}
if ( $ rest =~ /\s+SKIP(.*)/ ) {
$ rest = $ 1 ;
$ skip = 1 ;
}
if ( $ rest !~ /^\s*$/ ) {
die "$name: $.: Gargbage found after TEST_START\n$_" ;
}
if ( $ skip ) {
$ test_num = $ old_test_num ;
$ repeat = 1 ;
}
} elsif ( /^\s*DEFAULTS(.*)$/ ) {
$ default = 1 ;
$ rest = $ 1 ;
if ( $ rest =~ /\s+SKIP(.*)/ ) {
$ rest = $ 1 ;
$ skip = 1 ;
} else {
$ skip = 0 ;
}
if ( $ rest !~ /^\s*$/ ) {
die "$name: $.: Gargbage found after DEFAULTS\n$_" ;
}
} elsif ( /^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/ ) {
next if ( $ skip ) ;
2010-11-02 15:01:32 -04:00
my $ lvalue = $ 1 ;
my $ rvalue = $ 2 ;
2010-11-02 15:13:54 -04:00
if ( ! $ default &&
( $ lvalue eq "NUM_TESTS" ||
$ lvalue eq "LOG_FILE" ||
$ lvalue eq "CLEAR_LOG" ) ) {
die "$name: $.: $lvalue must be set in DEFAULTS section\n" ;
}
if ( $ lvalue eq "NUM_TESTS" ) {
if ( $ test_num ) {
die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n" ;
}
if ( ! $ default ) {
die "$name: $.: NUM_TESTS must be set in default section\n" ;
}
$ num_tests_set = 1 ;
}
if ( $ default || $ lvalue =~ /\[\d+\]$/ ) {
set_value ( $ lvalue , $ rvalue ) ;
} else {
my $ val = "$lvalue\[$test_num\]" ;
set_value ( $ val , $ rvalue ) ;
if ( $ repeat > 1 ) {
$ repeats { $ val } = $ repeat ;
}
2010-11-02 14:58:27 -04:00
}
2010-11-02 15:13:54 -04:00
} else {
die "$name: $.: Garbage found in config\n$_" ;
2010-11-02 15:01:32 -04:00
}
}
close ( IN ) ;
2010-11-02 14:58:27 -04:00
2010-11-02 15:13:54 -04:00
if ( $ test_num ) {
$ test_num += $ repeat - 1 ;
$ opt { "NUM_TESTS" } = $ test_num ;
}
2010-11-02 14:58:27 -04:00
# set any defaults
foreach my $ default ( keys % default ) {
if ( ! defined ( $ opt { $ default } ) ) {
$ opt { $ default } = $ default { $ default } ;
}
}
2010-11-02 15:01:32 -04:00
}
2010-11-08 16:39:57 -05:00
sub _logit {
2010-11-02 15:01:32 -04:00
if ( defined ( $ opt { "LOG_FILE" } ) ) {
open ( OUT , ">> $opt{LOG_FILE}" ) or die "Can't write to $opt{LOG_FILE}" ;
print OUT @ _ ;
close ( OUT ) ;
}
}
2010-11-08 16:39:57 -05:00
sub logit {
if ( defined ( $ opt { "LOG_FILE" } ) ) {
_logit @ _ ;
} else {
print @ _ ;
}
}
2010-11-02 14:57:33 -04:00
sub doprint {
print @ _ ;
2010-11-08 16:39:57 -05:00
_logit @ _ ;
2010-11-02 14:57:33 -04:00
}
2010-11-02 14:58:22 -04:00
sub run_command ;
sub reboot {
# try to reboot normally
2010-11-02 14:58:38 -04:00
if ( run_command "ssh $target reboot" ) {
if ( defined ( $ powercycle_after_reboot ) ) {
sleep $ powercycle_after_reboot ;
run_command "$power_cycle" ;
}
} else {
2010-11-02 14:58:22 -04:00
# nope? power cycle it.
2010-11-02 14:58:27 -04:00
run_command "$power_cycle" ;
2010-11-02 14:58:22 -04:00
}
}
2010-11-02 14:58:38 -04:00
sub do_not_reboot {
my $ i = $ iteration ;
return $ test_type eq "build" ||
( $ test_type eq "patchcheck" && $ opt { "PATCHCHECK_TYPE[$i]" } eq "build" ) ||
( $ test_type eq "bisect" && $ opt { "BISECT_TYPE[$i]" } eq "build" ) ;
}
2010-11-02 14:57:01 -04:00
sub dodie {
2010-11-02 14:57:43 -04:00
doprint "CRITICAL FAILURE... " , @ _ , "\n" ;
2010-11-02 14:57:01 -04:00
2010-11-02 14:58:38 -04:00
my $ i = $ iteration ;
if ( $ reboot_on_error && ! do_not_reboot ) {
2010-11-02 14:57:21 -04:00
doprint "REBOOTING\n" ;
2010-11-02 14:58:22 -04:00
reboot ;
2010-11-02 14:57:21 -04:00
2010-11-02 14:58:27 -04:00
} elsif ( $ poweroff_on_error && defined ( $ power_off ) ) {
2010-11-02 14:57:01 -04:00
doprint "POWERING OFF\n" ;
2010-11-02 14:58:27 -04:00
`$power_off` ;
2010-11-02 14:57:01 -04:00
}
2010-11-02 14:57:21 -04:00
2010-11-02 14:58:38 -04:00
die @ _ , "\n" ;
2010-11-02 14:57:01 -04:00
}
2010-11-02 14:58:22 -04:00
sub open_console {
my ( $ fp ) = @ _ ;
my $ flags ;
2010-11-02 14:58:27 -04:00
my $ pid = open ( $ fp , "$console|" ) or
dodie "Can't open console $console" ;
2010-11-02 14:58:22 -04:00
$ flags = fcntl ( $ fp , F_GETFL , 0 ) or
2010-11-02 14:58:38 -04:00
dodie "Can't get flags for the socket: $!" ;
2010-11-02 14:58:22 -04:00
$ flags = fcntl ( $ fp , F_SETFL , $ flags | O_NONBLOCK ) or
2010-11-02 14:58:38 -04:00
dodie "Can't set flags for the socket: $!" ;
2010-11-02 14:58:22 -04:00
return $ pid ;
}
sub close_console {
my ( $ fp , $ pid ) = @ _ ;
doprint "kill child process $pid\n" ;
kill 2 , $ pid ;
print "closing!\n" ;
close ( $ fp ) ;
}
sub start_monitor {
if ( $ monitor_cnt + + ) {
return ;
}
$ monitor_fp = \ * MONFD ;
$ monitor_pid = open_console $ monitor_fp ;
2010-11-02 14:58:27 -04:00
return ;
open ( MONFD , "Stop perl from warning about single use of MONFD" ) ;
2010-11-02 14:58:22 -04:00
}
sub end_monitor {
if ( - - $ monitor_cnt ) {
return ;
}
close_console ( $ monitor_fp , $ monitor_pid ) ;
}
sub wait_for_monitor {
my ( $ time ) = @ _ ;
my $ line ;
2010-11-02 14:58:27 -04:00
doprint "** Wait for monitor to settle down **\n" ;
2010-11-02 14:58:22 -04:00
# read the monitor and wait for the system to calm down
do {
$ line = wait_for_input ( $ monitor_fp , $ time ) ;
2010-11-02 14:58:27 -04:00
print "$line" if ( defined ( $ line ) ) ;
2010-11-02 14:58:22 -04:00
} while ( defined ( $ line ) ) ;
2010-11-02 14:58:27 -04:00
print "** Monitor flushed **\n" ;
2010-11-02 14:58:22 -04:00
}
2010-11-02 14:58:15 -04:00
sub fail {
2010-11-02 14:58:27 -04:00
if ( $ die_on_failure ) {
2010-11-02 14:58:15 -04:00
dodie @ _ ;
}
2010-11-02 14:58:27 -04:00
doprint "FAILED\n" ;
2010-11-02 14:58:22 -04:00
2010-11-02 14:58:38 -04:00
my $ i = $ iteration ;
2010-11-02 14:58:27 -04:00
# no need to reboot for just building.
2010-11-02 14:58:38 -04:00
if ( ! do_not_reboot ) {
2010-11-02 14:58:27 -04:00
doprint "REBOOTING\n" ;
reboot ;
start_monitor ;
wait_for_monitor $ sleep_time ;
end_monitor ;
}
2010-11-02 14:58:22 -04:00
2010-11-02 14:58:38 -04:00
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" ;
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" ;
2010-11-02 14:58:27 -04:00
doprint "**** Failed: " , @ _ , " ****\n" ;
2010-11-02 14:58:38 -04:00
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" ;
doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" ;
2010-11-02 14:58:27 -04:00
return 1 if ( ! defined ( $ store_failures ) ) ;
2010-11-02 14:58:22 -04:00
my @ t = localtime ;
my $ date = sprintf "%04d%02d%02d%02d%02d%02d" ,
1900 + $ t [ 5 ] , $ t [ 4 ] , $ t [ 3 ] , $ t [ 2 ] , $ t [ 1 ] , $ t [ 0 ] ;
2010-11-02 14:58:27 -04:00
my $ dir = "$machine-$test_type-$build_type-fail-$date" ;
my $ faildir = "$store_failures/$dir" ;
2010-11-02 14:58:22 -04:00
if ( ! - d $ faildir ) {
mkpath ( $ faildir ) or
2010-11-02 14:58:27 -04:00
die "can't create $faildir" ;
2010-11-02 14:58:22 -04:00
}
2010-11-08 16:43:21 -05:00
if ( - f "$output_config" ) {
cp "$output_config" , "$faildir/config" or
2010-11-02 14:58:22 -04:00
die "failed to copy .config" ;
}
if ( - f $ buildlog ) {
cp $ buildlog , "$faildir/buildlog" or
die "failed to move $buildlog" ;
}
if ( - f $ dmesg ) {
cp $ dmesg , "$faildir/dmesg" or
die "failed to move $dmesg" ;
}
doprint "*** Saved info to $faildir ***\n" ;
2010-11-02 14:58:15 -04:00
return 1 ;
}
2010-11-02 15:01:32 -04:00
sub run_command {
my ( $ command ) = @ _ ;
2010-11-02 14:58:05 -04:00
my $ dolog = 0 ;
my $ dord = 0 ;
my $ pid ;
doprint ( "$command ... " ) ;
$ pid = open ( CMD , "$command 2>&1 |" ) or
2010-11-02 14:58:15 -04:00
( fail "unable to exec $command" and return 0 ) ;
2010-11-02 15:01:32 -04:00
if ( defined ( $ opt { "LOG_FILE" } ) ) {
2010-11-02 14:58:05 -04:00
open ( LOG , ">>$opt{LOG_FILE}" ) or
dodie "failed to write to log" ;
$ dolog = 1 ;
2010-11-02 14:57:58 -04:00
}
if ( defined ( $ redirect ) ) {
2010-11-02 14:58:05 -04:00
open ( RD , ">$redirect" ) or
dodie "failed to write to redirect $redirect" ;
$ dord = 1 ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:58:05 -04:00
while ( <CMD> ) {
print LOG if ( $ dolog ) ;
print RD if ( $ dord ) ;
}
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:05 -04:00
waitpid ( $ pid , 0 ) ;
2010-11-02 15:01:32 -04:00
my $ failed = $? ;
2010-11-02 14:58:05 -04:00
close ( CMD ) ;
close ( LOG ) if ( $ dolog ) ;
close ( RD ) if ( $ dord ) ;
2010-11-02 15:01:32 -04:00
if ( $ failed ) {
doprint "FAILED!\n" ;
} else {
doprint "SUCCESS\n" ;
}
2010-11-02 14:57:33 -04:00
return ! $ failed ;
}
sub get_grub_index {
2010-11-02 14:58:27 -04:00
if ( $ reboot_type ne "grub" ) {
return ;
}
2010-11-02 14:57:43 -04:00
return if ( defined ( $ grub_number ) ) ;
2010-11-02 14:57:33 -04:00
doprint "Find grub menu ... " ;
$ grub_number = - 1 ;
open ( IN , "ssh $target cat /boot/grub/menu.lst |" )
or die "unable to get menu.lst" ;
while ( <IN> ) {
2010-11-02 14:58:27 -04:00
if ( /^\s*title\s+$grub_menu\s*$/ ) {
2010-11-02 14:57:33 -04:00
$ grub_number + + ;
last ;
} elsif ( /^\s*title\s/ ) {
$ grub_number + + ;
}
}
close ( IN ) ;
2010-11-02 14:58:27 -04:00
die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
2010-11-02 14:57:33 -04:00
if ( $ grub_number < 0 ) ;
doprint "$grub_number\n" ;
2010-11-02 15:01:32 -04:00
}
sub wait_for_input
{
my ( $ fp , $ time ) = @ _ ;
my $ rin ;
my $ ready ;
my $ line ;
my $ ch ;
if ( ! defined ( $ time ) ) {
$ time = $ timeout ;
}
$ rin = '' ;
vec ( $ rin , fileno ( $ fp ) , 1 ) = 1 ;
$ ready = select ( $ rin , undef , undef , $ time ) ;
$ line = "" ;
# try to read one char at a time
while ( sysread $ fp , $ ch , 1 ) {
$ line . = $ ch ;
last if ( $ ch eq "\n" ) ;
}
if ( ! length ( $ line ) ) {
return undef ;
}
return $ line ;
}
2010-11-02 14:57:21 -04:00
sub reboot_to {
2010-11-02 14:58:27 -04:00
if ( $ reboot_type eq "grub" ) {
run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'" ;
return ;
}
run_command "$reboot_script" ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 15:13:54 -04:00
sub get_sha1 {
my ( $ commit ) = @ _ ;
doprint "git rev-list --max-count=1 $commit ... " ;
my $ sha1 = `git rev-list --max-count=1 $commit` ;
my $ ret = $? ;
logit $ sha1 ;
if ( $ ret ) {
doprint "FAILED\n" ;
dodie "Failed to get git $commit" ;
}
print "SUCCESS\n" ;
chomp $ sha1 ;
return $ sha1 ;
}
2010-11-02 14:57:43 -04:00
sub monitor {
2010-11-02 15:01:32 -04:00
my $ booted = 0 ;
my $ bug = 0 ;
2010-11-02 14:57:01 -04:00
my $ skip_call_trace = 0 ;
2010-11-02 14:58:15 -04:00
my $ loops ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:22 -04:00
wait_for_monitor 5 ;
2010-11-02 15:01:32 -04:00
my $ line ;
my $ full_line = "" ;
2010-11-02 14:58:22 -04:00
open ( DMESG , "> $dmesg" ) or
die "unable to write to $dmesg" ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:57:21 -04:00
reboot_to ;
2010-11-02 15:01:32 -04:00
for ( ; ; ) {
2010-11-02 14:58:15 -04:00
if ( $ booted ) {
2010-11-02 14:58:27 -04:00
$ line = wait_for_input ( $ monitor_fp , $ booted_timeout ) ;
2010-11-02 14:58:15 -04:00
} else {
2010-11-02 14:58:22 -04:00
$ line = wait_for_input ( $ monitor_fp ) ;
2010-11-02 14:58:15 -04:00
}
2010-11-02 15:01:32 -04:00
last if ( ! defined ( $ line ) ) ;
doprint $ line ;
2010-11-02 14:58:22 -04:00
print DMESG $ line ;
2010-11-02 15:01:32 -04:00
# we are not guaranteed to get a full line
$ full_line . = $ line ;
2010-11-02 14:58:27 -04:00
if ( $ full_line =~ /$success_line/ ) {
2010-11-02 15:01:32 -04:00
$ booted = 1 ;
}
2010-11-02 14:57:01 -04:00
if ( $ full_line =~ /\[ backtrace testing \]/ ) {
$ skip_call_trace = 1 ;
}
2010-11-02 15:01:32 -04:00
if ( $ full_line =~ /call trace:/i ) {
2010-11-02 14:57:01 -04:00
$ bug = 1 if ( ! $ skip_call_trace ) ;
}
if ( $ full_line =~ /\[ end of backtrace testing \]/ ) {
$ skip_call_trace = 0 ;
}
if ( $ full_line =~ /Kernel panic -/ ) {
2010-11-02 15:01:32 -04:00
$ bug = 1 ;
}
if ( $ line =~ /\n/ ) {
$ full_line = "" ;
}
}
2010-11-02 14:58:22 -04:00
close ( DMESG ) ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:27 -04:00
if ( $ bug ) {
2010-11-02 14:58:15 -04:00
return 0 if ( $ in_bisect ) ;
2010-11-02 14:58:38 -04:00
fail "failed - got a bug report" and return 0 ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:58:27 -04:00
if ( ! $ booted ) {
2010-11-02 14:58:15 -04:00
return 0 if ( $ in_bisect ) ;
2010-11-02 14:58:38 -04:00
fail "failed - never got a boot prompt." and return 0 ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:57:33 -04:00
2010-11-02 14:58:15 -04:00
return 1 ;
2010-11-02 15:01:32 -04:00
}
sub install {
2010-11-02 14:58:27 -04:00
run_command "scp $outputdir/$build_target $target:$target_image" or
2010-11-02 14:57:01 -04:00
dodie "failed to copy image" ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:57:33 -04:00
my $ install_mods = 0 ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:57:33 -04:00
# should we process modules?
$ install_mods = 0 ;
2010-11-08 16:43:21 -05:00
open ( IN , "$output_config" ) or dodie ( "Can't read config file" ) ;
2010-11-02 14:57:33 -04:00
while ( <IN> ) {
if ( /CONFIG_MODULES(=y)?/ ) {
$ install_mods = 1 if ( defined ( $ 1 ) ) ;
last ;
2010-11-02 14:57:01 -04:00
}
2010-11-02 14:57:33 -04:00
}
close ( IN ) ;
2010-11-02 14:57:01 -04:00
2010-11-02 14:57:33 -04:00
if ( ! $ install_mods ) {
doprint "No modules needed\n" ;
return ;
}
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:27 -04:00
run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
2010-11-02 14:57:33 -04:00
dodie "Failed to install modules" ;
2010-11-02 14:57:01 -04:00
2010-11-02 14:57:33 -04:00
my $ modlib = "/lib/modules/$version" ;
2010-11-02 15:13:54 -04:00
my $ modtar = "ktest-mods.tar.bz2" ;
2010-11-02 14:57:01 -04:00
2010-11-02 14:57:33 -04:00
run_command "ssh $target rm -rf $modlib" or
dodie "failed to remove old mods: $modlib" ;
2010-11-02 14:57:01 -04:00
2010-11-02 14:57:33 -04:00
# would be nice if scp -r did not follow symbolic links
2010-11-02 14:58:27 -04:00
run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
2010-11-02 14:57:33 -04:00
dodie "making tarball" ;
2010-11-02 14:58:27 -04:00
run_command "scp $tmpdir/$modtar $target:/tmp" or
2010-11-02 14:57:33 -04:00
dodie "failed to copy modules" ;
2010-11-02 14:58:27 -04:00
unlink "$tmpdir/$modtar" ;
2010-11-02 14:57:33 -04:00
run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
dodie "failed to tar modules" ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:57:33 -04:00
run_command "ssh $target rm -f /tmp/$modtar" ;
2010-11-02 14:58:33 -04:00
return if ( ! defined ( $ post_install ) ) ;
my $ save_env = $ ENV { KERNEL_VERSION } ;
$ ENV { KERNEL_VERSION } = $ version ;
2010-11-02 14:58:38 -04:00
run_command "$post_install" or
dodie "Failed to run post install" ;
2010-11-02 14:58:33 -04:00
$ ENV { KERNEL_VERSION } = $ save_env ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:57:58 -04:00
sub check_buildlog {
my ( $ patch ) = @ _ ;
my @ files = `git show $patch | diffstat -l` ;
open ( IN , "git show $patch |" ) or
dodie "failed to show $patch" ;
while ( <IN> ) {
if ( m , ^ - - - a / ( . * ) , ) {
chomp $ 1 ;
$ files [ $# files ] = $ 1 ;
}
}
close ( IN ) ;
open ( IN , $ buildlog ) or dodie "Can't open $buildlog" ;
while ( <IN> ) {
if ( /^\s*(.*?):.*(warning|error)/ ) {
my $ err = $ 1 ;
foreach my $ file ( @ files ) {
2010-11-02 14:58:27 -04:00
my $ fullpath = "$builddir/$file" ;
2010-11-02 14:57:58 -04:00
if ( $ file eq $ err || $ fullpath eq $ err ) {
2010-11-02 14:58:15 -04:00
fail "$file built with warnings" and return 0 ;
2010-11-02 14:57:58 -04:00
}
}
}
}
close ( IN ) ;
2010-11-02 14:58:15 -04:00
return 1 ;
2010-11-02 14:57:58 -04:00
}
2010-11-02 15:01:32 -04:00
sub build {
my ( $ type ) = @ _ ;
2010-11-02 14:57:01 -04:00
my $ defconfig = "" ;
2010-11-02 14:58:22 -04:00
unlink $ buildlog ;
2010-11-02 14:57:21 -04:00
if ( $ type =~ /^useconfig:(.*)/ ) {
2010-11-08 16:43:21 -05:00
run_command "cp $1 $output_config" or
2010-11-02 14:57:21 -04:00
dodie "could not copy $1 to .config" ;
2010-11-02 14:57:33 -04:00
2010-11-02 14:57:21 -04:00
$ type = "oldconfig" ;
}
2010-11-02 14:57:01 -04:00
# old config can ask questions
if ( $ type eq "oldconfig" ) {
2010-11-08 16:35:48 -05:00
$ type = "oldnoconfig" ;
2010-11-02 14:57:21 -04:00
# allow for empty configs
2010-11-08 16:43:21 -05:00
run_command "touch $output_config" ;
2010-11-02 14:57:21 -04:00
2010-11-08 16:43:21 -05:00
run_command "mv $output_config $outputdir/config_temp" or
2010-11-02 14:57:01 -04:00
dodie "moving .config" ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:57:33 -04:00
if ( ! $ noclean && ! run_command "$make mrproper" ) {
2010-11-02 14:57:01 -04:00
dodie "make mrproper" ;
}
2010-11-02 15:01:32 -04:00
2010-11-08 16:43:21 -05:00
run_command "mv $outputdir/config_temp $output_config" or
2010-11-02 14:57:01 -04:00
dodie "moving config_temp" ;
} elsif ( ! $ noclean ) {
2010-11-08 16:43:21 -05:00
unlink "$output_config" ;
2010-11-02 14:57:33 -04:00
run_command "$make mrproper" or
2010-11-02 14:57:01 -04:00
dodie "make mrproper" ;
}
2010-11-02 15:01:32 -04:00
# add something to distinguish this build
2010-11-02 14:58:27 -04:00
open ( OUT , "> $outputdir/localversion" ) or dodie ( "Can't make localversion file" ) ;
print OUT "$localversion\n" ;
2010-11-02 15:01:32 -04:00
close ( OUT ) ;
2010-11-02 14:57:33 -04:00
if ( defined ( $ minconfig ) ) {
$ defconfig = "KCONFIG_ALLCONFIG=$minconfig" ;
2010-11-02 15:01:32 -04:00
}
2010-11-08 16:35:48 -05:00
run_command "$defconfig $make $type" or
2010-11-02 14:57:01 -04:00
dodie "failed make config" ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:27 -04:00
$ redirect = "$buildlog" ;
if ( ! run_command "$make $build_options" ) {
2010-11-02 14:57:58 -04:00
undef $ redirect ;
2010-11-02 14:57:33 -04:00
# bisect may need this to pass
2010-11-02 14:58:15 -04:00
return 0 if ( $ in_bisect ) ;
fail "failed build" and return 0 ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:57:58 -04:00
undef $ redirect ;
2010-11-02 14:57:33 -04:00
2010-11-02 14:58:15 -04:00
return 1 ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:57:21 -04:00
sub halt {
2010-11-02 14:58:27 -04:00
if ( ! run_command "ssh $target halt" or defined ( $ power_off ) ) {
2010-11-02 14:58:38 -04:00
if ( defined ( $ poweroff_after_halt ) ) {
sleep $ poweroff_after_halt ;
run_command "$power_off" ;
}
} else {
2010-11-02 14:57:21 -04:00
# nope? the zap it!
2010-11-02 14:58:27 -04:00
run_command "$power_off" ;
2010-11-02 14:57:21 -04:00
}
}
2010-11-02 14:57:33 -04:00
sub success {
my ( $ i ) = @ _ ;
doprint "\n\n*******************************************\n" ;
doprint "*******************************************\n" ;
2010-11-02 14:58:27 -04:00
doprint "** TEST $i SUCCESS!!!! **\n" ;
2010-11-02 14:57:33 -04:00
doprint "*******************************************\n" ;
doprint "*******************************************\n" ;
2010-11-02 14:58:38 -04:00
if ( $ i != $ opt { "NUM_TESTS" } && ! do_not_reboot ) {
2010-11-02 14:58:27 -04:00
doprint "Reboot and wait $sleep_time seconds\n" ;
2010-11-02 14:57:33 -04:00
reboot ;
2010-11-02 14:58:22 -04:00
start_monitor ;
2010-11-02 14:58:27 -04:00
wait_for_monitor $ sleep_time ;
2010-11-02 14:58:22 -04:00
end_monitor ;
2010-11-02 14:57:33 -04:00
}
}
sub get_version {
# get the release name
doprint "$make kernelrelease ... " ;
$ version = `$make kernelrelease | tail -1` ;
chomp ( $ version ) ;
doprint "$version\n" ;
}
2010-11-02 14:57:43 -04:00
sub child_run_test {
2010-11-02 14:58:22 -04:00
my $ failed = 0 ;
2010-11-02 14:57:43 -04:00
2010-11-02 14:58:22 -04:00
# child should have no power
2010-11-02 14:58:27 -04:00
$ reboot_on_error = 0 ;
$ poweroff_on_error = 0 ;
$ die_on_failure = 1 ;
2010-11-02 14:58:22 -04:00
run_command $ run_test or $ failed = 1 ;
2010-11-02 14:57:43 -04:00
exit $ failed ;
}
my $ child_done ;
sub child_finished {
$ child_done = 1 ;
}
sub do_run_test {
my $ child_pid ;
my $ child_exit ;
my $ line ;
my $ full_line ;
my $ bug = 0 ;
2010-11-02 14:58:22 -04:00
wait_for_monitor 1 ;
2010-11-02 14:57:43 -04:00
2010-11-02 14:58:22 -04:00
doprint "run test $run_test\n" ;
2010-11-02 14:57:43 -04:00
$ child_done = 0 ;
$ SIG { CHLD } = qw( child_finished ) ;
$ child_pid = fork ;
child_run_test if ( ! $ child_pid ) ;
$ full_line = "" ;
do {
2010-11-02 14:58:22 -04:00
$ line = wait_for_input ( $ monitor_fp , 1 ) ;
2010-11-02 14:57:43 -04:00
if ( defined ( $ line ) ) {
# we are not guaranteed to get a full line
$ full_line . = $ line ;
if ( $ full_line =~ /call trace:/i ) {
$ bug = 1 ;
}
if ( $ full_line =~ /Kernel panic -/ ) {
$ bug = 1 ;
}
if ( $ line =~ /\n/ ) {
$ full_line = "" ;
}
}
} while ( ! $ child_done && ! $ bug ) ;
if ( $ bug ) {
doprint "Detected kernel crash!\n" ;
# kill the child with extreme prejudice
kill 9 , $ child_pid ;
}
waitpid $ child_pid , 0 ;
$ child_exit = $? ;
if ( $ bug || $ child_exit ) {
2010-11-02 14:58:15 -04:00
return 0 if $ in_bisect ;
fail "test failed" and return 0 ;
2010-11-02 14:57:43 -04:00
}
2010-11-02 14:58:15 -04:00
return 1 ;
2010-11-02 14:57:43 -04:00
}
2010-11-02 14:58:27 -04:00
sub run_git_bisect {
my ( $ command ) = @ _ ;
doprint "$command ... " ;
my $ output = `$command 2>&1` ;
my $ ret = $? ;
logit $ output ;
if ( $ ret ) {
doprint "FAILED\n" ;
dodie "Failed to git bisect" ;
}
doprint "SUCCESS\n" ;
if ( $ output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/ ) {
doprint "$1 [$2]\n" ;
} elsif ( $ output =~ m/^([[:xdigit:]]+) is the first bad commit/ ) {
$ bisect_bad = $ 1 ;
doprint "Found bad commit... $1\n" ;
return 0 ;
} else {
# we already logged it, just print it now.
print $ output ;
}
return 1 ;
}
2010-11-02 14:57:33 -04:00
sub run_bisect {
my ( $ type ) = @ _ ;
2010-11-02 14:58:15 -04:00
my $ failed = 0 ;
2010-11-02 14:57:33 -04:00
my $ result ;
my $ output ;
my $ ret ;
if ( defined ( $ minconfig ) ) {
2010-11-02 14:58:15 -04:00
build "useconfig:$minconfig" or $ failed = 1 ;
2010-11-02 14:57:33 -04:00
} else {
# ?? no config to use?
2010-11-02 14:58:15 -04:00
build "oldconfig" or $ failed = 1 ;
2010-11-02 14:57:33 -04:00
}
if ( $ type ne "build" ) {
2010-11-02 14:58:22 -04:00
dodie "Failed on build" if $ failed ;
2010-11-02 14:57:33 -04:00
# Now boot the box
get_grub_index ;
get_version ;
install ;
2010-11-02 14:58:22 -04:00
start_monitor ;
2010-11-02 14:58:15 -04:00
monitor or $ failed = 1 ;
2010-11-02 14:57:33 -04:00
if ( $ type ne "boot" ) {
2010-11-02 14:58:22 -04:00
dodie "Failed on boot" if $ failed ;
2010-11-02 14:57:43 -04:00
2010-11-02 14:58:15 -04:00
do_run_test or $ failed = 1 ;
2010-11-02 14:57:33 -04:00
}
2010-11-02 14:58:22 -04:00
end_monitor ;
2010-11-02 14:57:33 -04:00
}
if ( $ failed ) {
$ result = "bad" ;
2010-11-02 14:57:43 -04:00
# reboot the box to a good kernel
2010-11-02 14:58:27 -04:00
if ( $ type ne "build" ) {
doprint "Reboot and sleep $bisect_sleep_time seconds\n" ;
2010-11-02 14:57:43 -04:00
reboot ;
2010-11-02 14:58:22 -04:00
start_monitor ;
2010-11-02 14:58:27 -04:00
wait_for_monitor $ bisect_sleep_time ;
2010-11-02 14:58:22 -04:00
end_monitor ;
2010-11-02 14:57:43 -04:00
}
2010-11-02 14:57:33 -04:00
} else {
$ result = "good" ;
}
2010-11-02 14:58:05 -04:00
# Are we looking for where it worked, not failed?
if ( $ reverse_bisect ) {
if ( $ failed ) {
$ result = "good" ;
} else {
$ result = "bad" ;
}
}
2010-11-02 14:58:27 -04:00
return $ result ;
2010-11-02 14:57:33 -04:00
}
sub bisect {
my ( $ i ) = @ _ ;
my $ result ;
die "BISECT_GOOD[$i] not defined\n" if ( ! defined ( $ opt { "BISECT_GOOD[$i]" } ) ) ;
die "BISECT_BAD[$i] not defined\n" if ( ! defined ( $ opt { "BISECT_BAD[$i]" } ) ) ;
die "BISECT_TYPE[$i] not defined\n" if ( ! defined ( $ opt { "BISECT_TYPE[$i]" } ) ) ;
my $ good = $ opt { "BISECT_GOOD[$i]" } ;
my $ bad = $ opt { "BISECT_BAD[$i]" } ;
my $ type = $ opt { "BISECT_TYPE[$i]" } ;
2010-11-02 14:58:27 -04:00
my $ start = $ opt { "BISECT_START[$i]" } ;
my $ replay = $ opt { "BISECT_REPLAY[$i]" } ;
2010-11-02 14:57:33 -04:00
2010-11-02 15:13:54 -04:00
# convert to true sha1's
$ good = get_sha1 ( $ good ) ;
$ bad = get_sha1 ( $ bad ) ;
2010-11-02 14:58:05 -04:00
if ( defined ( $ opt { "BISECT_REVERSE[$i]" } ) &&
$ opt { "BISECT_REVERSE[$i]" } == 1 ) {
doprint "Performing a reverse bisect (bad is good, good is bad!)\n" ;
$ reverse_bisect = 1 ;
} else {
$ reverse_bisect = 0 ;
}
2010-11-02 14:57:33 -04:00
$ in_bisect = 1 ;
2010-11-02 14:58:27 -04:00
# Can't have a test without having a test to run
if ( $ type eq "test" && ! defined ( $ run_test ) ) {
$ type = "boot" ;
}
my $ check = $ opt { "BISECT_CHECK[$i]" } ;
if ( defined ( $ check ) && $ check ne "0" ) {
# get current HEAD
2010-11-02 15:13:54 -04:00
my $ head = get_sha1 ( "HEAD" ) ;
2010-11-02 14:58:27 -04:00
if ( $ check ne "good" ) {
doprint "TESTING BISECT BAD [$bad]\n" ;
run_command "git checkout $bad" or
die "Failed to checkout $bad" ;
$ result = run_bisect $ type ;
if ( $ result ne "bad" ) {
fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0 ;
}
}
if ( $ check ne "bad" ) {
doprint "TESTING BISECT GOOD [$good]\n" ;
run_command "git checkout $good" or
die "Failed to checkout $good" ;
$ result = run_bisect $ type ;
if ( $ result ne "good" ) {
fail "Tested BISECT_GOOD [$good] and it failed" and return 0 ;
}
}
# checkout where we started
run_command "git checkout $head" or
die "Failed to checkout $head" ;
}
2010-11-02 14:57:33 -04:00
run_command "git bisect start" or
2010-11-02 14:58:27 -04:00
dodie "could not start bisect" ;
2010-11-02 14:57:33 -04:00
run_command "git bisect good $good" or
2010-11-02 14:58:27 -04:00
dodie "could not set bisect good to $good" ;
2010-11-02 14:57:33 -04:00
2010-11-02 14:58:27 -04:00
run_git_bisect "git bisect bad $bad" or
dodie "could not set bisect bad to $bad" ;
2010-11-02 14:57:33 -04:00
2010-11-02 14:58:27 -04:00
if ( defined ( $ replay ) ) {
run_command "git bisect replay $replay" or
dodie "failed to run replay" ;
2010-11-02 14:57:43 -04:00
}
2010-11-02 14:58:27 -04:00
if ( defined ( $ start ) ) {
run_command "git checkout $start" or
dodie "failed to checkout $start" ;
}
my $ test ;
2010-11-02 14:57:33 -04:00
do {
$ result = run_bisect $ type ;
2010-11-02 14:58:27 -04:00
$ test = run_git_bisect "git bisect $result" ;
} while ( $ test ) ;
2010-11-02 14:57:33 -04:00
run_command "git bisect log" or
dodie "could not capture git bisect log" ;
run_command "git bisect reset" or
dodie "could not reset git bisect" ;
doprint "Bad commit was [$bisect_bad]\n" ;
$ in_bisect = 0 ;
success $ i ;
}
2010-11-02 14:57:58 -04:00
sub patchcheck {
my ( $ i ) = @ _ ;
die "PATCHCHECK_START[$i] not defined\n"
if ( ! defined ( $ opt { "PATCHCHECK_START[$i]" } ) ) ;
die "PATCHCHECK_TYPE[$i] not defined\n"
if ( ! defined ( $ opt { "PATCHCHECK_TYPE[$i]" } ) ) ;
my $ start = $ opt { "PATCHCHECK_START[$i]" } ;
my $ end = "HEAD" ;
if ( defined ( $ opt { "PATCHCHECK_END[$i]" } ) ) {
$ end = $ opt { "PATCHCHECK_END[$i]" } ;
}
2010-11-02 15:13:54 -04:00
# Get the true sha1's since we can use things like HEAD~3
$ start = get_sha1 ( $ start ) ;
$ end = get_sha1 ( $ end ) ;
2010-11-02 14:57:58 -04:00
my $ type = $ opt { "PATCHCHECK_TYPE[$i]" } ;
# Can't have a test without having a test to run
if ( $ type eq "test" && ! defined ( $ run_test ) ) {
$ type = "boot" ;
}
open ( IN , "git log --pretty=oneline $end|" ) or
dodie "could not get git list" ;
my @ list ;
while ( <IN> ) {
chomp ;
$ list [ $# list + 1 ] = $ _ ;
last if ( /^$start/ ) ;
}
close ( IN ) ;
if ( $ list [ $# list ] !~ /^$start/ ) {
2010-11-02 14:58:15 -04:00
fail "SHA1 $start not found" ;
2010-11-02 14:57:58 -04:00
}
# go backwards in the list
@ list = reverse @ list ;
my $ save_clean = $ noclean ;
$ in_patchcheck = 1 ;
foreach my $ item ( @ list ) {
my $ sha1 = $ item ;
$ sha1 =~ s/^([[:xdigit:]]+).*/$1/ ;
doprint "\nProcessing commit $item\n\n" ;
run_command "git checkout $sha1" or
die "Failed to checkout $sha1" ;
# only clean on the first and last patch
if ( $ item eq $ list [ 0 ] ||
$ item eq $ list [ $# list ] ) {
$ noclean = $ save_clean ;
} else {
$ noclean = 1 ;
}
if ( defined ( $ minconfig ) ) {
2010-11-02 14:58:15 -04:00
build "useconfig:$minconfig" or return 0 ;
2010-11-02 14:57:58 -04:00
} else {
# ?? no config to use?
2010-11-02 14:58:15 -04:00
build "oldconfig" or return 0 ;
2010-11-02 14:57:58 -04:00
}
2010-11-02 14:58:15 -04:00
check_buildlog $ sha1 or return 0 ;
2010-11-02 14:57:58 -04:00
next if ( $ type eq "build" ) ;
get_grub_index ;
get_version ;
install ;
2010-11-02 14:58:22 -04:00
my $ failed = 0 ;
start_monitor ;
monitor or $ failed = 1 ;
if ( ! $ failed && $ type ne "boot" ) {
do_run_test or $ failed = 1 ;
}
end_monitor ;
return 0 if ( $ failed ) ;
2010-11-02 14:57:58 -04:00
}
$ in_patchcheck = 0 ;
success $ i ;
2010-11-02 14:58:15 -04:00
return 1 ;
2010-11-02 14:57:58 -04:00
}
2010-11-02 15:01:32 -04:00
read_config $ ARGV [ 0 ] ;
# mandatory configs
die "MACHINE not defined\n" if ( ! defined ( $ opt { "MACHINE" } ) ) ;
die "SSH_USER not defined\n" if ( ! defined ( $ opt { "SSH_USER" } ) ) ;
die "BUILD_DIR not defined\n" if ( ! defined ( $ opt { "BUILD_DIR" } ) ) ;
die "OUTPUT_DIR not defined\n" if ( ! defined ( $ opt { "OUTPUT_DIR" } ) ) ;
die "BUILD_TARGET not defined\n" if ( ! defined ( $ opt { "BUILD_TARGET" } ) ) ;
2010-11-02 14:57:21 -04:00
die "TARGET_IMAGE not defined\n" if ( ! defined ( $ opt { "TARGET_IMAGE" } ) ) ;
2010-11-02 15:01:32 -04:00
die "POWER_CYCLE not defined\n" if ( ! defined ( $ opt { "POWER_CYCLE" } ) ) ;
die "CONSOLE not defined\n" if ( ! defined ( $ opt { "CONSOLE" } ) ) ;
die "LOCALVERSION not defined\n" if ( ! defined ( $ opt { "LOCALVERSION" } ) ) ;
2010-11-02 14:58:15 -04:00
if ( $ opt { "CLEAR_LOG" } && defined ( $ opt { "LOG_FILE" } ) ) {
unlink $ opt { "LOG_FILE" } ;
}
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:15 -04:00
doprint "\n\nSTARTING AUTOMATED TESTS\n\n" ;
2010-11-02 15:13:54 -04:00
for ( my $ i = 0 , my $ repeat = 1 ; $ i <= $ opt { "NUM_TESTS" } ; $ i += $ repeat ) {
if ( ! $ i ) {
doprint "DEFAULT OPTIONS:\n" ;
} else {
doprint "\nTEST $i OPTIONS" ;
if ( defined ( $ repeat_tests { $ i } ) ) {
$ repeat = $ repeat_tests { $ i } ;
doprint " ITERATE $repeat" ;
}
doprint "\n" ;
}
foreach my $ option ( sort keys % opt ) {
if ( $ option =~ /\[(\d+)\]$/ ) {
next if ( $ i != $ 1 ) ;
} else {
next if ( $ i ) ;
}
doprint "$option = $opt{$option}\n" ;
}
2010-11-02 14:58:15 -04:00
}
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:27 -04:00
sub set_test_option {
2010-11-02 14:57:43 -04:00
my ( $ name , $ i ) = @ _ ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:57:43 -04:00
my $ option = "$name\[$i\]" ;
2010-11-02 14:57:01 -04:00
2010-11-02 14:57:43 -04:00
if ( defined ( $ opt { $ option } ) ) {
return $ opt { $ option } ;
2010-11-02 14:57:33 -04:00
}
2010-11-02 15:13:54 -04:00
foreach my $ test ( keys % repeat_tests ) {
if ( $ i >= $ test &&
$ i < $ test + $ repeat_tests { $ test } ) {
$ option = "$name\[$test\]" ;
if ( defined ( $ opt { $ option } ) ) {
return $ opt { $ option } ;
}
}
}
2010-11-02 14:57:43 -04:00
if ( defined ( $ opt { $ name } ) ) {
return $ opt { $ name } ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:57:43 -04:00
return undef ;
}
# First we need to do is the builds
2010-11-02 14:58:27 -04:00
for ( my $ i = 1 ; $ i <= $ opt { "NUM_TESTS" } ; $ i + + ) {
2010-11-02 14:58:38 -04:00
$ iteration = $ i ;
2010-11-02 14:58:27 -04:00
my $ ssh_user = set_test_option ( "SSH_USER" , $ i ) ;
my $ makecmd = set_test_option ( "MAKE_CMD" , $ i ) ;
$ machine = set_test_option ( "MACHINE" , $ i ) ;
$ tmpdir = set_test_option ( "TMP_DIR" , $ i ) ;
$ outputdir = set_test_option ( "OUTPUT_DIR" , $ i ) ;
$ builddir = set_test_option ( "BUILD_DIR" , $ i ) ;
$ test_type = set_test_option ( "TEST_TYPE" , $ i ) ;
$ build_type = set_test_option ( "BUILD_TYPE" , $ i ) ;
$ build_options = set_test_option ( "BUILD_OPTIONS" , $ i ) ;
$ power_cycle = set_test_option ( "POWER_CYCLE" , $ i ) ;
$ noclean = set_test_option ( "BUILD_NOCLEAN" , $ i ) ;
$ minconfig = set_test_option ( "MIN_CONFIG" , $ i ) ;
$ run_test = set_test_option ( "TEST" , $ i ) ;
$ addconfig = set_test_option ( "ADD_CONFIG" , $ i ) ;
$ reboot_type = set_test_option ( "REBOOT_TYPE" , $ i ) ;
$ grub_menu = set_test_option ( "GRUB_MENU" , $ i ) ;
2010-11-02 14:58:33 -04:00
$ post_install = set_test_option ( "POST_INSTALL" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ reboot_script = set_test_option ( "REBOOT_SCRIPT" , $ i ) ;
$ reboot_on_error = set_test_option ( "REBOOT_ON_ERROR" , $ i ) ;
$ poweroff_on_error = set_test_option ( "POWEROFF_ON_ERROR" , $ i ) ;
$ die_on_failure = set_test_option ( "DIE_ON_FAILURE" , $ i ) ;
$ power_off = set_test_option ( "POWER_OFF" , $ i ) ;
2010-11-02 14:58:38 -04:00
$ powercycle_after_reboot = set_test_option ( "POWERCYCLE_AFTER_REBOOT" , $ i ) ;
$ poweroff_after_halt = set_test_option ( "POWEROFF_AFTER_HALT" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ sleep_time = set_test_option ( "SLEEP_TIME" , $ i ) ;
$ bisect_sleep_time = set_test_option ( "BISECT_SLEEP_TIME" , $ i ) ;
$ store_failures = set_test_option ( "STORE_FAILURES" , $ i ) ;
$ timeout = set_test_option ( "TIMEOUT" , $ i ) ;
$ booted_timeout = set_test_option ( "BOOTED_TIMEOUT" , $ i ) ;
$ console = set_test_option ( "CONSOLE" , $ i ) ;
$ success_line = set_test_option ( "SUCCESS_LINE" , $ i ) ;
$ build_target = set_test_option ( "BUILD_TARGET" , $ i ) ;
$ target_image = set_test_option ( "TARGET_IMAGE" , $ i ) ;
$ localversion = set_test_option ( "LOCALVERSION" , $ i ) ;
chdir $ builddir || die "can't change directory to $builddir" ;
if ( ! - d $ tmpdir ) {
mkpath ( $ tmpdir ) or
die "can't create $tmpdir" ;
}
2010-11-02 14:57:51 -04:00
2010-11-02 14:58:27 -04:00
$ target = "$ssh_user\@$machine" ;
$ buildlog = "$tmpdir/buildlog-$machine" ;
$ dmesg = "$tmpdir/dmesg-$machine" ;
$ make = "$makecmd O=$outputdir" ;
2010-11-08 16:43:21 -05:00
$ output_config = "$outputdir/.config" ;
2010-11-02 14:58:27 -04:00
if ( $ reboot_type eq "grub" ) {
2010-11-02 14:58:38 -04:00
dodie "GRUB_MENU not defined" if ( ! defined ( $ grub_menu ) ) ;
2010-11-02 14:58:27 -04:00
} elsif ( ! defined ( $ reboot_script ) ) {
2010-11-02 14:58:38 -04:00
dodie "REBOOT_SCRIPT not defined"
2010-11-02 14:58:27 -04:00
}
my $ run_type = $ build_type ;
if ( $ test_type eq "patchcheck" ) {
$ run_type = $ opt { "PATCHCHECK_TYPE[$i]" } ;
} elsif ( $ test_type eq "bisect" ) {
$ run_type = $ opt { "BISECT_TYPE[$i]" } ;
}
# mistake in config file?
if ( ! defined ( $ run_type ) ) {
$ run_type = "ERROR" ;
}
2010-11-02 14:57:43 -04:00
2010-11-02 15:01:32 -04:00
doprint "\n\n" ;
2010-11-02 14:58:27 -04:00
doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n" ;
2010-11-02 14:58:22 -04:00
unlink $ dmesg ;
unlink $ buildlog ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:58:15 -04:00
if ( ! defined ( $ minconfig ) ) {
$ minconfig = $ addconfig ;
} elsif ( defined ( $ addconfig ) ) {
2010-11-02 14:58:27 -04:00
run_command "cat $addconfig $minconfig > $tmpdir/use_config" or
2010-11-02 14:58:15 -04:00
dodie "Failed to create temp config" ;
2010-11-02 14:58:27 -04:00
$ minconfig = "$tmpdir/use_config" ;
2010-11-02 14:58:15 -04:00
}
2010-11-02 14:57:58 -04:00
my $ checkout = $ opt { "CHECKOUT[$i]" } ;
if ( defined ( $ checkout ) ) {
run_command "git checkout $checkout" or
die "failed to checkout $checkout" ;
}
2010-11-02 14:58:27 -04:00
if ( $ test_type eq "bisect" ) {
2010-11-02 14:57:33 -04:00
bisect $ i ;
next ;
2010-11-02 14:58:27 -04:00
} elsif ( $ test_type eq "patchcheck" ) {
2010-11-02 14:57:58 -04:00
patchcheck $ i ;
next ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:58:22 -04:00
if ( $ build_type ne "nobuild" ) {
build $ build_type or next ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:58:27 -04:00
if ( $ test_type ne "build" ) {
get_grub_index ;
get_version ;
install ;
2010-11-02 14:57:43 -04:00
2010-11-02 14:58:27 -04:00
my $ failed = 0 ;
start_monitor ;
monitor or $ failed = 1 ; ;
if ( ! $ failed && $ test_type ne "boot" && defined ( $ run_test ) ) {
do_run_test or $ failed = 1 ;
}
end_monitor ;
next if ( $ failed ) ;
2010-11-02 14:57:43 -04:00
}
2010-11-02 14:57:33 -04:00
success $ i ;
2010-11-02 15:01:32 -04:00
}
2010-11-02 14:57:01 -04:00
if ( $ opt { "POWEROFF_ON_SUCCESS" } ) {
2010-11-02 14:57:21 -04:00
halt ;
2010-11-02 14:58:38 -04:00
} elsif ( $ opt { "REBOOT_ON_SUCCESS" } && ! do_not_reboot ) {
2010-11-02 14:57:21 -04:00
reboot ;
2010-11-02 14:57:01 -04:00
}
2010-11-02 14:57:21 -04:00
2010-11-02 15:01:32 -04:00
exit 0 ;