Commit | Line | Data |
---|---|---|
2545eb61 SR |
1 | #!/usr/bin/perl -w |
2 | ||
3 | use strict; | |
4 | use IPC::Open2; | |
5 | use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); | |
6 | use FileHandle; | |
7 | ||
8 | $#ARGV >= 0 || die "usage: autotest.pl config-file\n"; | |
9 | ||
10 | $| = 1; | |
11 | ||
12 | my %opt; | |
13 | ||
14 | #default opts | |
15 | $opt{"NUM_BUILDS"} = 5; | |
16 | $opt{"DEFAULT_BUILD_TYPE"} = "randconfig"; | |
17 | $opt{"MAKE_CMD"} = "make"; | |
18 | $opt{"TIMEOUT"} = 50; | |
19 | $opt{"TMP_DIR"} = "/tmp/autotest"; | |
20 | $opt{"SLEEP_TIME"} = 60; # sleep time between tests | |
5c42fc5b | 21 | $opt{"BUILD_NOCLEAN"} = 0; |
75c3fda7 | 22 | $opt{"REBOOT_ON_ERROR"} = 0; |
5c42fc5b | 23 | $opt{"POWEROFF_ON_ERROR"} = 0; |
1a5cfce3 | 24 | $opt{"REBOOT_ON_SUCCESS"} = 1; |
5c42fc5b | 25 | $opt{"POWEROFF_ON_SUCCESS"} = 0; |
75c3fda7 | 26 | $opt{"BUILD_OPTIONS"} = ""; |
5a391fbf | 27 | $opt{"BISECT_SLEEP_TIME"} = 10; # sleep time between bisects |
2545eb61 SR |
28 | |
29 | my $version; | |
2545eb61 SR |
30 | my $grub_number; |
31 | my $target; | |
32 | my $make; | |
5c42fc5b | 33 | my $noclean; |
5f9b6ced SR |
34 | my $minconfig; |
35 | my $in_bisect = 0; | |
36 | my $bisect_bad = ""; | |
6c5ee0be | 37 | my $in_patchcheck = 0; |
5a391fbf | 38 | my $run_test; |
6c5ee0be | 39 | my $redirect; |
2545eb61 SR |
40 | |
41 | sub read_config { | |
42 | my ($config) = @_; | |
43 | ||
44 | open(IN, $config) || die "can't read file $config"; | |
45 | ||
46 | while (<IN>) { | |
47 | ||
48 | # ignore blank lines and comments | |
49 | next if (/^\s*$/ || /\s*\#/); | |
50 | ||
51 | if (/^\s*(\S+)\s*=\s*(.*?)\s*$/) { | |
52 | my $lvalue = $1; | |
53 | my $rvalue = $2; | |
54 | ||
55 | $opt{$lvalue} = $rvalue; | |
56 | } | |
57 | } | |
58 | ||
59 | close(IN); | |
60 | } | |
61 | ||
5f9b6ced | 62 | sub logit { |
2545eb61 SR |
63 | if (defined($opt{"LOG_FILE"})) { |
64 | open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; | |
65 | print OUT @_; | |
66 | close(OUT); | |
67 | } | |
68 | } | |
69 | ||
5f9b6ced SR |
70 | sub doprint { |
71 | print @_; | |
72 | logit @_; | |
73 | } | |
74 | ||
5c42fc5b | 75 | sub dodie { |
5a391fbf | 76 | doprint "CRITICAL FAILURE... ", @_, "\n"; |
5c42fc5b | 77 | |
75c3fda7 SR |
78 | if ($opt{"REBOOT_ON_ERROR"}) { |
79 | doprint "REBOOTING\n"; | |
80 | `$opt{"POWER_CYCLE"}`; | |
81 | ||
82 | } elsif ($opt{"POWEROFF_ON_ERROR"} && defined($opt{"POWER_OFF"})) { | |
5c42fc5b SR |
83 | doprint "POWERING OFF\n"; |
84 | `$opt{"POWER_OFF"}`; | |
85 | } | |
75c3fda7 | 86 | |
5c42fc5b SR |
87 | die @_; |
88 | } | |
89 | ||
2545eb61 SR |
90 | sub run_command { |
91 | my ($command) = @_; | |
5a391fbf | 92 | my $redirect_log = ""; |
6c5ee0be | 93 | my $redirect_tee = ""; |
2545eb61 SR |
94 | |
95 | if (defined($opt{"LOG_FILE"})) { | |
6c5ee0be SR |
96 | $redirect_log = "| tee -a $opt{LOG_FILE}"; |
97 | } | |
98 | ||
99 | if (defined($redirect)) { | |
100 | $redirect_tee = "| tee $redirect" | |
2545eb61 SR |
101 | } |
102 | ||
103 | doprint "$command ... "; | |
6c5ee0be | 104 | `$command 2>&1 $redirect_tee $redirect_log > /dev/null`; |
2545eb61 SR |
105 | |
106 | my $failed = $?; | |
107 | ||
108 | if ($failed) { | |
109 | doprint "FAILED!\n"; | |
110 | } else { | |
111 | doprint "SUCCESS\n"; | |
112 | } | |
113 | ||
5f9b6ced SR |
114 | return !$failed; |
115 | } | |
116 | ||
117 | sub get_grub_index { | |
118 | ||
5a391fbf | 119 | return if (defined($grub_number)); |
5f9b6ced SR |
120 | |
121 | doprint "Find grub menu ... "; | |
122 | $grub_number = -1; | |
123 | open(IN, "ssh $target cat /boot/grub/menu.lst |") | |
124 | or die "unable to get menu.lst"; | |
125 | while (<IN>) { | |
126 | if (/^\s*title\s+$opt{GRUB_MENU}\s*$/) { | |
127 | $grub_number++; | |
128 | last; | |
129 | } elsif (/^\s*title\s/) { | |
130 | $grub_number++; | |
131 | } | |
132 | } | |
133 | close(IN); | |
134 | ||
135 | die "Could not find '$opt{GRUB_MENU}' in /boot/grub/menu on $opt{MACHINE}" | |
136 | if ($grub_number < 0); | |
137 | doprint "$grub_number\n"; | |
2545eb61 SR |
138 | } |
139 | ||
140 | my $timeout = $opt{"TIMEOUT"}; | |
141 | ||
142 | sub wait_for_input | |
143 | { | |
144 | my ($fp, $time) = @_; | |
145 | my $rin; | |
146 | my $ready; | |
147 | my $line; | |
148 | my $ch; | |
149 | ||
150 | if (!defined($time)) { | |
151 | $time = $timeout; | |
152 | } | |
153 | ||
154 | $rin = ''; | |
155 | vec($rin, fileno($fp), 1) = 1; | |
156 | $ready = select($rin, undef, undef, $time); | |
157 | ||
158 | $line = ""; | |
159 | ||
160 | # try to read one char at a time | |
161 | while (sysread $fp, $ch, 1) { | |
162 | $line .= $ch; | |
163 | last if ($ch eq "\n"); | |
164 | } | |
165 | ||
166 | if (!length($line)) { | |
167 | return undef; | |
168 | } | |
169 | ||
170 | return $line; | |
171 | } | |
172 | ||
75c3fda7 | 173 | sub reboot_to { |
2545eb61 SR |
174 | run_command "ssh $target '(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'"; |
175 | } | |
176 | ||
5a391fbf SR |
177 | sub open_console { |
178 | my ($fp) = @_; | |
179 | ||
2545eb61 | 180 | my $flags; |
5a391fbf SR |
181 | |
182 | my $pid = open($fp, "$opt{CONSOLE}|") or | |
183 | dodie "Can't open console $opt{CONSOLE}"; | |
184 | ||
185 | $flags = fcntl($fp, F_GETFL, 0) or | |
186 | dodie "Can't get flags for the socket: $!\n"; | |
187 | $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or | |
188 | dodie "Can't set flags for the socket: $!\n"; | |
189 | ||
190 | return $pid; | |
191 | } | |
192 | ||
193 | sub close_console { | |
194 | my ($fp, $pid) = @_; | |
195 | ||
196 | doprint "kill child process $pid\n"; | |
197 | kill 2, $pid; | |
198 | ||
199 | print "closing!\n"; | |
200 | close($fp); | |
201 | } | |
202 | ||
203 | sub monitor { | |
2545eb61 SR |
204 | my $booted = 0; |
205 | my $bug = 0; | |
206 | my $pid; | |
5c42fc5b | 207 | my $skip_call_trace = 0; |
5a391fbf | 208 | my $fp = \*IN; |
2545eb61 | 209 | |
5a391fbf | 210 | $pid = open_console($fp); |
2545eb61 SR |
211 | |
212 | my $line; | |
213 | my $full_line = ""; | |
214 | ||
215 | doprint "Wait for monitor to settle down.\n"; | |
216 | # read the monitor and wait for the system to calm down | |
217 | do { | |
5a391fbf | 218 | $line = wait_for_input($fp, 5); |
2545eb61 SR |
219 | } while (defined($line)); |
220 | ||
75c3fda7 | 221 | reboot_to; |
2545eb61 SR |
222 | |
223 | for (;;) { | |
224 | ||
5a391fbf | 225 | $line = wait_for_input($fp); |
2545eb61 SR |
226 | |
227 | last if (!defined($line)); | |
228 | ||
229 | doprint $line; | |
230 | ||
231 | # we are not guaranteed to get a full line | |
232 | $full_line .= $line; | |
233 | ||
234 | if ($full_line =~ /login:/) { | |
235 | $booted = 1; | |
236 | } | |
237 | ||
5c42fc5b SR |
238 | if ($full_line =~ /\[ backtrace testing \]/) { |
239 | $skip_call_trace = 1; | |
240 | } | |
241 | ||
2545eb61 | 242 | if ($full_line =~ /call trace:/i) { |
5c42fc5b SR |
243 | $bug = 1 if (!$skip_call_trace); |
244 | } | |
245 | ||
246 | if ($full_line =~ /\[ end of backtrace testing \]/) { | |
247 | $skip_call_trace = 0; | |
248 | } | |
249 | ||
250 | if ($full_line =~ /Kernel panic -/) { | |
2545eb61 SR |
251 | $bug = 1; |
252 | } | |
253 | ||
254 | if ($line =~ /\n/) { | |
255 | $full_line = ""; | |
256 | } | |
257 | } | |
258 | ||
5a391fbf | 259 | close_console($fp, $pid); |
2545eb61 SR |
260 | |
261 | if (!$booted) { | |
5a391fbf | 262 | return 1 if ($in_bisect); |
5c42fc5b | 263 | dodie "failed - never got a boot prompt.\n"; |
2545eb61 SR |
264 | } |
265 | ||
266 | if ($bug) { | |
5a391fbf | 267 | return 1 if ($in_bisect); |
5c42fc5b | 268 | dodie "failed - got a bug report\n"; |
2545eb61 | 269 | } |
5f9b6ced SR |
270 | |
271 | return 0; | |
2545eb61 SR |
272 | } |
273 | ||
274 | sub install { | |
275 | ||
5f9b6ced | 276 | run_command "scp $opt{OUTPUT_DIR}/$opt{BUILD_TARGET} $target:$opt{TARGET_IMAGE}" or |
5c42fc5b | 277 | dodie "failed to copy image"; |
2545eb61 | 278 | |
5f9b6ced | 279 | my $install_mods = 0; |
2545eb61 | 280 | |
5f9b6ced SR |
281 | # should we process modules? |
282 | $install_mods = 0; | |
283 | open(IN, "$opt{OUTPUT_DIR}/.config") or dodie("Can't read config file"); | |
284 | while (<IN>) { | |
285 | if (/CONFIG_MODULES(=y)?/) { | |
286 | $install_mods = 1 if (defined($1)); | |
287 | last; | |
5c42fc5b | 288 | } |
5f9b6ced SR |
289 | } |
290 | close(IN); | |
5c42fc5b | 291 | |
5f9b6ced SR |
292 | if (!$install_mods) { |
293 | doprint "No modules needed\n"; | |
294 | return; | |
295 | } | |
2545eb61 | 296 | |
5f9b6ced SR |
297 | run_command "$make INSTALL_MOD_PATH=$opt{TMP_DIR} modules_install" or |
298 | dodie "Failed to install modules"; | |
5c42fc5b | 299 | |
5f9b6ced SR |
300 | my $modlib = "/lib/modules/$version"; |
301 | my $modtar = "autotest-mods.tar.bz2"; | |
5c42fc5b | 302 | |
5f9b6ced SR |
303 | run_command "ssh $target rm -rf $modlib" or |
304 | dodie "failed to remove old mods: $modlib"; | |
5c42fc5b | 305 | |
5f9b6ced SR |
306 | # would be nice if scp -r did not follow symbolic links |
307 | run_command "cd $opt{TMP_DIR} && tar -cjf $modtar lib/modules/$version" or | |
308 | dodie "making tarball"; | |
309 | ||
310 | run_command "scp $opt{TMP_DIR}/$modtar $target:/tmp" or | |
311 | dodie "failed to copy modules"; | |
312 | ||
313 | unlink "$opt{TMP_DIR}/$modtar"; | |
314 | ||
315 | run_command "ssh $target '(cd / && tar xf /tmp/$modtar)'" or | |
316 | dodie "failed to tar modules"; | |
2545eb61 | 317 | |
5f9b6ced | 318 | run_command "ssh $target rm -f /tmp/$modtar"; |
2545eb61 SR |
319 | } |
320 | ||
6c5ee0be SR |
321 | sub check_buildlog { |
322 | my ($patch) = @_; | |
323 | ||
324 | my $buildlog = "$opt{TMP_DIR}/buildlog"; | |
325 | my @files = `git show $patch | diffstat -l`; | |
326 | ||
327 | open(IN, "git show $patch |") or | |
328 | dodie "failed to show $patch"; | |
329 | while (<IN>) { | |
330 | if (m,^--- a/(.*),) { | |
331 | chomp $1; | |
332 | $files[$#files] = $1; | |
333 | } | |
334 | } | |
335 | close(IN); | |
336 | ||
337 | open(IN, $buildlog) or dodie "Can't open $buildlog"; | |
338 | while (<IN>) { | |
339 | if (/^\s*(.*?):.*(warning|error)/) { | |
340 | my $err = $1; | |
341 | foreach my $file (@files) { | |
342 | my $fullpath = "$opt{BUILD_DIR}/$file"; | |
343 | if ($file eq $err || $fullpath eq $err) { | |
344 | dodie "$file built with warnings"; | |
345 | } | |
346 | } | |
347 | } | |
348 | } | |
349 | close(IN); | |
350 | } | |
351 | ||
2545eb61 SR |
352 | sub build { |
353 | my ($type) = @_; | |
5c42fc5b SR |
354 | my $defconfig = ""; |
355 | my $append = ""; | |
356 | ||
75c3fda7 | 357 | if ($type =~ /^useconfig:(.*)/) { |
5f9b6ced | 358 | run_command "cp $1 $opt{OUTPUT_DIR}/.config" or |
75c3fda7 | 359 | dodie "could not copy $1 to .config"; |
5f9b6ced | 360 | |
75c3fda7 SR |
361 | $type = "oldconfig"; |
362 | } | |
363 | ||
5c42fc5b SR |
364 | # old config can ask questions |
365 | if ($type eq "oldconfig") { | |
366 | $append = "yes ''|"; | |
75c3fda7 SR |
367 | |
368 | # allow for empty configs | |
369 | run_command "touch $opt{OUTPUT_DIR}/.config"; | |
370 | ||
5f9b6ced | 371 | run_command "mv $opt{OUTPUT_DIR}/.config $opt{OUTPUT_DIR}/config_temp" or |
5c42fc5b | 372 | dodie "moving .config"; |
2545eb61 | 373 | |
5f9b6ced | 374 | if (!$noclean && !run_command "$make mrproper") { |
5c42fc5b SR |
375 | dodie "make mrproper"; |
376 | } | |
2545eb61 | 377 | |
5f9b6ced | 378 | run_command "mv $opt{OUTPUT_DIR}/config_temp $opt{OUTPUT_DIR}/.config" or |
5c42fc5b | 379 | dodie "moving config_temp"; |
5c42fc5b SR |
380 | |
381 | } elsif (!$noclean) { | |
382 | unlink "$opt{OUTPUT_DIR}/.config"; | |
5f9b6ced | 383 | run_command "$make mrproper" or |
5c42fc5b | 384 | dodie "make mrproper"; |
5c42fc5b | 385 | } |
2545eb61 SR |
386 | |
387 | # add something to distinguish this build | |
5c42fc5b | 388 | open(OUT, "> $opt{OUTPUT_DIR}/localversion") or dodie("Can't make localversion file"); |
2545eb61 SR |
389 | print OUT "$opt{LOCALVERSION}\n"; |
390 | close(OUT); | |
391 | ||
5f9b6ced SR |
392 | if (defined($minconfig)) { |
393 | $defconfig = "KCONFIG_ALLCONFIG=$minconfig"; | |
2545eb61 SR |
394 | } |
395 | ||
5f9b6ced | 396 | run_command "$defconfig $append $make $type" or |
5c42fc5b | 397 | dodie "failed make config"; |
2545eb61 | 398 | |
6c5ee0be SR |
399 | # patch check will examine the log |
400 | if ($in_patchcheck) { | |
401 | $redirect = "$opt{TMP_DIR}/buildlog"; | |
402 | } | |
403 | ||
5f9b6ced | 404 | if (!run_command "$make $opt{BUILD_OPTIONS}") { |
6c5ee0be | 405 | undef $redirect; |
5f9b6ced SR |
406 | # bisect may need this to pass |
407 | return 1 if ($in_bisect); | |
5c42fc5b | 408 | dodie "failed build"; |
2545eb61 | 409 | } |
6c5ee0be | 410 | undef $redirect; |
5f9b6ced SR |
411 | |
412 | return 0; | |
2545eb61 SR |
413 | } |
414 | ||
75c3fda7 SR |
415 | sub reboot { |
416 | # try to reboot normally | |
5f9b6ced | 417 | if (!run_command "ssh $target reboot") { |
75c3fda7 SR |
418 | # nope? power cycle it. |
419 | run_command "$opt{POWER_CYCLE}"; | |
420 | } | |
421 | } | |
422 | ||
423 | sub halt { | |
5f9b6ced | 424 | if (!run_command "ssh $target halt" or defined($opt{"POWER_OFF"})) { |
75c3fda7 SR |
425 | # nope? the zap it! |
426 | run_command "$opt{POWER_OFF}"; | |
427 | } | |
428 | } | |
429 | ||
5f9b6ced SR |
430 | sub success { |
431 | my ($i) = @_; | |
432 | ||
433 | doprint "\n\n*******************************************\n"; | |
434 | doprint "*******************************************\n"; | |
435 | doprint "** SUCCESS!!!! **\n"; | |
436 | doprint "*******************************************\n"; | |
437 | doprint "*******************************************\n"; | |
438 | ||
439 | if ($i != $opt{"NUM_BUILDS"}) { | |
440 | reboot; | |
441 | doprint "Sleeping $opt{SLEEP_TIME} seconds\n"; | |
442 | sleep "$opt{SLEEP_TIME}"; | |
443 | } | |
444 | } | |
445 | ||
446 | sub get_version { | |
447 | # get the release name | |
448 | doprint "$make kernelrelease ... "; | |
449 | $version = `$make kernelrelease | tail -1`; | |
450 | chomp($version); | |
451 | doprint "$version\n"; | |
452 | } | |
453 | ||
5a391fbf SR |
454 | sub child_run_test { |
455 | my $failed; | |
456 | ||
457 | $failed = !run_command $run_test; | |
458 | exit $failed; | |
459 | } | |
460 | ||
461 | my $child_done; | |
462 | ||
463 | sub child_finished { | |
464 | $child_done = 1; | |
465 | } | |
466 | ||
467 | sub do_run_test { | |
468 | my $child_pid; | |
469 | my $child_exit; | |
470 | my $pid; | |
471 | my $line; | |
472 | my $full_line; | |
473 | my $bug = 0; | |
474 | my $fp = \*IN; | |
475 | ||
476 | $pid = open_console($fp); | |
477 | ||
478 | # read the monitor and wait for the system to calm down | |
479 | do { | |
480 | $line = wait_for_input($fp, 1); | |
481 | } while (defined($line)); | |
482 | ||
483 | $child_done = 0; | |
484 | ||
485 | $SIG{CHLD} = qw(child_finished); | |
486 | ||
487 | $child_pid = fork; | |
488 | ||
489 | child_run_test if (!$child_pid); | |
490 | ||
491 | $full_line = ""; | |
492 | ||
493 | do { | |
494 | $line = wait_for_input($fp, 1); | |
495 | if (defined($line)) { | |
496 | ||
497 | # we are not guaranteed to get a full line | |
498 | $full_line .= $line; | |
499 | ||
500 | if ($full_line =~ /call trace:/i) { | |
501 | $bug = 1; | |
502 | } | |
503 | ||
504 | if ($full_line =~ /Kernel panic -/) { | |
505 | $bug = 1; | |
506 | } | |
507 | ||
508 | if ($line =~ /\n/) { | |
509 | $full_line = ""; | |
510 | } | |
511 | } | |
512 | } while (!$child_done && !$bug); | |
513 | ||
514 | if ($bug) { | |
515 | doprint "Detected kernel crash!\n"; | |
516 | # kill the child with extreme prejudice | |
517 | kill 9, $child_pid; | |
518 | } | |
519 | ||
520 | waitpid $child_pid, 0; | |
521 | $child_exit = $?; | |
522 | ||
523 | close_console($fp, $pid); | |
524 | ||
525 | if ($bug || $child_exit) { | |
526 | return 1 if $in_bisect; | |
527 | dodie "test failed"; | |
528 | } | |
529 | return 0; | |
530 | } | |
531 | ||
5f9b6ced SR |
532 | sub run_bisect { |
533 | my ($type) = @_; | |
534 | ||
535 | my $failed; | |
536 | my $result; | |
537 | my $output; | |
538 | my $ret; | |
539 | ||
540 | ||
541 | if (defined($minconfig)) { | |
542 | $failed = build "useconfig:$minconfig"; | |
543 | } else { | |
544 | # ?? no config to use? | |
545 | $failed = build "oldconfig"; | |
546 | } | |
547 | ||
548 | if ($type ne "build") { | |
549 | dodie "Failed on build" if $failed; | |
550 | ||
551 | # Now boot the box | |
552 | get_grub_index; | |
553 | get_version; | |
554 | install; | |
555 | $failed = monitor; | |
556 | ||
557 | if ($type ne "boot") { | |
558 | dodie "Failed on boot" if $failed; | |
5a391fbf SR |
559 | |
560 | $failed = do_run_test; | |
5f9b6ced SR |
561 | } |
562 | } | |
563 | ||
564 | if ($failed) { | |
565 | $result = "bad"; | |
5a391fbf SR |
566 | |
567 | # reboot the box to a good kernel | |
568 | if ($type eq "boot") { | |
569 | reboot; | |
570 | doprint "sleep a little for reboot\n"; | |
571 | sleep $opt{"BISECT_SLEEP_TIME"}; | |
572 | } | |
5f9b6ced SR |
573 | } else { |
574 | $result = "good"; | |
575 | } | |
576 | ||
577 | doprint "git bisect $result ... "; | |
578 | $output = `git bisect $result 2>&1`; | |
579 | $ret = $?; | |
580 | ||
581 | logit $output; | |
582 | ||
583 | if ($ret) { | |
584 | doprint "FAILED\n"; | |
585 | dodie "Failed to git bisect"; | |
586 | } | |
587 | ||
588 | doprint "SUCCESS\n"; | |
5a391fbf | 589 | if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) { |
5f9b6ced SR |
590 | doprint "$1 [$2]\n"; |
591 | } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) { | |
592 | $bisect_bad = $1; | |
593 | doprint "Found bad commit... $1\n"; | |
594 | return 0; | |
5a391fbf SR |
595 | } else { |
596 | # we already logged it, just print it now. | |
597 | print $output; | |
5f9b6ced SR |
598 | } |
599 | ||
600 | ||
601 | return 1; | |
602 | } | |
603 | ||
604 | sub bisect { | |
605 | my ($i) = @_; | |
606 | ||
607 | my $result; | |
608 | ||
609 | die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"})); | |
610 | die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"})); | |
611 | die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"})); | |
612 | ||
613 | my $good = $opt{"BISECT_GOOD[$i]"}; | |
614 | my $bad = $opt{"BISECT_BAD[$i]"}; | |
615 | my $type = $opt{"BISECT_TYPE[$i]"}; | |
616 | ||
617 | $in_bisect = 1; | |
618 | ||
619 | run_command "git bisect start" or | |
620 | dodie "could not start bisect"; | |
621 | ||
622 | run_command "git bisect good $good" or | |
623 | dodie "could not set bisect good to $good"; | |
624 | ||
625 | run_command "git bisect bad $bad" or | |
626 | dodie "could not set bisect good to $bad"; | |
627 | ||
5a391fbf SR |
628 | # Can't have a test without having a test to run |
629 | if ($type eq "test" && !defined($run_test)) { | |
630 | $type = "boot"; | |
631 | } | |
632 | ||
5f9b6ced SR |
633 | do { |
634 | $result = run_bisect $type; | |
635 | } while ($result); | |
636 | ||
637 | run_command "git bisect log" or | |
638 | dodie "could not capture git bisect log"; | |
639 | ||
640 | run_command "git bisect reset" or | |
641 | dodie "could not reset git bisect"; | |
642 | ||
643 | doprint "Bad commit was [$bisect_bad]\n"; | |
644 | ||
645 | $in_bisect = 0; | |
646 | ||
647 | success $i; | |
648 | } | |
649 | ||
6c5ee0be SR |
650 | sub patchcheck { |
651 | my ($i) = @_; | |
652 | ||
653 | die "PATCHCHECK_START[$i] not defined\n" | |
654 | if (!defined($opt{"PATCHCHECK_START[$i]"})); | |
655 | die "PATCHCHECK_TYPE[$i] not defined\n" | |
656 | if (!defined($opt{"PATCHCHECK_TYPE[$i]"})); | |
657 | ||
658 | my $start = $opt{"PATCHCHECK_START[$i]"}; | |
659 | ||
660 | my $end = "HEAD"; | |
661 | if (defined($opt{"PATCHCHECK_END[$i]"})) { | |
662 | $end = $opt{"PATCHCHECK_END[$i]"}; | |
663 | } | |
664 | ||
665 | my $type = $opt{"PATCHCHECK_TYPE[$i]"}; | |
666 | ||
667 | # Can't have a test without having a test to run | |
668 | if ($type eq "test" && !defined($run_test)) { | |
669 | $type = "boot"; | |
670 | } | |
671 | ||
672 | open (IN, "git log --pretty=oneline $end|") or | |
673 | dodie "could not get git list"; | |
674 | ||
675 | my @list; | |
676 | ||
677 | while (<IN>) { | |
678 | chomp; | |
679 | $list[$#list+1] = $_; | |
680 | last if (/^$start/); | |
681 | } | |
682 | close(IN); | |
683 | ||
684 | if ($list[$#list] !~ /^$start/) { | |
685 | dodie "SHA1 $start not found"; | |
686 | } | |
687 | ||
688 | # go backwards in the list | |
689 | @list = reverse @list; | |
690 | ||
691 | my $save_clean = $noclean; | |
692 | ||
693 | $in_patchcheck = 1; | |
694 | foreach my $item (@list) { | |
695 | my $sha1 = $item; | |
696 | $sha1 =~ s/^([[:xdigit:]]+).*/$1/; | |
697 | ||
698 | doprint "\nProcessing commit $item\n\n"; | |
699 | ||
700 | run_command "git checkout $sha1" or | |
701 | die "Failed to checkout $sha1"; | |
702 | ||
703 | # only clean on the first and last patch | |
704 | if ($item eq $list[0] || | |
705 | $item eq $list[$#list]) { | |
706 | $noclean = $save_clean; | |
707 | } else { | |
708 | $noclean = 1; | |
709 | } | |
710 | ||
711 | if (defined($minconfig)) { | |
712 | build "useconfig:$minconfig"; | |
713 | } else { | |
714 | # ?? no config to use? | |
715 | build "oldconfig"; | |
716 | } | |
717 | ||
718 | check_buildlog $sha1; | |
719 | ||
720 | next if ($type eq "build"); | |
721 | ||
722 | get_grub_index; | |
723 | get_version; | |
724 | install; | |
725 | monitor; | |
726 | ||
727 | next if ($type eq "boot"); | |
728 | do_run_test; | |
729 | } | |
730 | $in_patchcheck = 0; | |
731 | success $i; | |
732 | } | |
733 | ||
2545eb61 SR |
734 | read_config $ARGV[0]; |
735 | ||
736 | # mandatory configs | |
737 | die "MACHINE not defined\n" if (!defined($opt{"MACHINE"})); | |
738 | die "SSH_USER not defined\n" if (!defined($opt{"SSH_USER"})); | |
739 | die "BUILD_DIR not defined\n" if (!defined($opt{"BUILD_DIR"})); | |
740 | die "OUTPUT_DIR not defined\n" if (!defined($opt{"OUTPUT_DIR"})); | |
741 | die "BUILD_TARGET not defined\n" if (!defined($opt{"BUILD_TARGET"})); | |
75c3fda7 | 742 | die "TARGET_IMAGE not defined\n" if (!defined($opt{"TARGET_IMAGE"})); |
2545eb61 SR |
743 | die "POWER_CYCLE not defined\n" if (!defined($opt{"POWER_CYCLE"})); |
744 | die "CONSOLE not defined\n" if (!defined($opt{"CONSOLE"})); | |
745 | die "LOCALVERSION not defined\n" if (!defined($opt{"LOCALVERSION"})); | |
746 | die "GRUB_MENU not defined\n" if (!defined($opt{"GRUB_MENU"})); | |
747 | ||
748 | chdir $opt{"BUILD_DIR"} || die "can't change directory to $opt{BUILD_DIR}"; | |
749 | ||
750 | $target = "$opt{SSH_USER}\@$opt{MACHINE}"; | |
751 | ||
752 | doprint "\n\nSTARTING AUTOMATED TESTS\n"; | |
753 | ||
2545eb61 SR |
754 | |
755 | $make = "$opt{MAKE_CMD} O=$opt{OUTPUT_DIR}"; | |
756 | ||
5a391fbf SR |
757 | sub set_build_option { |
758 | my ($name, $i) = @_; | |
2545eb61 | 759 | |
5a391fbf | 760 | my $option = "$name\[$i\]"; |
5c42fc5b | 761 | |
5a391fbf SR |
762 | if (defined($opt{$option})) { |
763 | return $opt{$option}; | |
5f9b6ced SR |
764 | } |
765 | ||
5a391fbf SR |
766 | if (defined($opt{$name})) { |
767 | return $opt{$name}; | |
2545eb61 SR |
768 | } |
769 | ||
5a391fbf SR |
770 | return undef; |
771 | } | |
772 | ||
773 | # First we need to do is the builds | |
774 | for (my $i = 1; $i <= $opt{"NUM_BUILDS"}; $i++) { | |
775 | my $type = "BUILD_TYPE[$i]"; | |
776 | ||
1a5cfce3 SR |
777 | if (!defined($opt{$type})) { |
778 | $opt{$type} = $opt{"DEFAULT_BUILD_TYPE"}; | |
779 | } | |
780 | ||
5a391fbf SR |
781 | $noclean = set_build_option("BUILD_NOCLEAN", $i); |
782 | $minconfig = set_build_option("MIN_CONFIG", $i); | |
783 | $run_test = set_build_option("TEST", $i); | |
784 | ||
2545eb61 SR |
785 | doprint "\n\n"; |
786 | doprint "RUNNING TEST $i of $opt{NUM_BUILDS} with option $opt{$type}\n\n"; | |
787 | ||
6c5ee0be SR |
788 | my $checkout = $opt{"CHECKOUT[$i]"}; |
789 | if (defined($checkout)) { | |
790 | run_command "git checkout $checkout" or | |
791 | die "failed to checkout $checkout"; | |
792 | } | |
793 | ||
5f9b6ced SR |
794 | if ($opt{$type} eq "bisect") { |
795 | bisect $i; | |
796 | next; | |
6c5ee0be SR |
797 | } elsif ($opt{$type} eq "patchcheck") { |
798 | patchcheck $i; | |
799 | next; | |
2545eb61 | 800 | } |
2545eb61 | 801 | |
5f9b6ced SR |
802 | if ($opt{$type} ne "nobuild") { |
803 | build $opt{$type}; | |
2545eb61 SR |
804 | } |
805 | ||
5f9b6ced SR |
806 | get_grub_index; |
807 | get_version; | |
2545eb61 | 808 | install; |
2545eb61 | 809 | monitor; |
5a391fbf SR |
810 | |
811 | if (defined($run_test)) { | |
812 | do_run_test; | |
813 | } | |
814 | ||
5f9b6ced | 815 | success $i; |
2545eb61 SR |
816 | } |
817 | ||
5c42fc5b | 818 | if ($opt{"POWEROFF_ON_SUCCESS"}) { |
75c3fda7 | 819 | halt; |
1a5cfce3 | 820 | } elsif ($opt{"REBOOT_ON_SUCCESS"}) { |
75c3fda7 | 821 | reboot; |
5c42fc5b | 822 | } |
75c3fda7 | 823 | |
2545eb61 | 824 | exit 0; |