ktest.pl 25.2 KB
Newer Older
S
Steven Rostedt 已提交
1
#!/usr/bin/perl -w
2 3 4 5
#
# Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
# Licensed under the terms of the GNU GPL License version 2
#
S
Steven Rostedt 已提交
6 7 8 9

use strict;
use IPC::Open2;
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
10 11
use File::Path qw(mkpath);
use File::Copy qw(cp);
S
Steven Rostedt 已提交
12 13 14 15 16 17 18
use FileHandle;

$#ARGV >= 0 || die "usage: autotest.pl config-file\n";

$| = 1;

my %opt;
19
my %default;
S
Steven Rostedt 已提交
20 21

#default opts
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
$default{"NUM_TESTS"}		= 5;
$default{"REBOOT_TYPE"}		= "grub";
$default{"TEST_TYPE"}		= "test";
$default{"BUILD_TYPE"}		= "randconfig";
$default{"MAKE_CMD"}		= "make";
$default{"TIMEOUT"}		= 120;
$default{"TMP_DIR"}		= "/tmp/autotest";
$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;
S
Steven Rostedt 已提交
41 42

my $version;
43 44 45 46 47
my $machine;
my $tmpdir;
my $builddir;
my $outputdir;
my $test_type;
48
my $build_type;
49 50 51 52 53 54 55
my $build_options;
my $reboot_type;
my $reboot_script;
my $power_cycle;
my $reboot_on_error;
my $poweroff_on_error;
my $die_on_failure;
56 57
my $powercycle_after_reboot;
my $poweroff_after_halt;
58 59
my $power_off;
my $grub_menu;
S
Steven Rostedt 已提交
60 61 62
my $grub_number;
my $target;
my $make;
63
my $post_install;
64
my $noclean;
65
my $minconfig;
66
my $addconfig;
67 68
my $in_bisect = 0;
my $bisect_bad = "";
69
my $reverse_bisect;
S
Steven Rostedt 已提交
70
my $in_patchcheck = 0;
71
my $run_test;
S
Steven Rostedt 已提交
72
my $redirect;
73 74 75 76 77
my $buildlog;
my $dmesg;
my $monitor_fp;
my $monitor_pid;
my $monitor_cnt = 0;
78 79 80 81 82 83 84 85 86 87
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;
88
my $iteration = 0;
S
Steven Rostedt 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

sub read_config {
    my ($config) = @_;

    open(IN, $config) || die "can't read file $config";

    while (<IN>) {

	# ignore blank lines and comments
	next if (/^\s*$/ || /\s*\#/);

	if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) {
	    my $lvalue = $1;
	    my $rvalue = $2;

104 105 106
	    if (defined($opt{$lvalue})) {
		die "Error: Option $lvalue defined more than once!\n";
	    }
S
Steven Rostedt 已提交
107 108 109 110 111
	    $opt{$lvalue} = $rvalue;
	}
    }

    close(IN);
112 113 114 115 116 117 118 119

    # set any defaults

    foreach my $default (keys %default) {
	if (!defined($opt{$default})) {
	    $opt{$default} = $default{$default};
	}
    }
S
Steven Rostedt 已提交
120 121
}

122
sub logit {
S
Steven Rostedt 已提交
123 124 125 126 127 128 129
    if (defined($opt{"LOG_FILE"})) {
	open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
	print OUT @_;
	close(OUT);
    }
}

130 131 132 133 134
sub doprint {
    print @_;
    logit @_;
}

135 136 137 138
sub run_command;

sub reboot {
    # try to reboot normally
139 140 141 142 143 144
    if (run_command "ssh $target reboot") {
	if (defined($powercycle_after_reboot)) {
	    sleep $powercycle_after_reboot;
	    run_command "$power_cycle";
	}
    } else {
145
	# nope? power cycle it.
146
	run_command "$power_cycle";
147 148 149
    }
}

150 151 152 153 154 155 156 157
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");
}

158
sub dodie {
159
    doprint "CRITICAL FAILURE... ", @_, "\n";
160

161 162 163 164
    my $i = $iteration;

    if ($reboot_on_error && !do_not_reboot) {

165
	doprint "REBOOTING\n";
166
	reboot;
167

168
    } elsif ($poweroff_on_error && defined($power_off)) {
169
	doprint "POWERING OFF\n";
170
	`$power_off`;
171
    }
172

173
    die @_, "\n";
174 175
}

