#!/usr/bin/perl #syntax one of: wraptests filename directory to run all accounts # wraptests filename directory seas to run all accounts alphabetically #strictly AFTER seas which is useful if seas crashed, then this continues after that student. #wraptest echos to screen the current seas account so that it is easy to see which was the one #that caused a crash/infinite loop/etc. # wraptests filename directory seas [redo] anything to run ONLY seas #If $redo is set to 0 (should be done after runtest script and test cases are finalized), then #wraptest will only call runtests for those students who do not have a results file. It #currently does NOT check that the newest submission is older then the results file. Note that #the rename script will report new resubmissions (see rename for details and limitations). If the #redo option is the word 'redo', then wraptest will call runtests even if there is a results file. #By setting $redo=1, the script will always run in redo, helpful during debugging of runtests. #see also the current alias' in glogin: wt, rt, ng, and ren. #filename is the name of the submission ($filename), directory ($script_dir) is the name of the #directory containing the relevant runtests #executes $home/$script_dir/runtests in each student directory. #Last code in this script is a call to system ("@commands"), change system to print and it will #output the commands it would have executed. #In Perl, $ is a scalar variable (number, string, etc), @ is an array, % is a hash. #array look up is $array[index], hash get is $hash{key}, $ is b/c result is a scalar variable #There aren't any hashes in this script. #$skips is a space separated list of students whose code should be skipped. Useful if no ahead of #time (b/c of rerunning script) that a student's code will infinite loop. Can also handle them #separately (see end of code) if it is known what tests to skip. $filename=shift @ARGV; #exact filename $script_dir=shift @ARGV; #directory with runtests script in it $home="/u/cs/class/cs131/cs131xx"; #home directory $errorfile="$script_dir-error"; #for compilation error output, mainly for Java $resultsfile="$script_dir-results"; #output file of runtests $redo=0; #flag==1 -->rerun runtests even if results present unless ($filename && $script_dir) { print "Syntax is wraptest filename directory [seas] [opt]\n"; exit; } #$skips=''; $start=shift @ARGV; #get a starting seas directory if ($start eq "redo") { $start=''; $redo=1; } elsif ($start eq "this") { $redo=1; $temp=`pwd`; ($start) = $temp =~ m:/(\w+)\n:; $ARGV[0]=1; } if ($ARGV[0] eq "redo") { #redo present? $redo=1; shift @ARGV; } if (@ARGV) { #'anything' was present, so just run on seas which is in $start $files[0]="$start"; } else { @files=`ls $home/*/$filename`; #get list of all submissions, assumes rename already run #shells out, runs ls, each line is a file and each line is element of array @files. map {s:$home/(\w+)/$filename.*:$1:so} @files; #strips off filename so that it is now a directory shift @files if ($files[0] eq "$script_dir"); #I use capital names for script dir so it will be #first if present, present if file with submission name is there from testing while ($start && $#files>=0) { #if have starting account then skip past it using shift $start="" if ($files[0] eq $start); #found start, remove it and stop shifting afterwards shift @files; } } shift @files while ($files[0]=~ m:[A-Z]:); require "$home/$script_dir/runtests"; $count=0; foreach $dir (@files) { # next if ($skips =~ m:\b$dir\b:); #\b so that if xyz isn't skipped b/c axyzb is in list next if (!$redo && (-f "$home/$dir/$resultsfile") ); # skip if results present and not redoing if ((-e "$home/$dir/$errorfile" && -s "$home/$dir/$errorfile" ) ||#no compile student (-e "$home/$dir/${errorfile}Test" && -s "$home/$dir/${errorfile}Test")) {#no compile driver `echo \"Did not compile\n\nFinal Score is 0\n\" > $resultsfile`; } else { print " $dir\n"; chdir "$home/$dir"; if (-f "$home/$dir/$resultsfile") {rename $resultsfile, "$resultsfile.bak";} # if (-f "$home/$dir/$resultsfile") {rename $resultsfile, "$resultsfile.orig";} if (-f "$home/$dir/${errorfile}Run") {rename "${errorfile}Run", "${errorfile}Run.bak";} &runtests; # >${errorfile}Run 2>&1\n";} } } &killbad; #This loop will go through the seas accounts listed in $skips and try them on a subset of the test #cases. This is useful if there are a couple of cases that a lot of people crash/loop on. Only #does this if not testing 1 single seas account and if $skips contains people. Runtests is assumed #to support parameters indicating tests to skip. For my code, runtests N would skip test N, #runtests X M-N Y would skip tests M through N, test X and test Y. So list here whichever tests #are causing the problem. May still have to test them individually #if (!@ARGV && $skips) { # $loops="1 5-8"; #put tough tests here # push @commands, "echo 'Trying skips'\n"; # @files=sort split (/\s+/, $skips); #try them in alphabetical order, if they still crash # #easier to track which ran if in order. # foreach $dir (@files) { # push @commands, "echo \" $dir\"\ncd $home/$dir\n$home/$script_dir/runtests $loops\n"; # } #} sub killbad { #this is specialized for speed versus killbad in Scripts directory #also avoids shell for killbad and recompilation. my @procs=`ps -u cs131xx`; shift @procs; foreach $ps (@procs) {kill 9, $1 if ($ps =~ m:\s+(\d+)\s.*\bmzscheme\b:);} }