ktest: Allow a test case to undefine a default value
[deliverable/linux.git] / tools / testing / ktest / ktest.pl
CommitLineData
2545eb61 1#!/usr/bin/perl -w
d6ce2a0b
SR
2#
3# Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
4# Licensed under the terms of the GNU GPL License version 2
5#
2545eb61
SR
6
7use strict;
8use IPC::Open2;
9use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
7faafbd6
SR
10use File::Path qw(mkpath);
11use File::Copy qw(cp);
2545eb61
SR
12use FileHandle;
13
a57419b3 14$#ARGV >= 0 || die "usage: ktest.pl config-file\n";
2545eb61
SR
15
16$| = 1;
17
18my %opt;
a57419b3
SR
19my %repeat_tests;
20my %repeats;
a75fecec 21my %default;
2545eb61
SR
22
23#default opts
a57419b3 24$default{"NUM_TESTS"} = 1;
a75fecec
SR
25$default{"REBOOT_TYPE"} = "grub";
26$default{"TEST_TYPE"} = "test";
27$default{"BUILD_TYPE"} = "randconfig";
28$default{"MAKE_CMD"} = "make";
29$default{"TIMEOUT"} = 120;
a57419b3 30$default{"TMP_DIR"} = "/tmp/ktest";
a75fecec
SR
31$default{"SLEEP_TIME"} = 60; # sleep time between tests
32$default{"BUILD_NOCLEAN"} = 0;
33$default{"REBOOT_ON_ERROR"} = 0;
34$default{"POWEROFF_ON_ERROR"} = 0;
35$default{"REBOOT_ON_SUCCESS"} = 1;
36$default{"POWEROFF_ON_SUCCESS"} = 0;
37$default{"BUILD_OPTIONS"} = "";
38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects
39$default{"CLEAR_LOG"} = 0;
40$default{"SUCCESS_LINE"} = "login:";
41$default{"BOOTED_TIMEOUT"} = 1;
42$default{"DIE_ON_FAILURE"} = 1;
2545eb61
SR
43
44my $version;
a75fecec
SR
45my $machine;
46my $tmpdir;
47my $builddir;
48my $outputdir;
51ad1dd1 49my $output_config;
a75fecec 50my $test_type;
7faafbd6 51my $build_type;
a75fecec
SR
52my $build_options;
53my $reboot_type;
54my $reboot_script;
55my $power_cycle;
56my $reboot_on_error;
57my $poweroff_on_error;
58my $die_on_failure;
576f627c
SR
59my $powercycle_after_reboot;
60my $poweroff_after_halt;
a75fecec
SR
61my $power_off;
62my $grub_menu;
2545eb61
SR
63my $grub_number;
64my $target;
65my $make;
8b37ca8c 66my $post_install;
5c42fc5b 67my $noclean;
5f9b6ced 68my $minconfig;
2b7d9b21 69my $addconfig;
5f9b6ced
SR
70my $in_bisect = 0;
71my $bisect_bad = "";
d6ce2a0b 72my $reverse_bisect;
6c5ee0be 73my $in_patchcheck = 0;
5a391fbf 74my $run_test;
6c5ee0be 75my $redirect;
7faafbd6
SR
76my $buildlog;
77my $dmesg;
78my $monitor_fp;
79my $monitor_pid;
80my $monitor_cnt = 0;
a75fecec
SR
81my $sleep_time;
82my $bisect_sleep_time;
83my $store_failures;
84my $timeout;
85my $booted_timeout;
86my $console;
87my $success_line;
88my $build_target;
89my $target_image;
90my $localversion;
576f627c 91my $iteration = 0;
2545eb61 92
a57419b3
SR
93sub set_value {
94 my ($lvalue, $rvalue) = @_;
95
96 if (defined($opt{$lvalue})) {
97 die "Error: Option $lvalue defined more than once!\n";
98 }
99 $opt{$lvalue} = $rvalue;
21a9679f
SR
100 if ($rvalue =~ /^\s*$/) {
101 delete $opt{$lvalue};
102 } else {
103 $opt{$lvalue} = $rvalue;
104 }
a57419b3
SR
105}
106
2545eb61
SR
107sub read_config {
108 my ($config) = @_;
109
110 open(IN, $config) || die "can't read file $config";
111
a57419b3
SR
112 my $name = $config;
113 $name =~ s,.*/(.*),$1,;
114
115 my $test_num = 0;
116 my $default = 1;
117 my $repeat = 1;
118 my $num_tests_set = 0;
119 my $skip = 0;
120 my $rest;
121
2545eb61
SR
122 while (<IN>) {
123
124 # ignore blank lines and comments
125 next if (/^\s*$/ || /\s*\#/);
126
a57419b3
SR
127 if (/^\s*TEST_START(.*)/) {
128
129 $rest = $1;
130
131 if ($num_tests_set) {
132 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
133 }
134
135 my $old_test_num = $test_num;
136
137 $test_num += $repeat;
138 $default = 0;
139 $repeat = 1;
140
141 if ($rest =~ /\s+SKIP(.*)/) {
142 $rest = $1;
143 $skip = 1;
144 } else {
145 $skip = 0;
146 }
147
148 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
149 $repeat = $1;
150 $rest = $2;
151 $repeat_tests{"$test_num"} = $repeat;
152 }
153
154 if ($rest =~ /\s+SKIP(.*)/) {
155 $rest = $1;
156 $skip = 1;
157 }
158
159 if ($rest !~ /^\s*$/) {
160 die "$name: $.: Gargbage found after TEST_START\n$_";
161 }
162
163 if ($skip) {
164 $test_num = $old_test_num;
165 $repeat = 1;
166 }
167
168 } elsif (/^\s*DEFAULTS(.*)$/) {
169 $default = 1;
170
171 $rest = $1;
172
173 if ($rest =~ /\s+SKIP(.*)/) {
174 $rest = $1;
175 $skip = 1;
176 } else {
177 $skip = 0;
178 }
179
180 if ($rest !~ /^\s*$/) {
181 die "$name: $.: Gargbage found after DEFAULTS\n$_";
182 }
183
184 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
185
186 next if ($skip);
187
2545eb61
SR
188 my $lvalue = $1;
189 my $rvalue = $2;
190
a57419b3
SR
191 if (!$default &&
192 ($lvalue eq "NUM_TESTS" ||
193 $lvalue eq "LOG_FILE" ||
194 $lvalue eq "CLEAR_LOG")) {
195 die "$name: $.: $lvalue must be set in DEFAULTS section\n";
196 }
197
198 if ($lvalue eq "NUM_TESTS") {
199 if ($test_num) {
200 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
201 }
202 if (!$default) {
203 die "$name: $.: NUM_TESTS must be set in default section\n";
204 }
205 $num_tests_set = 1;
206 }
207
208 if ($default || $lvalue =~ /\[\d+\]$/) {
209 set_value($lvalue, $rvalue);
210 } else {
211 my $val = "$lvalue\[$test_num\]";
212 set_value($val, $rvalue);
213
214 if ($repeat > 1) {
215 $repeats{$val} = $repeat;
216 }
a75fecec 217 }
a57419b3
SR
218 } else {
219 die "$name: $.: Garbage found in config\n$_";
2545eb61
SR
220 }
221 }
222
223 close(IN);
a75fecec 224
a57419b3
SR
225 if ($test_num) {
226 $test_num += $repeat - 1;
227 $opt{"NUM_TESTS"} = $test_num;
228 }
229
a75fecec
SR
230 # set any defaults
231
232 foreach my $default (keys %default) {
233 if (!defined($opt{$default})) {
234 $opt{$default} = $default{$default};
235 }
236 }
2545eb61
SR
237}
238
d1e2f22a 239sub _logit {
2545eb61
SR
240 if (defined($opt{"LOG_FILE"})) {
241 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
242 print OUT @_;
243 close(OUT);
244 }
245}
246
d1e2f22a
SR
247sub logit {
248 if (defined($opt{"LOG_FILE"})) {
249 _logit @_;
250 } else {
251 print @_;
252 }
253}
254
5f9b6ced
SR
255sub doprint {
256 print @_;
d1e2f22a 257 _logit @_;
5f9b6ced
SR
258}
259
7faafbd6
SR
260sub run_command;
261
262sub reboot {
263 # try to reboot normally
576f627c
SR
264 if (run_command "ssh $target reboot") {
265 if (defined($powercycle_after_reboot)) {
266 sleep $powercycle_after_reboot;
267 run_command "$power_cycle";
268 }
269 } else {
7faafbd6 270 # nope? power cycle it.
a75fecec 271 run_command "$power_cycle";
7faafbd6
SR
272 }
273}
274
576f627c
SR
275sub do_not_reboot {
276 my $i = $iteration;
277
278 return $test_type eq "build" ||
279 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
280 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
281}
282
5c42fc5b 283sub dodie {
5a391fbf 284 doprint "CRITICAL FAILURE... ", @_, "\n";
5c42fc5b 285
576f627c
SR
286 my $i = $iteration;
287
288 if ($reboot_on_error && !do_not_reboot) {
289
75c3fda7 290 doprint "REBOOTING\n";
7faafbd6 291 reboot;
75c3fda7 292
a75fecec 293 } elsif ($poweroff_on_error && defined($power_off)) {
5c42fc5b 294 doprint "POWERING OFF\n";
a75fecec 295 `$power_off`;
5c42fc5b 296 }
75c3fda7 297
576f627c 298 die @_, "\n";
5c42fc5b
SR
299}
300
7faafbd6
SR
301sub open_console {
302 my ($fp) = @_;
303
304 my $flags;
305
a75fecec
SR
306 my $pid = open($fp, "$console|") or
307 dodie "Can't open console $console";
7faafbd6
SR
308
309 $flags = fcntl($fp, F_GETFL, 0) or
576f627c 310 dodie "Can't get flags for the socket: $!";
7faafbd6 311 $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
576f627c 312 dodie "Can't set flags for the socket: $!";
7faafbd6
SR
313
314 return $pid;
315}
316
317sub close_console {
318 my ($fp, $pid) = @_;
319
320 doprint "kill child process $pid\n";
321 kill 2, $pid;
322
323 print "closing!\n";
324 close($fp);
325}
326
327sub start_monitor {
328 if ($monitor_cnt++) {
329 return;
330 }
331 $monitor_fp = \*MONFD;
332 $monitor_pid = open_console $monitor_fp;
a75fecec
SR
333
334 return;
335
336 open(MONFD, "Stop perl from warning about single use of MONFD");
7faafbd6
SR
337}
338
339sub end_monitor {
340 if (--$monitor_cnt) {
341 return;
342 }
343 close_console($monitor_fp, $monitor_pid);
344}
345
346sub wait_for_monitor {
347 my ($time) = @_;
348 my $line;
349
a75fecec 350 doprint "** Wait for monitor to settle down **\n";
7faafbd6
SR
351
352 # read the monitor and wait for the system to calm down
353 do {
354 $line = wait_for_input($monitor_fp, $time);
a75fecec 355 print "$line" if (defined($line));
7faafbd6 356 } while (defined($line));
a75fecec 357 print "** Monitor flushed **\n";
7faafbd6
SR
358}
359
2b7d9b21
SR
360sub fail {
361
a75fecec 362 if ($die_on_failure) {
2b7d9b21
SR
363 dodie @_;
364 }
365
a75fecec 366 doprint "FAILED\n";
7faafbd6 367
576f627c
SR
368 my $i = $iteration;
369
a75fecec 370 # no need to reboot for just building.
576f627c 371 if (!do_not_reboot) {
a75fecec
SR
372 doprint "REBOOTING\n";
373 reboot;
374 start_monitor;
375 wait_for_monitor $sleep_time;
376 end_monitor;
377 }
7faafbd6 378
576f627c
SR
379 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
380 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
a75fecec 381 doprint "**** Failed: ", @_, " ****\n";
576f627c
SR
382 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
383 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
a75fecec
SR
384
385 return 1 if (!defined($store_failures));
7faafbd6
SR
386
387 my @t = localtime;
388 my $date = sprintf "%04d%02d%02d%02d%02d%02d",
389 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
390
a75fecec
SR
391 my $dir = "$machine-$test_type-$build_type-fail-$date";
392 my $faildir = "$store_failures/$dir";
7faafbd6
SR
393
394 if (!-d $faildir) {
395 mkpath($faildir) or
a75fecec 396 die "can't create $faildir";
7faafbd6 397 }
51ad1dd1
SR
398 if (-f "$output_config") {
399 cp "$output_config", "$faildir/config" or
7faafbd6
SR
400 die "failed to copy .config";
401 }
402 if (-f $buildlog) {
403 cp $buildlog, "$faildir/buildlog" or
404 die "failed to move $buildlog";
405 }
406 if (-f $dmesg) {
407 cp $dmesg, "$faildir/dmesg" or
408 die "failed to move $dmesg";
409 }
410
411 doprint "*** Saved info to $faildir ***\n";
412
2b7d9b21
SR
413 return 1;
414}
415
2545eb61
SR
416sub run_command {
417 my ($command) = @_;
d6ce2a0b
SR
418 my $dolog = 0;
419 my $dord = 0;
420 my $pid;
421
422 doprint("$command ... ");
423
424 $pid = open(CMD, "$command 2>&1 |") or
2b7d9b21 425 (fail "unable to exec $command" and return 0);
2545eb61
SR
426
427 if (defined($opt{"LOG_FILE"})) {
d6ce2a0b
SR
428 open(LOG, ">>$opt{LOG_FILE}") or
429 dodie "failed to write to log";
430 $dolog = 1;
6c5ee0be
SR
431 }
432
433 if (defined($redirect)) {
d6ce2a0b
SR
434 open (RD, ">$redirect") or
435 dodie "failed to write to redirect $redirect";
436 $dord = 1;
2545eb61
SR
437 }
438
d6ce2a0b
SR
439 while (<CMD>) {
440 print LOG if ($dolog);
441 print RD if ($dord);
442 }
2545eb61 443
d6ce2a0b 444 waitpid($pid, 0);
2545eb61
SR
445 my $failed = $?;
446
d6ce2a0b
SR
447 close(CMD);
448 close(LOG) if ($dolog);
449 close(RD) if ($dord);
450
2545eb61
SR
451 if ($failed) {
452 doprint "FAILED!\n";
453 } else {
454 doprint "SUCCESS\n";
455 }
456
5f9b6ced
SR
457 return !$failed;
458}
459
460sub get_grub_index {
461
a75fecec
SR
462 if ($reboot_type ne "grub") {
463 return;
464 }
5a391fbf 465 return if (defined($grub_number));
5f9b6ced
SR
466
467 doprint "Find grub menu ... ";
468 $grub_number = -1;
469 open(IN, "ssh $target cat /boot/grub/menu.lst |")
470 or die "unable to get menu.lst";
471 while (<IN>) {
a75fecec 472 if (/^\s*title\s+$grub_menu\s*$/) {
5f9b6ced
SR
473 $grub_number++;
474 last;
475 } elsif (/^\s*title\s/) {
476 $grub_number++;
477 }
478 }
479 close(IN);
480
a75fecec 481 die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
5f9b6ced
SR
482 if ($grub_number < 0);
483 doprint "$grub_number\n";
2545eb61
SR
484}
485
2545eb61
SR
486sub wait_for_input
487{
488 my ($fp, $time) = @_;
489 my $rin;
490 my $ready;
491 my $line;
492 my $ch;
493
494 if (!defined($time)) {
495 $time = $timeout;
496 }
497
498 $rin = '';
499 vec($rin, fileno($fp), 1) = 1;
500 $ready = select($rin, undef, undef, $time);
501
502 $line = "";
503
504 # try to read one char at a time
505 while (sysread $fp, $ch, 1) {
506 $line .= $ch;
507 last if ($ch eq "\n");
508 }
509
510 if (!length($line)) {
511 return undef;
512 }
513
514 return $line;
515}
516
75c3fda7 517sub reboot_to {
a75fecec
SR
518 if ($reboot_type eq "grub") {
519 run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
520 return;
521 }
522
523 run_command "$reboot_script";
2545eb61
SR
524}
525
a57419b3
SR
526sub get_sha1 {
527 my ($commit) = @_;
528
529 doprint "git rev-list --max-count=1 $commit ... ";
530 my $sha1 = `git rev-list --max-count=1 $commit`;
531 my $ret = $?;
532
533 logit $sha1;
534
535 if ($ret) {
536 doprint "FAILED\n";
537 dodie "Failed to get git $commit";
538 }
539
540 print "SUCCESS\n";
541
542 chomp $sha1;
543
544 return $sha1;
545}
546
5a391fbf 547sub monitor {
2545eb61
SR
548 my $booted = 0;
549 my $bug = 0;
5c42fc5b 550 my $skip_call_trace = 0;
2b7d9b21 551 my $loops;
2545eb61 552
7faafbd6 553 wait_for_monitor 5;
2545eb61
SR
554
555 my $line;
556 my $full_line = "";
557
7faafbd6
SR
558 open(DMESG, "> $dmesg") or
559 die "unable to write to $dmesg";
2545eb61 560
75c3fda7 561 reboot_to;
2545eb61
SR
562
563 for (;;) {
564
2b7d9b21 565 if ($booted) {
a75fecec 566 $line = wait_for_input($monitor_fp, $booted_timeout);
2b7d9b21 567 } else {
7faafbd6 568 $line = wait_for_input($monitor_fp);
2b7d9b21 569 }
2545eb61
SR
570
571 last if (!defined($line));
572
573 doprint $line;
7faafbd6 574 print DMESG $line;
2545eb61
SR
575
576 # we are not guaranteed to get a full line
577 $full_line .= $line;
578
a75fecec 579 if ($full_line =~ /$success_line/) {
2545eb61
SR
580 $booted = 1;
581 }
582
5c42fc5b
SR
583 if ($full_line =~ /\[ backtrace testing \]/) {
584 $skip_call_trace = 1;
585 }
586
2545eb61 587 if ($full_line =~ /call trace:/i) {
5c42fc5b
SR
588 $bug = 1 if (!$skip_call_trace);
589 }
590
591 if ($full_line =~ /\[ end of backtrace testing \]/) {
592 $skip_call_trace = 0;
593 }
594
595 if ($full_line =~ /Kernel panic -/) {
2545eb61
SR
596 $bug = 1;
597 }
598
599 if ($line =~ /\n/) {
600 $full_line = "";
601 }
602 }
603
7faafbd6 604 close(DMESG);
2545eb61 605
a75fecec 606 if ($bug) {
2b7d9b21 607 return 0 if ($in_bisect);
576f627c 608 fail "failed - got a bug report" and return 0;
2545eb61
SR
609 }
610
a75fecec 611 if (!$booted) {
2b7d9b21 612 return 0 if ($in_bisect);
576f627c 613 fail "failed - never got a boot prompt." and return 0;
2545eb61 614 }
5f9b6ced 615
2b7d9b21 616 return 1;
2545eb61
SR
617}
618
619sub install {
620
a75fecec 621 run_command "scp $outputdir/$build_target $target:$target_image" or
5c42fc5b 622 dodie "failed to copy image";
2545eb61 623
5f9b6ced 624 my $install_mods = 0;
2545eb61 625
5f9b6ced
SR
626 # should we process modules?
627 $install_mods = 0;
51ad1dd1 628 open(IN, "$output_config") or dodie("Can't read config file");
5f9b6ced
SR
629 while (<IN>) {
630 if (/CONFIG_MODULES(=y)?/) {
631 $install_mods = 1 if (defined($1));
632 last;
5c42fc5b 633 }
5f9b6ced
SR
634 }
635 close(IN);
5c42fc5b 636
5f9b6ced
SR
637 if (!$install_mods) {
638 doprint "No modules needed\n";
639 return;
640 }
2545eb61 641
a75fecec 642 run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
5f9b6ced 643 dodie "Failed to install modules";
5c42fc5b 644
5f9b6ced 645 my $modlib = "/lib/modules/$version";
a57419b3 646 my $modtar = "ktest-mods.tar.bz2";
5c42fc5b 647
5f9b6ced
SR
648 run_command "ssh $target rm -rf $modlib" or
649 dodie "failed to remove old mods: $modlib";
5c42fc5b 650
5f9b6ced 651 # would be nice if scp -r did not follow symbolic links
a75fecec 652 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
5f9b6ced
SR
653 dodie "making tarball";
654
a75fecec 655 run_command "scp $tmpdir/$modtar $target:/tmp" or
5f9b6ced
SR
656 dodie "failed to copy modules";
657
a75fecec 658 unlink "$tmpdir/$modtar";
5f9b6ced
SR
659
660 run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or
661 dodie "failed to tar modules";
2545eb61 662
5f9b6ced 663 run_command "ssh $target rm -f /tmp/$modtar";
8b37ca8c
SR
664
665 return if (!defined($post_install));
666
667 my $save_env = $ENV{KERNEL_VERSION};
668
669 $ENV{KERNEL_VERSION} = $version;
576f627c
SR
670 run_command "$post_install" or
671 dodie "Failed to run post install";
8b37ca8c
SR
672
673 $ENV{KERNEL_VERSION} = $save_env;
2545eb61
SR
674}
675
6c5ee0be
SR
676sub check_buildlog {
677 my ($patch) = @_;
678
6c5ee0be
SR
679 my @files = `git show $patch | diffstat -l`;
680
681 open(IN, "git show $patch |") or
682 dodie "failed to show $patch";
683 while (<IN>) {
684 if (m,^--- a/(.*),) {
685 chomp $1;
686 $files[$#files] = $1;
687 }
688 }
689 close(IN);
690
691 open(IN, $buildlog) or dodie "Can't open $buildlog";
692 while (<IN>) {
693 if (/^\s*(.*?):.*(warning|error)/) {
694 my $err = $1;
695 foreach my $file (@files) {
a75fecec 696 my $fullpath = "$builddir/$file";
6c5ee0be 697 if ($file eq $err || $fullpath eq $err) {
2b7d9b21 698 fail "$file built with warnings" and return 0;
6c5ee0be
SR
699 }
700 }
701 }
702 }
703 close(IN);
2b7d9b21
SR
704
705 return 1;
6c5ee0be
SR
706}
707
2545eb61
SR
708sub build {
709 my ($type) = @_;
5c42fc5b 710 my $defconfig = "";
5c42fc5b 711
7faafbd6
SR
712 unlink $buildlog;
713
75c3fda7 714 if ($type =~ /^useconfig:(.*)/) {
51ad1dd1 715 run_command "cp $1 $output_config" or
75c3fda7 716 dodie "could not copy $1 to .config";
5f9b6ced 717
75c3fda7
SR
718 $type = "oldconfig";
719 }
720
5c42fc5b
SR
721 # old config can ask questions
722 if ($type eq "oldconfig") {
9386c6ab 723 $type = "oldnoconfig";
75c3fda7
SR
724
725 # allow for empty configs
51ad1dd1 726 run_command "touch $output_config";
75c3fda7 727
51ad1dd1 728 run_command "mv $output_config $outputdir/config_temp" or
5c42fc5b 729 dodie "moving .config";
2545eb61 730
5f9b6ced 731 if (!$noclean && !run_command "$make mrproper") {
5c42fc5b
SR
732 dodie "make mrproper";
733 }
2545eb61 734
51ad1dd1 735 run_command "mv $outputdir/config_temp $output_config" or
5c42fc5b 736 dodie "moving config_temp";
5c42fc5b
SR
737
738 } elsif (!$noclean) {
51ad1dd1 739 unlink "$output_config";
5f9b6ced 740 run_command "$make mrproper" or
5c42fc5b 741 dodie "make mrproper";
5c42fc5b 742 }
2545eb61
SR
743
744 # add something to distinguish this build
a75fecec
SR
745 open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file");
746 print OUT "$localversion\n";
2545eb61
SR
747 close(OUT);
748
5f9b6ced
SR
749 if (defined($minconfig)) {
750 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
2545eb61
SR
751 }
752
9386c6ab 753 run_command "$defconfig $make $type" or
5c42fc5b 754 dodie "failed make config";
2545eb61 755
a75fecec
SR
756 $redirect = "$buildlog";
757 if (!run_command "$make $build_options") {
6c5ee0be 758 undef $redirect;
5f9b6ced 759 # bisect may need this to pass
2b7d9b21
SR
760 return 0 if ($in_bisect);
761 fail "failed build" and return 0;
2545eb61 762 }
6c5ee0be 763 undef $redirect;
5f9b6ced 764
2b7d9b21 765 return 1;
2545eb61
SR
766}
767
75c3fda7 768sub halt {
a75fecec 769 if (!run_command "ssh $target halt" or defined($power_off)) {
576f627c
SR
770 if (defined($poweroff_after_halt)) {
771 sleep $poweroff_after_halt;
772 run_command "$power_off";
773 }
774 } else {
75c3fda7 775 # nope? the zap it!
a75fecec 776 run_command "$power_off";
75c3fda7
SR
777 }
778}
779
5f9b6ced
SR
780sub success {
781 my ($i) = @_;
782
783 doprint "\n\n*******************************************\n";
784 doprint "*******************************************\n";
a75fecec 785 doprint "** TEST $i SUCCESS!!!! **\n";
5f9b6ced
SR
786 doprint "*******************************************\n";
787 doprint "*******************************************\n";
788
576f627c 789 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
a75fecec 790 doprint "Reboot and wait $sleep_time seconds\n";
5f9b6ced 791 reboot;
7faafbd6 792 start_monitor;
a75fecec 793 wait_for_monitor $sleep_time;
7faafbd6 794 end_monitor;
5f9b6ced
SR
795 }
796}
797
798sub get_version {
799 # get the release name
800 doprint "$make kernelrelease ... ";
801 $version = `$make kernelrelease | tail -1`;
802 chomp($version);
803 doprint "$version\n";
804}
805
5a391fbf 806sub child_run_test {
7faafbd6 807 my $failed = 0;
5a391fbf 808
7faafbd6 809 # child should have no power
a75fecec
SR
810 $reboot_on_error = 0;
811 $poweroff_on_error = 0;
812 $die_on_failure = 1;
7faafbd6
SR
813
814 run_command $run_test or $failed = 1;
5a391fbf
SR
815 exit $failed;
816}
817
818my $child_done;
819
820sub child_finished {
821 $child_done = 1;
822}
823
824sub do_run_test {
825 my $child_pid;
826 my $child_exit;
5a391fbf
SR
827 my $line;
828 my $full_line;
829 my $bug = 0;
5a391fbf 830
7faafbd6 831 wait_for_monitor 1;
5a391fbf 832
7faafbd6 833 doprint "run test $run_test\n";
5a391fbf
SR
834
835 $child_done = 0;
836
837 $SIG{CHLD} = qw(child_finished);
838
839 $child_pid = fork;
840
841 child_run_test if (!$child_pid);
842
843 $full_line = "";
844
845 do {
7faafbd6 846 $line = wait_for_input($monitor_fp, 1);
5a391fbf
SR
847 if (defined($line)) {
848
849 # we are not guaranteed to get a full line
850 $full_line .= $line;
851
852 if ($full_line =~ /call trace:/i) {
853 $bug = 1;
854 }
855
856 if ($full_line =~ /Kernel panic -/) {
857 $bug = 1;
858 }
859
860 if ($line =~ /\n/) {
861 $full_line = "";
862 }
863 }
864 } while (!$child_done && !$bug);
865
866 if ($bug) {
867 doprint "Detected kernel crash!\n";
868 # kill the child with extreme prejudice
869 kill 9, $child_pid;
870 }
871
872 waitpid $child_pid, 0;
873 $child_exit = $?;
874
5a391fbf 875 if ($bug || $child_exit) {
2b7d9b21
SR
876 return 0 if $in_bisect;
877 fail "test failed" and return 0;
5a391fbf 878 }
2b7d9b21 879 return 1;
5a391fbf
SR
880}
881
a75fecec
SR
882sub run_git_bisect {
883 my ($command) = @_;
884
885 doprint "$command ... ";
886
887 my $output = `$command 2>&1`;
888 my $ret = $?;
889
890 logit $output;
891
892 if ($ret) {
893 doprint "FAILED\n";
894 dodie "Failed to git bisect";
895 }
896
897 doprint "SUCCESS\n";
898 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
899 doprint "$1 [$2]\n";
900 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
901 $bisect_bad = $1;
902 doprint "Found bad commit... $1\n";
903 return 0;
904 } else {
905 # we already logged it, just print it now.
906 print $output;
907 }
908
909 return 1;
910}
911
5f9b6ced
SR
912sub run_bisect {
913 my ($type) = @_;
914
2b7d9b21 915 my $failed = 0;
5f9b6ced
SR
916 my $result;
917 my $output;
918 my $ret;
919
5f9b6ced 920 if (defined($minconfig)) {
2b7d9b21 921 build "useconfig:$minconfig" or $failed = 1;
5f9b6ced
SR
922 } else {
923 # ?? no config to use?
2b7d9b21 924 build "oldconfig" or $failed = 1;
5f9b6ced
SR
925 }
926
927 if ($type ne "build") {
7faafbd6 928 dodie "Failed on build" if $failed;
5f9b6ced
SR
929
930 # Now boot the box
931 get_grub_index;
932 get_version;
933 install;
7faafbd6
SR
934
935 start_monitor;
2b7d9b21 936 monitor or $failed = 1;
5f9b6ced
SR
937
938 if ($type ne "boot") {
7faafbd6 939 dodie "Failed on boot" if $failed;
5a391fbf 940
2b7d9b21 941 do_run_test or $failed = 1;
5f9b6ced 942 }
7faafbd6 943 end_monitor;
5f9b6ced
SR
944 }
945
946 if ($failed) {
947 $result = "bad";
5a391fbf
SR
948
949 # reboot the box to a good kernel
a75fecec
SR
950 if ($type ne "build") {
951 doprint "Reboot and sleep $bisect_sleep_time seconds\n";
5a391fbf 952 reboot;
7faafbd6 953 start_monitor;
a75fecec 954 wait_for_monitor $bisect_sleep_time;
7faafbd6 955 end_monitor;
5a391fbf 956 }
5f9b6ced
SR
957 } else {
958 $result = "good";
959 }
960
d6ce2a0b
SR
961 # Are we looking for where it worked, not failed?
962 if ($reverse_bisect) {
963 if ($failed) {
964 $result = "good";
965 } else {
966 $result = "bad";
967 }
968 }
969
a75fecec 970 return $result;
5f9b6ced
SR
971}
972
973sub bisect {
974 my ($i) = @_;
975
976 my $result;
977
978 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
979 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
980 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
981
982 my $good = $opt{"BISECT_GOOD[$i]"};
983 my $bad = $opt{"BISECT_BAD[$i]"};
984 my $type = $opt{"BISECT_TYPE[$i]"};
a75fecec
SR
985 my $start = $opt{"BISECT_START[$i]"};
986 my $replay = $opt{"BISECT_REPLAY[$i]"};
5f9b6ced 987
a57419b3
SR
988 # convert to true sha1's
989 $good = get_sha1($good);
990 $bad = get_sha1($bad);
991
d6ce2a0b
SR
992 if (defined($opt{"BISECT_REVERSE[$i]"}) &&
993 $opt{"BISECT_REVERSE[$i]"} == 1) {
994 doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
995 $reverse_bisect = 1;
996 } else {
997 $reverse_bisect = 0;
998 }
999
5f9b6ced
SR
1000 $in_bisect = 1;
1001
a75fecec
SR
1002 # Can't have a test without having a test to run
1003 if ($type eq "test" && !defined($run_test)) {
1004 $type = "boot";
1005 }
1006
1007 my $check = $opt{"BISECT_CHECK[$i]"};
1008 if (defined($check) && $check ne "0") {
1009
1010 # get current HEAD
a57419b3 1011 my $head = get_sha1("HEAD");
a75fecec
SR
1012
1013 if ($check ne "good") {
1014 doprint "TESTING BISECT BAD [$bad]\n";
1015 run_command "git checkout $bad" or
1016 die "Failed to checkout $bad";
1017
1018 $result = run_bisect $type;
1019
1020 if ($result ne "bad") {
1021 fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0;
1022 }
1023 }
1024
1025 if ($check ne "bad") {
1026 doprint "TESTING BISECT GOOD [$good]\n";
1027 run_command "git checkout $good" or
1028 die "Failed to checkout $good";
1029
1030 $result = run_bisect $type;
1031
1032 if ($result ne "good") {
1033 fail "Tested BISECT_GOOD [$good] and it failed" and return 0;
1034 }
1035 }
1036
1037 # checkout where we started
1038 run_command "git checkout $head" or
1039 die "Failed to checkout $head";
1040 }
1041
5f9b6ced 1042 run_command "git bisect start" or
a75fecec 1043 dodie "could not start bisect";
5f9b6ced
SR
1044
1045 run_command "git bisect good $good" or
a75fecec 1046 dodie "could not set bisect good to $good";
5f9b6ced 1047
a75fecec
SR
1048 run_git_bisect "git bisect bad $bad" or
1049 dodie "could not set bisect bad to $bad";
5f9b6ced 1050
a75fecec
SR
1051 if (defined($replay)) {
1052 run_command "git bisect replay $replay" or
1053 dodie "failed to run replay";
5a391fbf
SR
1054 }
1055
a75fecec
SR
1056 if (defined($start)) {
1057 run_command "git checkout $start" or
1058 dodie "failed to checkout $start";
1059 }
1060
1061 my $test;
5f9b6ced
SR
1062 do {
1063 $result = run_bisect $type;
a75fecec
SR
1064 $test = run_git_bisect "git bisect $result";
1065 } while ($test);
5f9b6ced
SR
1066
1067 run_command "git bisect log" or
1068 dodie "could not capture git bisect log";
1069
1070 run_command "git bisect reset" or
1071 dodie "could not reset git bisect";
1072
1073 doprint "Bad commit was [$bisect_bad]\n";
1074
1075 $in_bisect = 0;
1076
1077 success $i;
1078}
1079
6c5ee0be
SR
1080sub patchcheck {
1081 my ($i) = @_;
1082
1083 die "PATCHCHECK_START[$i] not defined\n"
1084 if (!defined($opt{"PATCHCHECK_START[$i]"}));
1085 die "PATCHCHECK_TYPE[$i] not defined\n"
1086 if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
1087
1088 my $start = $opt{"PATCHCHECK_START[$i]"};
1089
1090 my $end = "HEAD";
1091 if (defined($opt{"PATCHCHECK_END[$i]"})) {
1092 $end = $opt{"PATCHCHECK_END[$i]"};
1093 }
1094
a57419b3
SR
1095 # Get the true sha1's since we can use things like HEAD~3
1096 $start = get_sha1($start);
1097 $end = get_sha1($end);
1098
6c5ee0be
SR
1099 my $type = $opt{"PATCHCHECK_TYPE[$i]"};
1100
1101 # Can't have a test without having a test to run
1102 if ($type eq "test" && !defined($run_test)) {
1103 $type = "boot";
1104 }
1105
1106 open (IN, "git log --pretty=oneline $end|") or
1107 dodie "could not get git list";
1108
1109 my @list;
1110
1111 while (<IN>) {
1112 chomp;
1113 $list[$#list+1] = $_;
1114 last if (/^$start/);
1115 }
1116 close(IN);
1117
1118 if ($list[$#list] !~ /^$start/) {
2b7d9b21 1119 fail "SHA1 $start not found";
6c5ee0be
SR
1120 }
1121
1122 # go backwards in the list
1123 @list = reverse @list;
1124
1125 my $save_clean = $noclean;
1126
1127 $in_patchcheck = 1;
1128 foreach my $item (@list) {
1129 my $sha1 = $item;
1130 $sha1 =~ s/^([[:xdigit:]]+).*/$1/;
1131
1132 doprint "\nProcessing commit $item\n\n";
1133
1134 run_command "git checkout $sha1" or
1135 die "Failed to checkout $sha1";
1136
1137 # only clean on the first and last patch
1138 if ($item eq $list[0] ||
1139 $item eq $list[$#list]) {
1140 $noclean = $save_clean;
1141 } else {
1142 $noclean = 1;
1143 }
1144
1145 if (defined($minconfig)) {
2b7d9b21 1146 build "useconfig:$minconfig" or return 0;
6c5ee0be
SR
1147 } else {
1148 # ?? no config to use?
2b7d9b21 1149 build "oldconfig" or return 0;
6c5ee0be
SR
1150 }
1151
2b7d9b21 1152 check_buildlog $sha1 or return 0;
6c5ee0be
SR
1153
1154 next if ($type eq "build");
1155
1156 get_grub_index;
1157 get_version;
1158 install;
6c5ee0be 1159
7faafbd6
SR
1160 my $failed = 0;
1161
1162 start_monitor;
1163 monitor or $failed = 1;
1164
1165 if (!$failed && $type ne "boot"){
1166 do_run_test or $failed = 1;
1167 }
1168 end_monitor;
1169 return 0 if ($failed);
1170
6c5ee0be
SR
1171 }
1172 $in_patchcheck = 0;
1173 success $i;
2b7d9b21
SR
1174
1175 return 1;
6c5ee0be
SR
1176}
1177
2545eb61
SR
1178read_config $ARGV[0];
1179
1180# mandatory configs
1181die "MACHINE not defined\n" if (!defined($opt{"MACHINE"}));
1182die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"}));
1183die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"}));
1184die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"}));
1185die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"}));
75c3fda7 1186die "TARGET_IMAGE not defined\n" if (!defined($opt{"TARGET_IMAGE"}));
2545eb61
SR
1187die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"}));
1188die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"}));
1189die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"}));
2545eb61 1190
2b7d9b21
SR
1191if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) {
1192 unlink $opt{"LOG_FILE"};
1193}
2545eb61 1194
2b7d9b21
SR
1195doprint "\n\nSTARTING AUTOMATED TESTS\n\n";
1196
a57419b3
SR
1197for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) {
1198
1199 if (!$i) {
1200 doprint "DEFAULT OPTIONS:\n";
1201 } else {
1202 doprint "\nTEST $i OPTIONS";
1203 if (defined($repeat_tests{$i})) {
1204 $repeat = $repeat_tests{$i};
1205 doprint " ITERATE $repeat";
1206 }
1207 doprint "\n";
1208 }
1209
1210 foreach my $option (sort keys %opt) {
1211
1212 if ($option =~ /\[(\d+)\]$/) {
1213 next if ($i != $1);
1214 } else {
1215 next if ($i);
1216 }
1217
1218 doprint "$option = $opt{$option}\n";
1219 }
2b7d9b21 1220}
2545eb61 1221
a75fecec 1222sub set_test_option {
5a391fbf 1223 my ($name, $i) = @_;
2545eb61 1224
5a391fbf 1225 my $option = "$name\[$i\]";
5c42fc5b 1226
5a391fbf
SR
1227 if (defined($opt{$option})) {
1228 return $opt{$option};
5f9b6ced
SR
1229 }
1230
a57419b3
SR
1231 foreach my $test (keys %repeat_tests) {
1232 if ($i >= $test &&
1233 $i < $test + $repeat_tests{$test}) {
1234 $option = "$name\[$test\]";
1235 if (defined($opt{$option})) {
1236 return $opt{$option};
1237 }
1238 }
1239 }
1240
5a391fbf
SR
1241 if (defined($opt{$name})) {
1242 return $opt{$name};
2545eb61
SR
1243 }
1244
5a391fbf
SR
1245 return undef;
1246}
1247
1248# First we need to do is the builds
a75fecec
SR
1249for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
1250
576f627c
SR
1251 $iteration = $i;
1252
a75fecec
SR
1253 my $ssh_user = set_test_option("SSH_USER", $i);
1254 my $makecmd = set_test_option("MAKE_CMD", $i);
1255
1256 $machine = set_test_option("MACHINE", $i);
1257 $tmpdir = set_test_option("TMP_DIR", $i);
1258 $outputdir = set_test_option("OUTPUT_DIR", $i);
1259 $builddir = set_test_option("BUILD_DIR", $i);
1260 $test_type = set_test_option("TEST_TYPE", $i);
1261 $build_type = set_test_option("BUILD_TYPE", $i);
1262 $build_options = set_test_option("BUILD_OPTIONS", $i);
1263 $power_cycle = set_test_option("POWER_CYCLE", $i);
1264 $noclean = set_test_option("BUILD_NOCLEAN", $i);
1265 $minconfig = set_test_option("MIN_CONFIG", $i);
1266 $run_test = set_test_option("TEST", $i);
1267 $addconfig = set_test_option("ADD_CONFIG", $i);
1268 $reboot_type = set_test_option("REBOOT_TYPE", $i);
1269 $grub_menu = set_test_option("GRUB_MENU", $i);
8b37ca8c 1270 $post_install = set_test_option("POST_INSTALL", $i);
a75fecec
SR
1271 $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
1272 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
1273 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
1274 $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
1275 $power_off = set_test_option("POWER_OFF", $i);
576f627c
SR
1276 $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
1277 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
a75fecec
SR
1278 $sleep_time = set_test_option("SLEEP_TIME", $i);
1279 $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
1280 $store_failures = set_test_option("STORE_FAILURES", $i);
1281 $timeout = set_test_option("TIMEOUT", $i);
1282 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
1283 $console = set_test_option("CONSOLE", $i);
1284 $success_line = set_test_option("SUCCESS_LINE", $i);
1285 $build_target = set_test_option("BUILD_TARGET", $i);
1286 $target_image = set_test_option("TARGET_IMAGE", $i);
1287 $localversion = set_test_option("LOCALVERSION", $i);
1288
1289 chdir $builddir || die "can't change directory to $builddir";
1290
1291 if (!-d $tmpdir) {
1292 mkpath($tmpdir) or
1293 die "can't create $tmpdir";
1294 }
1a5cfce3 1295
a75fecec
SR
1296 $target = "$ssh_user\@$machine";
1297
1298 $buildlog = "$tmpdir/buildlog-$machine";
1299 $dmesg = "$tmpdir/dmesg-$machine";
1300 $make = "$makecmd O=$outputdir";
51ad1dd1 1301 $output_config = "$outputdir/.config";
a75fecec
SR
1302
1303 if ($reboot_type eq "grub") {
576f627c 1304 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
a75fecec 1305 } elsif (!defined($reboot_script)) {
576f627c 1306 dodie "REBOOT_SCRIPT not defined"
a75fecec
SR
1307 }
1308
1309 my $run_type = $build_type;
1310 if ($test_type eq "patchcheck") {
1311 $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
1312 } elsif ($test_type eq "bisect") {
1313 $run_type = $opt{"BISECT_TYPE[$i]"};
1314 }
1315
1316 # mistake in config file?
1317 if (!defined($run_type)) {
1318 $run_type = "ERROR";
1319 }
5a391fbf 1320
2545eb61 1321 doprint "\n\n";
a75fecec 1322 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
7faafbd6
SR
1323
1324 unlink $dmesg;
1325 unlink $buildlog;
2545eb61 1326
2b7d9b21
SR
1327 if (!defined($minconfig)) {
1328 $minconfig = $addconfig;
1329
1330 } elsif (defined($addconfig)) {
a75fecec 1331 run_command "cat $addconfig $minconfig > $tmpdir/use_config" or
2b7d9b21 1332 dodie "Failed to create temp config";
a75fecec 1333 $minconfig = "$tmpdir/use_config";
2b7d9b21
SR
1334 }
1335
6c5ee0be
SR
1336 my $checkout = $opt{"CHECKOUT[$i]"};
1337 if (defined($checkout)) {
1338 run_command "git checkout $checkout" or
1339 die "failed to checkout $checkout";
1340 }
1341
a75fecec 1342 if ($test_type eq "bisect") {
5f9b6ced
SR
1343 bisect $i;
1344 next;
a75fecec 1345 } elsif ($test_type eq "patchcheck") {
6c5ee0be
SR
1346 patchcheck $i;
1347 next;
2545eb61 1348 }
2545eb61 1349
7faafbd6
SR
1350 if ($build_type ne "nobuild") {
1351 build $build_type or next;
2545eb61
SR
1352 }
1353
a75fecec
SR
1354 if ($test_type ne "build") {
1355 get_grub_index;
1356 get_version;
1357 install;
5a391fbf 1358
a75fecec
SR
1359 my $failed = 0;
1360 start_monitor;
1361 monitor or $failed = 1;;
1362
1363 if (!$failed && $test_type ne "boot" && defined($run_test)) {
1364 do_run_test or $failed = 1;
1365 }
1366 end_monitor;
1367 next if ($failed);
5a391fbf
SR
1368 }
1369
5f9b6ced 1370 success $i;
2545eb61
SR
1371}
1372
5c42fc5b 1373if ($opt{"POWEROFF_ON_SUCCESS"}) {
75c3fda7 1374 halt;
576f627c 1375} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
75c3fda7 1376 reboot;
5c42fc5b 1377}
75c3fda7 1378
2545eb61 1379exit 0;
This page took 0.089047 seconds and 5 git commands to generate.