176 177 178 179 180
sub open_console {
    my ($fp) = @_;

    my $flags;

181 182
    my $pid = open($fp, "$console|") or
	dodie "Can't open console $console";
183 184

    $flags = fcntl($fp, F_GETFL, 0) or
185
	dodie "Can't get flags for the socket: $!";
186
    $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
187
	dodie "Can't set flags for the socket: $!";
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207

    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;
208 209 210 211

    return;

    open(MONFD, "Stop perl from warning about single use of MONFD");
212 213 214 215 216 217 218 219 220 221 222 223 224
}

sub end_monitor {
    if (--$monitor_cnt) {
	return;
    }
    close_console($monitor_fp, $monitor_pid);
}

sub wait_for_monitor {
    my ($time) = @_;
    my $line;

225
    doprint "** Wait for monitor to settle down **\n";
226 227 228 229

    # read the monitor and wait for the system to calm down
    do {
	$line = wait_for_input($monitor_fp, $time);
230
	print "$line" if (defined($line));
231
    } while (defined($line));
232
    print "** Monitor flushed **\n";
233 234
}

235 236
sub fail {

237
	if ($die_on_failure) {
238 239 240
		dodie @_;
	}

241
	doprint "FAILED\n";
242

243 244
	my $i = $iteration;

245
	# no need to reboot for just building.
246
	if (!do_not_reboot) {
247 248 249 250 251 252
	    doprint "REBOOTING\n";
	    reboot;
	    start_monitor;
	    wait_for_monitor $sleep_time;
	    end_monitor;
	}
253

254 255
	doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
	doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
256
	doprint "**** Failed: ", @_, " ****\n";
257 258
	doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
	doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
259 260

	return 1 if (!defined($store_failures));
261 262 263 264 265

	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];

266 267
	my $dir = "$machine-$test_type-$build_type-fail-$date";
	my $faildir = "$store_failures/$dir";
268 269 270

	if (!-d $faildir) {
	    mkpath($faildir) or
271
		die "can't create $faildir";
272
	}
273 274
	if (-f "$outputdir/.config") {
	    cp "$outputdir/.config", "$faildir/config" or
275 276 277 278 279 280 281 282 283 284 285 286 287
		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";

288 289 290
	return 1;
}

S
Steven Rostedt 已提交
291 292
sub run_command {
    my ($command) = @_;
293 294 295 296 297 298 299
    my $dolog = 0;
    my $dord = 0;
    my $pid;

    doprint("$command ... ");

    $pid = open(CMD, "$command 2>&1 |") or
300
	(fail "unable to exec $command" and return 0);
S
Steven Rostedt 已提交
301 302

    if (defined($opt{"LOG_FILE"})) {
303 304 305
	open(LOG, ">>$opt{LOG_FILE}") or
	    dodie "failed to write to log";
	$dolog = 1;
S
Steven Rostedt 已提交
306 307 308
    }

    if (defined($redirect)) {
309 310 311
	open (RD, ">$redirect") or
	    dodie "failed to write to redirect $redirect";
	$dord = 1;
S
Steven Rostedt 已提交
312 313
    }

314 315 316 317
    while (<CMD>) {
	print LOG if ($dolog);
	print RD  if ($dord);
    }
S
Steven Rostedt 已提交
318

319
    waitpid($pid, 0);
S
Steven Rostedt 已提交
320 321
    my $failed = $?;

322 323 324 325
    close(CMD);
    close(LOG) if ($dolog);
    close(RD)  if ($dord);

S
Steven Rostedt 已提交
326 327 328 329 330 331
    if ($failed) {
	doprint "FAILED!\n";
    } else {
	doprint "SUCCESS\n";
    }

332 333 334 335 336
    return !$failed;
}

sub get_grub_index {

337 338 339
    if ($reboot_type ne "grub") {
	return;
    }
340
    return if (defined($grub_number));
341 342 343 344 345 346

    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>) {
347
	if (/^\s*title\s+$grub_menu\s*$/) {
348 349 350 351 352 353 354 355
	    $grub_number++;
	    last;
	} elsif (/^\s*title\s/) {
	    $grub_number++;
	}
    }
    close(IN);

