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 14:35:37 -04:00
my $ VERSION = "0.2" ;
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 ;
2011-03-08 09:22:39 -05:00
$ default { "BISECT_MANUAL" } = 0 ;
2011-03-08 09:26:31 -05:00
$ default { "BISECT_SKIP" } = 1 ;
2010-11-02 14:58:27 -04:00
$ default { "SUCCESS_LINE" } = "login:" ;
$ default { "BOOTED_TIMEOUT" } = 1 ;
$ default { "DIE_ON_FAILURE" } = 1 ;
2010-11-02 14:35:37 -04:00
$ default { "SSH_EXEC" } = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND" ;
$ default { "SCP_TO_TARGET" } = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE" ;
$ default { "REBOOT" } = "ssh \$SSH_USER\@\$MACHINE reboot" ;
2010-11-09 12:55:40 -05:00
$ default { "STOP_AFTER_SUCCESS" } = 10 ;
$ default { "STOP_AFTER_FAILURE" } = 60 ;
2010-11-18 15:39:48 -05:00
$ default { "LOCALVERSION" } = "-test" ;
2010-11-02 15:01:32 -04:00
2010-11-18 15:39:48 -05:00
my $ ktest_config ;
2010-11-02 15:01:32 -04:00
my $ version ;
2010-11-02 14:58:27 -04:00
my $ machine ;
2010-11-02 14:35:37 -04:00
my $ ssh_user ;
2010-11-02 14:58:27 -04:00
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 ;
2010-11-02 14:35:37 -04:00
my $ reboot ;
2010-11-02 14:58:27 -04:00
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:35:37 -04:00
my $ ssh_exec ;
my $ scp_to_target ;
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 ;
2011-03-08 09:22:39 -05:00
my $ bisect_manual ;
2011-03-08 09:26:31 -05:00
my $ bisect_skip ;
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 ;
2010-11-09 12:55:40 -05:00
my $ stop_after_success ;
my $ stop_after_failure ;
2010-11-02 14:58:27 -04:00
my $ build_target ;
my $ target_image ;
my $ localversion ;
2010-11-02 14:58:38 -04:00
my $ iteration = 0 ;
2010-11-02 14:35:37 -04:00
my $ successes = 0 ;
2010-11-02 15:01:32 -04:00
2010-11-18 15:39:48 -05:00
my % entered_configs ;
my % config_help ;
$ config_help { "MACHINE" } = << "EOF"
The machine hostname that you will test .
EOF
;
$ config_help { "SSH_USER" } = << "EOF"
The box is expected to have ssh on normal bootup , provide the user
( most likely root , since you need privileged operations )
EOF
;
$ config_help { "BUILD_DIR" } = << "EOF"
The directory that contains the Linux source code ( full path ) .
EOF
;
$ config_help { "OUTPUT_DIR" } = << "EOF"
The directory that the objects will be built ( full path ) .
( can not be same as BUILD_DIR )
EOF
;
$ config_help { "BUILD_TARGET" } = << "EOF"
The location of the compiled file to copy to the target .
( relative to OUTPUT_DIR )
EOF
;
$ config_help { "TARGET_IMAGE" } = << "EOF"
The place to put your image on the test machine .
EOF
;
$ config_help { "POWER_CYCLE" } = << "EOF"
A script or command to reboot the box .
Here is a digital loggers power switch example
POWER_CYCLE = wget - - no - proxy - O /dev/ null - q - - auth - no - challenge 'http://admin:admin\@power/outlet?5=CCL'
Here is an example to reboot a virtual box on the current host
with the name "Guest" .
POWER_CYCLE = virsh destroy Guest ; sleep 5 ; virsh start Guest
EOF
;
$ config_help { "CONSOLE" } = << "EOF"
The script or command that reads the console
If you use ttywatch server , something like the following would work .
CONSOLE = nc - d localhost 3001
For a virtual machine with guest name "Guest" .
CONSOLE = virsh console Guest
EOF
;
$ config_help { "LOCALVERSION" } = << "EOF"
Required version ending to differentiate the test
from other linux builds on the system .
EOF
;
$ config_help { "REBOOT_TYPE" } = << "EOF"
Way to reboot the box to the test kernel .
Only valid options so far are "grub" and "script" .
If you specify grub , it will assume grub version 1
and will search in /boot/g rub / menu . lst for the title \ $ GRUB_MENU
and select that target to reboot to the kernel . If this is not
your setup , then specify "script" and have a command or script
specified in REBOOT_SCRIPT to boot to the target .
The entry in /boot/g rub / menu . lst must be entered in manually .
The test will not modify that file .
EOF
;
$ config_help { "GRUB_MENU" } = << "EOF"
The grub title name for the test kernel to boot
( Only mandatory if REBOOT_TYPE = grub )
Note , ktest . pl will not update the grub menu . lst , you need to
manually add an option for the test . ktest . pl will search
the grub menu . lst for this option to find what kernel to
reboot into .
For example , if in the /boot/g rub / menu . lst the test kernel title has:
title Test Kernel
kernel vmlinuz - test
GRUB_MENU = Test Kernel
EOF
;
$ config_help { "REBOOT_SCRIPT" } = << "EOF"
A script to reboot the target into the test kernel
( Only mandatory if REBOOT_TYPE = script )
EOF
;
sub get_ktest_config {
my ( $ config ) = @ _ ;
return if ( defined ( $ opt { $ config } ) ) ;
if ( defined ( $ config_help { $ config } ) ) {
print "\n" ;
print $ config_help { $ config } ;
}
for ( ; ; ) {
print "$config = " ;
if ( defined ( $ default { $ config } ) ) {
print "\[$default{$config}\] " ;
}
$ entered_configs { $ config } = <STDIN> ;
$ entered_configs { $ config } =~ s/^\s*(.*\S)\s*$/$1/ ;
if ( $ entered_configs { $ config } =~ /^\s*$/ ) {
if ( $ default { $ config } ) {
$ entered_configs { $ config } = $ default { $ config } ;
} else {
print "Your answer can not be blank\n" ;
next ;
}
}
last ;
}
}
sub get_ktest_configs {
get_ktest_config ( "MACHINE" ) ;
get_ktest_config ( "SSH_USER" ) ;
get_ktest_config ( "BUILD_DIR" ) ;
get_ktest_config ( "OUTPUT_DIR" ) ;
get_ktest_config ( "BUILD_TARGET" ) ;
get_ktest_config ( "TARGET_IMAGE" ) ;
get_ktest_config ( "POWER_CYCLE" ) ;
get_ktest_config ( "CONSOLE" ) ;
get_ktest_config ( "LOCALVERSION" ) ;
my $ rtype = $ opt { "REBOOT_TYPE" } ;
if ( ! defined ( $ rtype ) ) {
if ( ! defined ( $ opt { "GRUB_MENU" } ) ) {
get_ktest_config ( "REBOOT_TYPE" ) ;
$ rtype = $ entered_configs { "REBOOT_TYPE" } ;
} else {
$ rtype = "grub" ;
}
}
if ( $ rtype eq "grub" ) {
get_ktest_config ( "GRUB_MENU" ) ;
} else {
get_ktest_config ( "REBOOT_SCRIPT" ) ;
}
}
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" ;
}
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 ;
2010-11-02 14:35:37 -04:00
my $ old_repeat = $ repeat ;
2010-11-02 15:13:54 -04:00
$ 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 ;
2010-11-02 14:35:37 -04:00
$ repeat = $ old_repeat ;
2010-11-02 15:13:54 -04:00
}
} 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-18 15:39:48 -05:00
# make sure we have all mandatory configs
get_ktest_configs ;
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:35:37 -04:00
if ( run_command $ reboot ) {
2010-11-02 14:58:38 -04:00
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
2011-03-07 13:18:47 -05:00
if ( defined ( $ opt { "LOG_FILE" } ) ) {
print " See $opt{LOG_FILE} for more info.\n" ;
}
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-08 16:49:25 -05:00
doprint "KTEST RESULT: TEST $i 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-09 12:21:32 -05:00
my $ type = $ build_type ;
if ( $ type =~ /useconfig/ ) {
$ type = "useconfig" ;
}
my $ dir = "$machine-$test_type-$type-fail-$date" ;
2010-11-02 14:58:27 -04:00
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 ;
2010-11-02 14:35:37 -04:00
$ command =~ s/\$SSH_USER/$ssh_user/g ;
$ command =~ s/\$MACHINE/$machine/g ;
2010-11-02 14:58:05 -04:00
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 ;
}
2010-11-02 14:35:37 -04:00
sub run_ssh {
my ( $ cmd ) = @ _ ;
my $ cp_exec = $ ssh_exec ;
$ cp_exec =~ s/\$SSH_COMMAND/$cmd/g ;
return run_command "$cp_exec" ;
}
sub run_scp {
my ( $ src , $ dst ) = @ _ ;
my $ cp_scp = $ scp_to_target ;
$ cp_scp =~ s/\$SRC_FILE/$src/g ;
$ cp_scp =~ s/\$DST_FILE/$dst/g ;
return run_command "$cp_scp" ;
}
2010-11-02 14:57:33 -04:00
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 ;
2010-11-02 14:35:37 -04:00
my $ ssh_grub = $ ssh_exec ;
$ ssh_grub =~ s , \ $ SSH_COMMAND , cat /boot/g rub / menu . lst , g ;
open ( IN , "$ssh_grub |" )
2010-11-02 14:57:33 -04:00
or die "unable to get menu.lst" ;
2010-11-02 14:35:37 -04:00
2010-11-02 14:57:33 -04:00
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" ) {
2010-11-10 09:08:20 -05:00
run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'" ;
2010-11-02 14:58:27 -04:00
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
2010-11-09 12:55:40 -05:00
my $ success_start ;
my $ failure_start ;
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-09 12:55:40 -05:00
$ success_start = time ;
}
if ( $ booted && defined ( $ stop_after_success ) &&
$ stop_after_success >= 0 ) {
my $ now = time ;
if ( $ now - $ success_start >= $ stop_after_success ) {
doprint "Test forced to stop after $stop_after_success seconds after success\n" ;
last ;
}
2010-11-02 15:01:32 -04:00
}
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 ) {
2011-03-08 09:40:31 -05:00
if ( ! $ bug && ! $ skip_call_trace ) {
2010-11-09 12:55:40 -05:00
$ bug = 1 ;
$ failure_start = time ;
}
}
if ( $ bug && defined ( $ stop_after_failure ) &&
$ stop_after_failure >= 0 ) {
my $ now = time ;
if ( $ now - $ failure_start >= $ stop_after_failure ) {
doprint "Test forced to stop after $stop_after_failure seconds after failure\n" ;
last ;
}
2010-11-02 14:57:01 -04:00
}
if ( $ full_line =~ /\[ end of backtrace testing \]/ ) {
$ skip_call_trace = 0 ;
}
if ( $ full_line =~ /Kernel panic -/ ) {
2011-03-07 13:21:00 -05:00
$ failure_start = time ;
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:35:37 -04:00
run_scp "$outputdir/$build_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:35:37 -04:00
run_ssh "rm -rf $modlib" or
2010-11-02 14:57:33 -04:00
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:35:37 -04:00
run_scp "$tmpdir/$modtar" , "/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
2010-11-02 14:35:37 -04:00
run_ssh "'(cd / && tar xf /tmp/$modtar)'" or
2010-11-02 14:57:33 -04:00
dodie "failed to tar modules" ;
2010-11-02 15:01:32 -04:00
2010-11-02 14:35:37 -04:00
run_ssh "rm -f /tmp/$modtar" ;
2010-11-02 14:58:33 -04:00
return if ( ! defined ( $ post_install ) ) ;
2010-11-02 14:35:37 -04:00
my $ cp_post_install = $ post_install ;
$ cp_post_install = s/\$KERNEL_VERSION/$version/g ;
run_command "$cp_post_install" or
2010-11-02 14:58:38 -04:00
dodie "Failed to run post install" ;
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
}
2011-03-07 13:27:43 -05:00
sub make_oldconfig {
my ( $ defconfig ) = @ _ ;
if ( ! run_command "$defconfig $make oldnoconfig" ) {
# Perhaps oldnoconfig doesn't exist in this version of the kernel
# try a yes '' | oldconfig
doprint "oldnoconfig failed, trying yes '' | make oldconfig\n" ;
run_command "yes '' | $defconfig $make oldconfig" or
dodie "failed make config oldconfig" ;
}
}
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
}
2011-03-07 13:27:43 -05:00
if ( $ type eq "oldnoconfig" ) {
make_oldconfig $ defconfig ;
} else {
run_command "$defconfig $make $type" or
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:35:37 -04:00
if ( ! run_ssh "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 ) = @ _ ;
2010-11-02 14:35:37 -04:00
$ successes + + ;
2010-11-02 14:57:33 -04:00
doprint "\n\n*******************************************\n" ;
doprint "*******************************************\n" ;
2010-11-08 16:49:25 -05:00
doprint "KTEST RESULT: 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" ;
}
2011-03-08 09:22:39 -05:00
sub answer_bisect {
for ( ; ; ) {
doprint "Pass or fail? [p/f]" ;
my $ ans = <STDIN> ;
chomp $ ans ;
if ( $ ans eq "p" || $ ans eq "P" ) {
return 1 ;
} elsif ( $ ans eq "f" || $ ans eq "F" ) {
return 0 ;
} else {
print "Please answer 'P' or 'F'\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 ;
}
2011-03-08 09:26:31 -05:00
sub bisect_reboot {
doprint "Reboot and sleep $bisect_sleep_time seconds\n" ;
reboot ;
start_monitor ;
wait_for_monitor $ bisect_sleep_time ;
end_monitor ;
}
# returns 1 on success, 0 on failure, -1 on skip
2010-11-08 11:14:10 -05:00
sub run_bisect_test {
my ( $ type , $ buildtype ) = @ _ ;
2010-11-02 14:57:33 -04:00
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 ;
2010-11-08 11:14:10 -05:00
$ in_bisect = 1 ;
build $ buildtype or $ failed = 1 ;
2010-11-02 14:57:33 -04:00
if ( $ type ne "build" ) {
2011-03-08 09:26:31 -05:00
if ( $ failed && $ bisect_skip ) {
$ in_bisect = 0 ;
return - 1 ;
}
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" ) {
2011-03-08 09:26:31 -05:00
if ( $ failed && $ bisect_skip ) {
end_monitor ;
bisect_reboot ;
$ in_bisect = 0 ;
return - 1 ;
}
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 ) {
2010-11-08 11:14:10 -05:00
$ result = 0 ;
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" ) {
2011-03-08 09:26:31 -05:00
bisect_reboot ;
2010-11-02 14:57:43 -04:00
}
2010-11-02 14:57:33 -04:00
} else {
2010-11-08 11:14:10 -05:00
$ result = 1 ;
}
$ in_bisect = 0 ;
return $ result ;
}
sub run_bisect {
my ( $ type ) = @ _ ;
my $ buildtype = "oldconfig" ;
# We should have a minconfig to use?
if ( defined ( $ minconfig ) ) {
$ buildtype = "useconfig:$minconfig" ;
2010-11-02 14:57:33 -04:00
}
2010-11-08 11:14:10 -05:00
my $ ret = run_bisect_test $ type , $ buildtype ;
2011-03-08 09:22:39 -05:00
if ( $ bisect_manual ) {
$ ret = answer_bisect ;
}
2010-11-08 11:14:10 -05:00
2010-11-02 14:58:05 -04:00
# Are we looking for where it worked, not failed?
if ( $ reverse_bisect ) {
2010-11-08 11:14:10 -05:00
$ ret = ! $ ret ;
2010-11-02 14:58:05 -04:00
}
2011-03-08 09:26:31 -05:00
if ( $ ret > 0 ) {
2010-11-08 11:14:10 -05:00
return "good" ;
2011-03-08 09:26:31 -05:00
} elsif ( $ ret == 0 ) {
2010-11-08 11:14:10 -05:00
return "bad" ;
2011-03-08 09:26:31 -05:00
} elsif ( $ bisect_skip ) {
doprint "HIT A BAD COMMIT ... SKIPPING\n" ;
return "skip" ;
2010-11-08 11:14:10 -05:00
}
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]" } ;
2011-03-08 09:38:12 -05:00
my $ start_files = $ opt { "BISECT_FILES[$i]" } ;
if ( defined ( $ start_files ) ) {
$ start_files = " -- " . $ start_files ;
} else {
$ start_files = "" ;
}
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: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" ;
}
2011-03-08 09:38:12 -05:00
run_command "git bisect start$start_files" 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" ;
2010-11-08 11:14:10 -05:00
success $ i ;
}
my % config_ignore ;
my % config_set ;
my % config_list ;
my % null_config ;
my % dependency ;
sub process_config_ignore {
my ( $ config ) = @ _ ;
open ( IN , $ config )
or dodie "Failed to read $config" ;
while ( <IN> ) {
if ( /^(.*?(CONFIG\S*)(=.*| is not set))/ ) {
$ config_ignore { $ 2 } = $ 1 ;
}
}
close ( IN ) ;
}
sub read_current_config {
my ( $ config_ref ) = @ _ ;
% { $ config_ref } = ( ) ;
undef % { $ config_ref } ;
my @ key = keys % { $ config_ref } ;
if ( $# key >= 0 ) {
print "did not delete!\n" ;
exit ;
}
open ( IN , "$output_config" ) ;
while ( <IN> ) {
if ( /^(CONFIG\S+)=(.*)/ ) {
$ { $ config_ref } { $ 1 } = $ 2 ;
}
}
close ( IN ) ;
}
sub get_dependencies {
my ( $ config ) = @ _ ;
my $ arr = $ dependency { $ config } ;
if ( ! defined ( $ arr ) ) {
return ( ) ;
}
my @ deps = @ { $ arr } ;
foreach my $ dep ( @ { $ arr } ) {
print "ADD DEP $dep\n" ;
@ deps = ( @ deps , get_dependencies $ dep ) ;
}
return @ deps ;
}
sub create_config {
my @ configs = @ _ ;
open ( OUT , ">$output_config" ) or dodie "Can not write to $output_config" ;
foreach my $ config ( @ configs ) {
print OUT "$config_set{$config}\n" ;
my @ deps = get_dependencies $ config ;
foreach my $ dep ( @ deps ) {
print OUT "$config_set{$dep}\n" ;
}
}
foreach my $ config ( keys % config_ignore ) {
print OUT "$config_ignore{$config}\n" ;
}
close ( OUT ) ;
# exit;
2011-03-07 13:27:43 -05:00
make_oldconfig "" ;
2010-11-08 11:14:10 -05:00
}
sub compare_configs {
my ( % a , % b ) = @ _ ;
foreach my $ item ( keys % a ) {
if ( ! defined ( $ b { $ item } ) ) {
print "diff $item\n" ;
return 1 ;
}
delete $ b { $ item } ;
}
my @ keys = keys % b ;
if ( $# keys ) {
print "diff2 $keys[0]\n" ;
}
return - 1 if ( $# keys >= 0 ) ;
return 0 ;
}
sub run_config_bisect_test {
my ( $ type ) = @ _ ;
return run_bisect_test $ type , "oldconfig" ;
}
sub process_passed {
my ( % configs ) = @ _ ;
doprint "These configs had no failure: (Enabling them for further compiles)\n" ;
# Passed! All these configs are part of a good compile.
# Add them to the min options.
foreach my $ config ( keys % configs ) {
if ( defined ( $ config_list { $ config } ) ) {
doprint " removing $config\n" ;
$ config_ignore { $ config } = $ config_list { $ config } ;
delete $ config_list { $ config } ;
}
}
2010-11-11 11:34:38 -05:00
doprint "config copied to $outputdir/config_good\n" ;
run_command "cp -f $output_config $outputdir/config_good" ;
2010-11-08 11:14:10 -05:00
}
sub process_failed {
my ( $ config ) = @ _ ;
doprint "\n\n***************************************\n" ;
doprint "Found bad config: $config\n" ;
doprint "***************************************\n\n" ;
}
sub run_config_bisect {
my @ start_list = keys % config_list ;
if ( $# start_list < 0 ) {
doprint "No more configs to test!!!\n" ;
return - 1 ;
}
doprint "***** RUN TEST ***\n" ;
my $ type = $ opt { "CONFIG_BISECT_TYPE[$iteration]" } ;
my $ ret ;
my % current_config ;
my $ count = $# start_list + 1 ;
doprint " $count configs to test\n" ;
my $ half = int ( $# start_list / 2 ) ;
do {
my @ tophalf = @ start_list [ 0 .. $ half ] ;
create_config @ tophalf ;
read_current_config \ % current_config ;
$ count = $# tophalf + 1 ;
doprint "Testing $count configs\n" ;
my $ found = 0 ;
# make sure we test something
foreach my $ config ( @ tophalf ) {
if ( defined ( $ current_config { $ config } ) ) {
logit " $config\n" ;
$ found = 1 ;
}
}
if ( ! $ found ) {
# try the other half
doprint "Top half produced no set configs, trying bottom half\n" ;
@ tophalf = @ start_list [ $ half .. $# start_list ] ;
create_config @ tophalf ;
read_current_config \ % current_config ;
foreach my $ config ( @ tophalf ) {
if ( defined ( $ current_config { $ config } ) ) {
logit " $config\n" ;
$ found = 1 ;
}
}
if ( ! $ found ) {
doprint "Failed: Can't make new config with current configs\n" ;
foreach my $ config ( @ start_list ) {
doprint " CONFIG: $config\n" ;
}
return - 1 ;
}
$ count = $# tophalf + 1 ;
doprint "Testing $count configs\n" ;
}
$ ret = run_config_bisect_test $ type ;
2011-03-08 09:22:39 -05:00
if ( $ bisect_manual ) {
$ ret = answer_bisect ;
}
2010-11-08 11:14:10 -05:00
if ( $ ret ) {
process_passed % current_config ;
return 0 ;
}
doprint "This config had a failure.\n" ;
doprint "Removing these configs that were not set in this config:\n" ;
2010-11-11 11:34:38 -05:00
doprint "config copied to $outputdir/config_bad\n" ;
run_command "cp -f $output_config $outputdir/config_bad" ;
2010-11-08 11:14:10 -05:00
# A config exists in this group that was bad.
foreach my $ config ( keys % config_list ) {
if ( ! defined ( $ current_config { $ config } ) ) {
doprint " removing $config\n" ;
delete $ config_list { $ config } ;
}
}
@ start_list = @ tophalf ;
if ( $# start_list == 0 ) {
process_failed $ start_list [ 0 ] ;
return 1 ;
}
# remove half the configs we are looking at and see if
# they are good.
$ half = int ( $# start_list / 2 ) ;
} while ( $ half > 0 ) ;
2011-03-08 09:22:39 -05:00
# we found a single config, try it again unless we are running manually
if ( $ bisect_manual ) {
process_failed $ start_list [ 0 ] ;
return 1 ;
}
2010-11-08 11:14:10 -05:00
my @ tophalf = @ start_list [ 0 .. 0 ] ;
$ ret = run_config_bisect_test $ type ;
if ( $ ret ) {
process_passed % current_config ;
return 0 ;
}
process_failed $ start_list [ 0 ] ;
return 1 ;
}
sub config_bisect {
my ( $ i ) = @ _ ;
my $ start_config = $ opt { "CONFIG_BISECT[$i]" } ;
my $ tmpconfig = "$tmpdir/use_config" ;
# Make the file with the bad config and the min config
if ( defined ( $ minconfig ) ) {
# read the min config for things to ignore
run_command "cp $minconfig $tmpconfig" or
dodie "failed to copy $minconfig to $tmpconfig" ;
} else {
unlink $ tmpconfig ;
}
# Add other configs
if ( defined ( $ addconfig ) ) {
run_command "cat $addconfig >> $tmpconfig" or
dodie "failed to append $addconfig" ;
}
my $ defconfig = "" ;
if ( - f $ tmpconfig ) {
$ defconfig = "KCONFIG_ALLCONFIG=$tmpconfig" ;
process_config_ignore $ tmpconfig ;
}
# now process the start config
run_command "cp $start_config $output_config" or
dodie "failed to copy $start_config to $output_config" ;
# read directly what we want to check
my % config_check ;
open ( IN , $ output_config )
or dodie "faied to open $output_config" ;
while ( <IN> ) {
if ( /^((CONFIG\S*)=.*)/ ) {
$ config_check { $ 2 } = $ 1 ;
}
}
close ( IN ) ;
# Now run oldconfig with the minconfig (and addconfigs)
2011-03-07 13:27:43 -05:00
make_oldconfig $ defconfig ;
2010-11-08 11:14:10 -05:00
# check to see what we lost (or gained)
open ( IN , $ output_config )
or dodie "Failed to read $start_config" ;
my % removed_configs ;
my % added_configs ;
while ( <IN> ) {
if ( /^((CONFIG\S*)=.*)/ ) {
# save off all options
$ config_set { $ 2 } = $ 1 ;
if ( defined ( $ config_check { $ 2 } ) ) {
if ( defined ( $ config_ignore { $ 2 } ) ) {
$ removed_configs { $ 2 } = $ 1 ;
} else {
$ config_list { $ 2 } = $ 1 ;
}
} elsif ( ! defined ( $ config_ignore { $ 2 } ) ) {
$ added_configs { $ 2 } = $ 1 ;
$ config_list { $ 2 } = $ 1 ;
}
}
}
close ( IN ) ;
my @ confs = keys % removed_configs ;
if ( $# confs >= 0 ) {
doprint "Configs overridden by default configs and removed from check:\n" ;
foreach my $ config ( @ confs ) {
doprint " $config\n" ;
}
}
@ confs = keys % added_configs ;
if ( $# confs >= 0 ) {
doprint "Configs appearing in make oldconfig and added:\n" ;
foreach my $ config ( @ confs ) {
doprint " $config\n" ;
}
}
my % config_test ;
my $ once = 0 ;
# Sometimes kconfig does weird things. We must make sure
# that the config we autocreate has everything we need
# to test, otherwise we may miss testing configs, or
# may not be able to create a new config.
# Here we create a config with everything set.
create_config ( keys % config_list ) ;
read_current_config \ % config_test ;
foreach my $ config ( keys % config_list ) {
if ( ! defined ( $ config_test { $ config } ) ) {
if ( ! $ once ) {
$ once = 1 ;
doprint "Configs not produced by kconfig (will not be checked):\n" ;
}
doprint " $config\n" ;
delete $ config_list { $ config } ;
}
}
my $ ret ;
do {
$ ret = run_config_bisect ;
} while ( ! $ ret ) ;
return $ ret if ( $ ret < 0 ) ;
2010-11-02 14:57:33 -04:00
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-18 15:39:48 -05:00
$# ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n" ;
if ( $# ARGV == 0 ) {
$ ktest_config = $ ARGV [ 0 ] ;
if ( ! - f $ ktest_config ) {
print "$ktest_config does not exist.\n" ;
my $ ans ;
for ( ; ; ) {
print "Create it? [Y/n] " ;
$ ans = <STDIN> ;
chomp $ ans ;
if ( $ ans =~ /^\s*$/ ) {
$ ans = "y" ;
}
last if ( $ ans =~ /^y$/i || $ ans =~ /^n$/i ) ;
print "Please answer either 'y' or 'n'.\n" ;
}
if ( $ ans !~ /^y$/i ) {
exit 0 ;
}
}
} else {
$ ktest_config = "ktest.conf" ;
}
if ( ! - f $ ktest_config ) {
open ( OUT , ">$ktest_config" ) or die "Can not create $ktest_config" ;
print OUT << "EOF"
# Generated by ktest.pl
#
# Define each test with TEST_START
# The config options below it will override the defaults
TEST_START
DEFAULTS
EOF
;
close ( OUT ) ;
}
read_config $ ktest_config ;
# Append any configs entered in manually to the config file.
my @ new_configs = keys % entered_configs ;
if ( $# new_configs >= 0 ) {
print "\nAppending entered in configs to $ktest_config\n" ;
open ( OUT , ">>$ktest_config" ) or die "Can not append to $ktest_config" ;
foreach my $ config ( @ new_configs ) {
print OUT "$config = $entered_configs{$config}\n" ;
$ opt { $ config } = $ entered_configs { $ config } ;
}
}
2010-11-02 15:01:32 -04:00
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 $ makecmd = set_test_option ( "MAKE_CMD" , $ i ) ;
$ machine = set_test_option ( "MACHINE" , $ i ) ;
2010-11-02 14:35:37 -04:00
$ ssh_user = set_test_option ( "SSH_USER" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ 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 ) ;
2010-11-02 14:35:37 -04:00
$ reboot = set_test_option ( "REBOOT" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ 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 ) ;
2011-03-08 09:22:39 -05:00
$ bisect_manual = set_test_option ( "BISECT_MANUAL" , $ i ) ;
2011-03-08 09:26:31 -05:00
$ bisect_skip = set_test_option ( "BISECT_SKIP" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ 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 ) ;
2010-11-09 12:55:40 -05:00
$ stop_after_success = set_test_option ( "STOP_AFTER_SUCCESS" , $ i ) ;
$ stop_after_failure = set_test_option ( "STOP_AFTER_FAILURE" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ build_target = set_test_option ( "BUILD_TARGET" , $ i ) ;
2010-11-02 14:35:37 -04:00
$ ssh_exec = set_test_option ( "SSH_EXEC" , $ i ) ;
$ scp_to_target = set_test_option ( "SCP_TO_TARGET" , $ i ) ;
2010-11-02 14:58:27 -04:00
$ 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:35:37 -04:00
$ ENV { "SSH_USER" } = $ ssh_user ;
$ ENV { "MACHINE" } = $ machine ;
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]" } ;
2010-11-08 11:14:10 -05:00
} elsif ( $ test_type eq "config_bisect" ) {
$ run_type = $ opt { "CONFIG_BISECT_TYPE[$i]" } ;
2010-11-02 14:58:27 -04:00
}
# 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-09 12:20:21 -05:00
run_command "cat $addconfig $minconfig > $tmpdir/add_config" or
2010-11-02 14:58:15 -04:00
dodie "Failed to create temp config" ;
2010-11-09 12:20:21 -05:00
$ minconfig = "$tmpdir/add_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-08 11:14:10 -05:00
} elsif ( $ test_type eq "config_bisect" ) {
config_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 14:35:37 -04:00
doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n" ;
2010-11-02 15:01:32 -04:00
exit 0 ;