356
    die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
357 358
	if ($grub_number < 0);
    doprint "$grub_number\n";
S
Steven Rostedt 已提交
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
}

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;
}

392
sub reboot_to {
393 394 395 396 397 398
    if ($reboot_type eq "grub") {
	run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
	return;
    }

    run_command "$reboot_script";
S
Steven Rostedt 已提交
399 400
}

401
sub monitor {
S
Steven Rostedt 已提交
402 403
    my $booted = 0;
    my $bug = 0;
404
    my $skip_call_trace = 0;
405
    my $loops;
S
Steven Rostedt 已提交
406

407
    wait_for_monitor 5;
S
Steven Rostedt 已提交
408 409 410 411

    my $line;
    my $full_line = "";

412 413
    open(DMESG, "> $dmesg") or
	die "unable to write to $dmesg";
S
Steven Rostedt 已提交
414

415
    reboot_to;
S
Steven Rostedt 已提交
416 417 418

    for (;;) {

419
	if ($booted) {
420
	    $line = wait_for_input($monitor_fp, $booted_timeout);
421
	} else {
422
	    $line = wait_for_input($monitor_fp);
423
	}
S
Steven Rostedt 已提交
424 425 426 427

	last if (!defined($line));

	doprint $line;
428
	print DMESG $line;
S
Steven Rostedt 已提交
429 430 431 432

	# we are not guaranteed to get a full line
	$full_line .= $line;

433
	if ($full_line =~ /$success_line/) {
S
Steven Rostedt 已提交
434 435 436
	    $booted = 1;
	}

437 438 439 440
	if ($full_line =~ /\[ backtrace testing \]/) {
	    $skip_call_trace = 1;
	}

S
Steven Rostedt 已提交
441
	if ($full_line =~ /call trace:/i) {
442 443 444 445 446 447 448 449
	    $bug = 1 if (!$skip_call_trace);
	}

	if ($full_line =~ /\[ end of backtrace testing \]/) {
	    $skip_call_trace = 0;
	}

	if ($full_line =~ /Kernel panic -/) {
S
Steven Rostedt 已提交
450 451 452 453 454 455 456 457
	    $bug = 1;
	}

	if ($line =~ /\n/) {
	    $full_line = "";
	}
    }

458
    close(DMESG);
S
Steven Rostedt 已提交
459

460
    if ($bug) {
461
	return 0 if ($in_bisect);
462
	fail "failed - got a bug report" and return 0;
S
Steven Rostedt 已提交
463 464
    }

465
    if (!$booted) {
466
	return 0 if ($in_bisect);
467
	fail "failed - never got a boot prompt." and return 0;
S
Steven Rostedt 已提交
468
    }
469

470
    return 1;
S
Steven Rostedt 已提交
471 472 473 474
}

sub install {

475
    run_command "scp $outputdir/$build_target $target:$target_image" or
476
	dodie "failed to copy image";
S
Steven Rostedt 已提交
477

478
    my $install_mods = 0;
S
Steven Rostedt 已提交
479

480 481
    # should we process modules?
    $install_mods = 0;
482
    open(IN, "$outputdir/.config") or dodie("Can't read config file");
483 484 485 486
    while (<IN>) {
	if (/CONFIG_MODULES(=y)?/) {
	    $install_mods = 1 if (defined($1));
	    last;
487
	}
488 489
    }
    close(IN);
490

491 492 493 494
    if (!$install_mods) {
	doprint "No modules needed\n";
	return;
    }
S
Steven Rostedt 已提交
495

496
    run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
497
	dodie "Failed to install modules";
498

499 500
    my $modlib = "/lib/modules/$version";
    my $modtar = "autotest-mods.tar.bz2";
501

502 503
    run_command "ssh $target rm -rf $modlib" or
	dodie "failed to remove old mods: $modlib";
504

505
    # would be nice if scp -r did not follow symbolic links
506
    run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
507 508
	dodie "making tarball";

509
    run_command "scp $tmpdir/$modtar $target:/tmp" or
510 511
	dodie "failed to copy modules";

512
    unlink "$tmpdir/$modtar";
513 514 515

    run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
	dodie "failed to tar modules";
S
Steven Rostedt 已提交
516

517
    run_command "ssh $target rm -f /tmp/$modtar";
518 519 520 521 522 523

    return if (!defined($post_install));

    my $save_env = $ENV{KERNEL_VERSION};

    $ENV{KERNEL_VERSION} = $version;
524 525
    run_command "$post_install" or
	dodie "Failed to run post install";
526 527

    $ENV{KERNEL_VERSION} = $save_env;
S
Steven Rostedt 已提交
528 529
}

S
Steven Rostedt 已提交
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
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) {
550
		my $fullpath = "$builddir/$file";
S
Steven Rostedt 已提交
551
		if ($file eq $err || $fullpath eq $err) {
552
		    fail "$file built with warnings" and return 0;
S
Steven Rostedt 已提交
553 554 555 556 557
		}
	    }
	}
    }
    close(IN);
558 559

    return 1;
S
Steven Rostedt 已提交
560 561
}

S
Steven Rostedt 已提交
562 563
sub build {
    my ($type) = @_;
564 565 566
    my $defconfig = "";
    my $append = "";

567 568
    unlink $buildlog;

569
    if ($type =~ /^useconfig:(.*)/) {
570
	run_command "cp $1 $outputdir/.config" or
571
	    dodie "could not copy $1 to .config";
572

573 574 575
	$type = "oldconfig";
    }

576 577 578
    # old config can ask questions
    if ($type eq "oldconfig") {
	$append = "yes ''|";
579 580

	# allow for empty configs
581
	run_command "touch $outputdir/.config";
582

583
	run_command "mv $outputdir/.config $outputdir/config_temp" or
584
	    dodie "moving .config";
S
Steven Rostedt 已提交
585

586
	if (!$noclean && !run_command "$make mrproper") {
587 588
	    dodie "make mrproper";
	}
S
Steven Rostedt 已提交
589

590
	run_command "mv $outputdir/config_temp $outputdir/.config" or
591 592 593
	    dodie "moving config_temp";

    } elsif (!$noclean) {
594
	unlink "$outputdir/.config";
595
	run_command "$make mrproper" or
596 597
	    dodie "make mrproper";
    }
S
Steven Rostedt 已提交
598 599

    # add something to distinguish this build
600 601
    open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file");
    print OUT "$localversion\n";
S
Steven Rostedt 已提交
602 603
    close(OUT);

604 605
    if (defined($minconfig)) {
	$defconfig = "KCONFIG_ALLCONFIG=$minconfig";
S
Steven Rostedt 已提交
606 607
    }

608
    run_command "$append $defconfig $make $type" or
609
	dodie "failed make config";
S
Steven Rostedt 已提交
610

611 612
    $redirect = "$buildlog";
    if (!run_command "$make $build_options") {
S
Steven Rostedt 已提交
613
	undef $redirect;
614
	# bisect may need this to pass
615 616
	return 0 if ($in_bisect);
	fail "failed build" and return 0;
S
Steven Rostedt 已提交
617
    }
S
Steven Rostedt 已提交
618
    undef $redirect;
619

620
    return 1;
S
Steven Rostedt 已提交
621 622
}

623
sub halt {
624
    if (!run_command "ssh $target halt" or defined($power_off)) {
625 626 627 628 629
	if (defined($poweroff_after_halt)) {
	    sleep $poweroff_after_halt;
	    run_command "$power_off";
	}
    } else {
630
	# nope? the zap it!
631
	run_command "$power_off";
632 633 634
    }
}

635 636 637 638 639
sub success {
    my ($i) = @_;

    doprint "\n\n*******************************************\n";
    doprint     "*******************************************\n";
640
    doprint     "**           TEST $i SUCCESS!!!!         **\n";
641 642 643
    doprint     "*******************************************\n";
    doprint     "*******************************************\n";

644
    if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
645
	doprint "Reboot and wait $sleep_time seconds\n";
646
	reboot;
647
	start_monitor;
648
	wait_for_monitor $sleep_time;
649
	end_monitor;
650 651 652 653 654 655 656 657 658 659 660
    }
}

sub get_version {
    # get the release name
    doprint "$make kernelrelease ... ";
    $version = `$make kernelrelease | tail -1`;
    chomp($version);
    doprint "$version\n";
}

661
sub child_run_test {
662
    my $failed = 0;
663

664
    # child should have no power
665 666 667
    $reboot_on_error = 0;
    $poweroff_on_error = 0;
    $die_on_failure = 1;
668 669

    run_command $run_test or $failed = 1;
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
    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;

686
    wait_for_monitor 1;
687

688
    doprint "run test $run_test\n";
689 690 691 692 693 694 695 696 697 698 699 700

    $child_done = 0;

    $SIG{CHLD} = qw(child_finished);

    $child_pid = fork;

    child_run_test if (!$child_pid);

    $full_line = "";

    do {
701
	$line = wait_for_input($monitor_fp, 1);
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
	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) {
731 732
	return 0 if $in_bisect;
	fail "test failed" and return 0;
733
    }
734
    return 1;
735 736
}

737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
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;
}

767 768 769
sub run_bisect {
    my ($type) = @_;

770
    my $failed = 0;
771 772 773 774 775
    my $result;
    my $output;
    my $ret;

    if (defined($minconfig)) {
776
	build "useconfig:$minconfig" or $failed = 1;
777 778
    } else {
	# ?? no config to use?
779
	build "oldconfig" or $failed = 1;
780 781 782
    }

    if ($type ne "build") {
783
	dodie "Failed on build" if $failed;
784 785 786 787 788

	# Now boot the box
	get_grub_index;
	get_version;
	install;
789 790

	start_monitor;
791
	monitor or $failed = 1;
792 793

	if ($type ne "boot") {
794
	    dodie "Failed on boot" if $failed;
795

796
	    do_run_test or $failed = 1;
797
	}
798
	end_monitor;
799 800 801 802
    }

    if ($failed) {
	$result = "bad";
803 804

	# reboot the box to a good kernel
805 806
	if ($type ne "build") {
	    doprint "Reboot and sleep $bisect_sleep_time seconds\n";
807
	    reboot;
808
	    start_monitor;
809
	    wait_for_monitor $bisect_sleep_time;
810
	    end_monitor;
811
	}
812 813 814 815
    } else {
	$result = "good";
    }

816 817 818 819 820 821 822 823 824
    # Are we looking for where it worked, not failed?
    if ($reverse_bisect) {
	if ($failed) {
	    $result = "good";
	} else {
	    $result = "bad";
	}
    }

825
    return $result;
826 827 828 829 830 831 832 833 834 835 836 837 838 839
}

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]"};
840 841
    my $start = $opt{"BISECT_START[$i]"};
    my $replay = $opt{"BISECT_REPLAY[$i]"};
842

843 844 845 846 847 848 849 850
    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;
    }

851 852
    $in_bisect = 1;

853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
    # 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
	doprint "git rev-list HEAD --max-count=1 ... ";
	my $head = `git rev-list HEAD --max-count=1`;
	my $ret = $?;

	logit $head;

	if ($ret) {
	    doprint "FAILED\n";
	    dodie "Failed to get git HEAD";
	}

	print "SUCCESS\n";

	chomp $head;

	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";
    }

906
    run_command "git bisect start" or
907
	dodie "could not start bisect";
908 909

    run_command "git bisect good $good" or
910
	dodie "could not set bisect good to $good";
911

912 913
    run_git_bisect "git bisect bad $bad" or
	dodie "could not set bisect bad to $bad";
914

915 916 917
    if (defined($replay)) {
	run_command "git bisect replay $replay" or
	    dodie "failed to run replay";
918 919
    }

920 921 922 923 924 925
    if (defined($start)) {
	run_command "git checkout $start" or
	    dodie "failed to checkout $start";
    }

    my $test;
926 927
    do {
	$result = run_bisect $type;
928 929
	$test = run_git_bisect "git bisect $result";
    } while ($test);
930 931 932 933 934 935 936 937 938 939 940 941 942 943

    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;
}

S
Steven Rostedt 已提交
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
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]"};
    }

    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/) {
979
	fail "SHA1 $start not found";
S
Steven Rostedt 已提交
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
    }

    # 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)) {
1006
	    build "useconfig:$minconfig" or return 0;
S
Steven Rostedt 已提交
1007 1008
	} else {
	    # ?? no config to use?
1009
	    build "oldconfig" or return 0;
S
Steven Rostedt 已提交
1010 1011
	}

1012
	check_buildlog $sha1 or return 0;
S
Steven Rostedt 已提交
1013 1014 1015 1016 1017 1018 1019

	next if ($type eq "build");

	get_grub_index;
	get_version;
	install;

1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
	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);

S
Steven Rostedt 已提交
1031 1032 1033
    }
    $in_patchcheck = 0;
    success $i;
1034 1035

    return 1;
S
Steven Rostedt 已提交
1036 1037
}

S
Steven Rostedt 已提交
1038 1039 1040 1041 1042 1043 1044 1045
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"}));
1046
die "TARGET_IMAGE not defined\n"	if (!defined($opt{"TARGET_IMAGE"}));
S
Steven Rostedt 已提交
1047 1048 1049 1050
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"}));

1051 1052 1053
if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) {
    unlink $opt{"LOG_FILE"};
}
S
Steven Rostedt 已提交
1054

1055 1056 1057 1058 1059
doprint "\n\nSTARTING AUTOMATED TESTS\n\n";

foreach my $option (sort keys %opt) {
    doprint "$option = $opt{$option}\n";
}
S
Steven Rostedt 已提交
1060

1061
sub set_test_option {
1062
    my ($name, $i) = @_;
S
Steven Rostedt 已提交
1063

1064
    my $option = "$name\[$i\]";
1065

1066 1067
    if (defined($opt{$option})) {
	return $opt{$option};
1068 1069
    }

1070 1071
    if (defined($opt{$name})) {
	return $opt{$name};
S
Steven Rostedt 已提交
1072 1073
    }

1074 1075 1076 1077
    return undef;
}

# First we need to do is the builds
1078 1079
for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {

1080 1081
    $iteration = $i;

1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
    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);
1099
    $post_install = set_test_option("POST_INSTALL", $i);
1100 1101 1102 1103 1104
    $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);
1105 1106
    $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
    $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
    $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";
    }
S
Steven Rostedt 已提交
1124

1125 1126 1127 1128 1129 1130 1131
    $target = "$ssh_user\@$machine";

    $buildlog = "$tmpdir/buildlog-$machine";
    $dmesg = "$tmpdir/dmesg-$machine";
    $make = "$makecmd O=$outputdir";

    if ($reboot_type eq "grub") {
1132
	dodie "GRUB_MENU not defined" if (!defined($grub_menu));
1133
    } elsif (!defined($reboot_script)) {
1134
	dodie "REBOOT_SCRIPT not defined"
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
    }

    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";
    }
1148

S
Steven Rostedt 已提交
1149
    doprint "\n\n";
1150
    doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
1151 1152 1153

    unlink $dmesg;
    unlink $buildlog;
S
Steven Rostedt 已提交
1154

1155 1156 1157 1158
    if (!defined($minconfig)) {
	$minconfig = $addconfig;

    } elsif (defined($addconfig)) {
1159
	run_command "cat $addconfig $minconfig > $tmpdir/use_config" or
1160
	    dodie "Failed to create temp config";
1161
	$minconfig = "$tmpdir/use_config";
1162 1163
    }

S
Steven Rostedt 已提交
1164 1165 1166 1167 1168 1169
    my $checkout = $opt{"CHECKOUT[$i]"};
    if (defined($checkout)) {
	run_command "git checkout $checkout" or
	    die "failed to checkout $checkout";
    }

1170
    if ($test_type eq "bisect") {
1171 1172
	bisect $i;
	next;
1173
    } elsif ($test_type eq "patchcheck") {
S
Steven Rostedt 已提交
1174 1175
	patchcheck $i;
	next;
S
Steven Rostedt 已提交
1176 1177
    }

1178 1179
    if ($build_type ne "nobuild") {
	build $build_type or next;
S
Steven Rostedt 已提交
1180 1181
    }

1182 1183 1184 1185
    if ($test_type ne "build") {
	get_grub_index;
	get_version;
	install;
1186

1187 1188 1189 1190 1191 1192 1193 1194 1195
	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);
1196 1197
    }

1198
    success $i;
S
Steven Rostedt 已提交
1199 1200
}

1201
if ($opt{"POWEROFF_ON_SUCCESS"}) {
1202
    halt;
1203
} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
1204
    reboot;
1205
}
1206

S
Steven Rostedt 已提交
1207
exit 0;