source: PSPA/madxPSPA/testing/MadTestPy.pl @ 457

Last change on this file since 457 was 430, checked in by touze, 11 years ago

import madx-5.01.00

File size: 33.3 KB
Line 
1#!/usr/bin/perl
2
3# now supports a specific $debugMode to carry-out tests of a single target.
4# sample invocation: MadTest.pl ./MadCvsExtract/madX debug=match
5# In this case, HTML file becomes test_debug.html instead of test.htm.
6
7# input: directory name in which madx and madxp are present
8# output: a hierachy of directories to hold the tests' inputs and outputs
9# at the same time an HTML document is created and moved to the web folder
10
11# Still to do :
12# (1) expand call-tree till the leafs
13# (2) accomodate for different directory structures
14# (3) allow for files loading from different directories in the call-tree
15# (4) check potential troubles with namespace restricted to target name
16# (5) ideally HTML formatting should be moved out of the code, relying on XML, XSLT and CSS instead
17
18use MIME::Lite; # to send e-mail
19
20open REPORT_FILE, ">MadTest_Report.txt";
21
22$startTime = localtime;
23
24my $path = $ENV{'PATH'};
25my $newPath = $path . ":."; # can invoke local commands from MAD-X script
26$ENV{'PATH'}=$newPath;
27
28
29
30print REPORT_FILE "MadTest.pl report from $startTime\n";
31
32$testReport = ""; # will be stored into an HTML document
33
34$pwd = `pwd`;
35chop $pwd;
36$localRootDir = $pwd;
37
38# for Makefile_develop and Makefile_nag, stderr is redirected
39my $stderrFile = "stderr_redirected";
40
41my $debugMode;          # select a specific target and writes summary HTML file
42                        # to test_debug.htm instead of test.htm
43my $debugTarget;        # meaningful iff $debugMode is set to 1
44
45my $silentMode = 0;     # if set, no message will be sent. 0 by default
46               
47if ( $#ARGV < 0 ) {
48    print "expect at least 1 argument: (1) MAD executable directory [(2) debug:<target>]  EXIT!\n" ;
49    exit ;
50} else {
51    if (($#ARGV == 1) || ($#ARGV == 2)) {
52        # second parameter for debug-mode
53        my $option = @ARGV[1];
54        if ($option =~ /^debug=(\w+)/){
55            $debugMode = 1;
56            $debugTarget = $1;
57            print "debug mode set for target '$debugTarget'\n";
58        } elsif ($option =~ /^silent$/){
59            $silentMode = 1;
60        } else {
61            print "the second optional argument '$option' should be of the form:";
62            print "debug=<target>\n";
63            print "EXIT!\n";
64            exit;
65        }
66    }
67       
68        $madDir = @ARGV[0];
69        # check specified directory indeed contains executable
70        $existsMadx = `ls $madDir/madx | wc -l`;
71        if ($existsMadx == 0) {
72                print REPORT_FILE "Madx missing in specified directory => exit!\n";
73                exit;
74        }
75#       $existsMadxp = `ls $madDir/madxp | wc -l`;
76#       if ($existsMadxp == 0){
77#               print REPORT_FILE "Madxp missing in specified directory => exit!\n";
78#               exit;
79#       }
80        # expand the full path
81        $_ = $madDir;
82        if (/^.\/([\w\d_\-\/.]+)/) {
83                # local path specified
84                $madDir = $localRootDir . "/" . $1;
85        } else { 
86                # full path already given
87        }
88
89        # remove last "/" if any
90        $_ = $madDir;
91        if (/\/$/) { chop $madDir;  } # $ for end anchoring of the string
92
93
94}
95
96
97# checkout reference examples from the CVS
98my $rmRes = `rm -rf ./madX-examples`;
99
100if ($debugMode ==0){
101        # default: we retrieve all the CVS
102        print REPORT_FILE "extract the complete CVS repository containing examples\n";
103        my $checkoutRes = `cvs -d :gserver:isscvs.cern.ch:/local/reps/madx-examples checkout madX-examples`;
104        print REPORT_FILE $checkoutRes;
105} else {
106        print REPORT_FILE "extract only the CVS repository containing specific example";
107        print REPORT_FILE " $debugTarget\n";
108        # extract only the $debugTarget from the CVS
109        my $checkoutRes = `cvs -d :gserver:isscvs.cern.ch:/local/reps/madx-examples checkout madX-examples/REF/$debugTarget`;
110        print REPORT_FILE $checkoutRes;
111}
112
113# $samplesRootDir = '/afs/cern.ch/user/f/frs/public_html/mad-X_examples';
114
115$samplesRootDir = "$localRootDir/madX-examples/REF";
116
117
118$htmlRootDir = '/afs/cern.ch/user/n/nougaret/www/mad';
119
120if ($debugMode == 0) {
121        $htmlFile = "$htmlRootDir/test.htm"; # for the time being
122} else {
123        $htmlFile = "$htmlRootDir/test_debug.htm"; # for the time being
124}
125       
126@targetDirs = `ls $samplesRootDir`;
127
128# search all test examples' directories
129# (only a subset of them will be processed by the automated test, as specified in a separate XML document)
130
131# in future version, should grow the call-graph from the list of source mad files provided in the XML file
132
133# not instead of being performed beforehand on all possible files, this dependency analysis should only be
134# carried-out on the actual target directories...
135
136# build the call-graph
137TARGET_DIR: foreach $targetDir (@targetDirs) {
138
139chop $targetDir;
140
141if ($debugMode ==1) {
142        if ($targetDir ne $debugTarget){
143                next TARGET_DIR;
144        }
145}
146
147
148print REPORT_FILE "target = '$targetDir'\n";
149
150chdir("$samplesRootDir/$targetDir");
151@subdirectories =`ls -d */`; # returns directories only (with '/' suffix)
152
153@alldirectories = ('./',@subdirectories);
154foreach $dir (@alldirectories) {
155        chop $dir; # end-of-line
156        chop $dir; # /
157        $pwd = `pwd`; # for print below
158        print REPORT_FILE "process directory $dir in $pwd\n";
159        if ($dir eq "test") { next; } # Very specific case: twiss/test directory causes multiple key error in call-graph
160        chdir("$samplesRootDir/$targetDir/$dir"); # go to subdir to open files with getListOfDependantFiles()
161        @files = `ls`;
162        foreach $file(@files) {
163        chop $file;
164        print REPORT_FILE "process $file"; 
165        $dependentFileList = getListOfDependantFiles($file);
166        # avoid name clash by prefixing
167        $fileKey = $targetDir . "/" . $file;
168        if ($dependencyList{$fileKey} ne "") {
169                # actually no trouble if the entry is the same
170                if ($dependencyList{$fileKey} eq $dependentFileList) {
171                print REPORT_FILE "WARNING: multiple entry $fileKey in call-graph\n";
172                $testReport .= "</p><font color=\"#FFCCBB\">WARNING: multiple entry $fileKey in call-graph</font></p>\n";
173
174                } else {
175                $testReport .= "</p><font color=\"#FFBBBB\">ERROR: multiple incompatible entry $fileKey in call-graph</font></p>\n";
176                print REPORT_FILE "ERROR: multiple incompatible entry $fileKey in call-graph\n";
177                print REPORT_FILE "previous entry = '$dependencyList{$fileKey}'\n";
178                print REPORT_FILE "new entry = $dependentFileList\n";
179                }
180        } # let's make sure
181       
182        $dependencyList{$fileKey}=$dependentFileList; # comma-separated list of files that depend on key
183        if ($dependencyList{$fileKey} ne "") {
184                print REPORT_FILE " -> calls $dependencyList{$fileKey}\n";
185        } else {
186                print REPORT_FILE " -> calls no other file\n";
187        }           
188        }
189        chdir("$samplesRootDir/$targetDir/$dir");
190}
191chdir($localRootDir); # back to local root dir
192
193}
194
195@makefiles = ('Makefile_develop','Makefile_nag','Makefile'); # Makefile must be last
196# because we need to have collected the results of the two previous makefiles in order
197# to prepare the final web-page, which is only created for Makefile ...
198
199# hierarchy to accomodate the local copy of the tests
200`rm -rf $localRootDir/TESTING`; # cleanup
201mkdir("$localRootDir/TESTING", 0777);
202
203foreach $makefile (@makefiles) { # repeat for Makefile_develop, Makefile_nag, Makefile
204
205# back to the initial directory
206chdir $localRootDir;
207
208my $regressionTest;
209if ($makefile eq "Makefile") {
210        $regressionTest = 1;
211} else {
212        $regressionTest = 0;
213}
214
215
216$localTestDir = "$localRootDir/TESTING/$makefile"; # separate work dirs for the 3 makefiles...
217mkdir($localTestDir, 0777);
218
219# following executables have been prepared by MadBuid.pl
220$madxLink = $madDir . "/madx_$makefile";
221$madxpLink = $madDir . "/madxp_$makefile";
222print REPORT_FILE "madxLink is $madxLink\n";
223print REPORT_FILE "madxpLink is $madxpLink\n";
224
225
226
227@targets = `xsltproc --stringparam what list_targets ProcessScenario.xsl TestScenario.xml`; # all target functionalities
228
229TARGET: foreach $target (@targets) {
230chop $target;
231
232$outcome{$target} = "success"; # by default, nobody will receive an e-mail about this target
233
234if ($debugMode ==1){
235        if ($target ne $debugTarget) {
236                next TARGET;
237        }
238}
239
240print REPORT_FILE "--- testing $target\n";
241
242        if ($regressionTest) {
243        $testReport .= "<table width=\"75%\" border=\"0\">\n";
244        $testReport .= "<tr class='test_target'><td colspan=\"2\"><div align=\"center\"><strong>$target</strong></div></td></tr>\n";
245        }
246
247chdir($localRootDir); # top of the hierarchy
248
249$targetDir = "$localTestDir/$target";
250mkdir($targetDir, 0777) or die "fail to create directory $targetDir\n";
251
252@tests = `xsltproc --stringparam what list_tests --stringparam target $target ProcessScenario.xsl TestScenario.xml`;
253
254
255chdir("$localTestDir/$target") or die "fail to chdir to $localTestDir/$target\n"; # after processing stylessheets
256
257# populate the local test directory with the input file as well as with all the files it depends from
258
259$autonumber = 0;
260foreach $test (@tests) {
261
262        $autonumber++;
263        chop $test;
264        $command = $test;
265        print REPORT_FILE "command='$command'\n";       
266       
267        # retreive the subdirectory relocation if any (specific subdirs are specified in the XML)
268        $sourceSubDir = ""; # by default
269        $_ = $command;
270        if(/subdirectory=([\w_\-\.\d]+)/){
271        $sourceSubDir = $1;
272        }
273
274        # retrieve the 'input file' name with a regular expression
275        $_ = $command;
276        /<[\s\t]+([\w\.\-_\d]+)[\s\t]+>/;
277        $infilename = $1;
278        print REPORT_FILE "the input file name is: $infilename\n";
279       
280        if ($sourceSubDir eq "" ) {
281        $testCaseDir = "test_" . $autonumber;
282        } else {
283        $testCaseDir = "test_" . $autonumber . "_" . $sourceSubDir; 
284        # keep the same name for the local test dir under 'target' as in the reference
285        # and the files will need to be copied from location with the $testSubDir prefix later-on...
286        }
287
288        # before executing the command, make sure we remove
289        # the optional subdirectory information which shows up after the comma
290        # in case the source test directory contains a subdirectory structure...
291        my $executableCommand;
292        if ($sourceSubDir eq "") {
293        $executableCommand = $command;
294        } else {
295        $_ = $command;
296        s/,[\s\t]*[\w\d.\-_=]+//g;
297        $executableCommand = $_;
298        }
299
300        if ($regressionTest) {
301                my $key = $target . "_" . $testCaseDir;
302                $testReport .= "<tr class='test_case'><td width=\"80%\">$testCaseDir: $executableCommand</td><td width=\"20%\"><table width=\"100%\" style=\"text-align: center\"><tr>$dev{$key} $nag{$key}</tr></table></td></tr>\n"; 
303                # above sets column width for the whole table
304        }
305
306
307        mkdir("$localTestDir/$target/$testCaseDir",0777) or die "fail to create directory $testCaseDir\n";
308        chdir("$localTestDir/$target/$testCaseDir") or die "fail to chdir to $localTestDir/$target/$testCaseDir\n";
309
310        # copy the input file that corresponds to this specific test case
311        if ($sourceSubDir eq "") {
312                `cp $samplesRootDir/$target/$infilename .`;
313        } else {
314                `cp $samplesRootDir/$target/$sourceSubDir/$infilename .`;
315        }
316       
317        $key = "$target/$infilename";
318
319        # now copy additional input files for the test, according to the dependency information retreived above
320        @inputs = split /,/, $dependencyList{"$target/$infilename"}; # prefixed with $target to avoid name clashes
321
322        # now grow the @input list by expanding the dependency and by adding the root node
323
324        # partial treatment: only look for files calling files under the same directory
325        my $reccursionLevels =2;
326
327        for ($i=0;$i<$reccursionLevels;$i++){
328        foreach $input (@inputs){
329                if ($dependencyList{"$target/$input"} ne "") 
330                {
331                my @secondLevelInputs = split /,/, $dependencyList{"$target/$input"};
332                # or third etc... level according to reccursion level...
333                foreach $secondLevelInput (@secondLevelInputs){
334                        if (/..\/([\w\d\-_\.\/]+)/) { 
335                        # file located in a directory with path starting above
336                        # currently handled differently by code appearing downthere
337                        # => do nothing for time-being
338                        # (incomplete: should also handle any tree structure)
339                        } else {
340                        print REPORT_FILE "Found $secondLevelInput called by $testCaseDir/$input and to be copied locally\n";
341                        # actually, should only add to the list if not already present
342                        my $existsInput = 0;
343                        INPUT_LOOP: foreach $existingInput (@inputs) {
344                                if ($secondLevelInput eq $existingInput) {
345                                $existsInput = 1;
346                                next INPUT_LOOP; 
347                                }
348                        }
349                        if ($existsInput ==0) {
350                                @inputs = (@inputs, $secondLevelInput);
351                        }
352                        } 
353                }
354                }
355        } # grow list of inputs at one level
356        }  # end growing the list of inputs that can be moved to the same input directory
357
358        @inputs = ($infilename, @inputs); # add the root inputfile
359
360
361        my @inputSubdirectories = (); # list of input subdirectories under the workdir in which MAD is invoked
362        # these subdirectories will later be moved under "inputs" instead of "outputs". In most cases this
363        # list is empty, but not for targets 'error' and 'twiss' for instance.
364
365
366        # copyping inputs and dependent files locally
367        foreach $input (@inputs) {
368        print REPORT_FILE "Input is $input\n";
369        $_ = $input;
370        # SPECIFIC CASE: files that must be stored in a locally replicated hierarchy
371        # considering the MAD call instructions mention a relative path...
372        # note later-on should also accomodate for situations were the included files
373        # are below, down the hierarchy... At this stage should re-implement path handling
374        if (/\.\.\/([\w\d\-_\.\/]+)/) { # ../dir/file or ../file formats
375                my $term = $1;
376                if (/(\.\.\/[\w\d\-_]+)\/([\w\d-_\.]+)/) { # ../dir/file format only
377                # file to be called is located up the hierarchy
378                # in which case we need to reflect the directory tree structure
379                # by creating directories if necessary
380                $dependencyDir = $1;
381                $dependencyFile = $2;
382                } else {
383                $dependencyDir = '..';
384                $dependencyFile = $term;
385                }
386                # print REPORT_FILE "Found dependency file '$dependencyFile' under '$dependencyDir'\n";         
387                $existsDir = `ls -d $dependencyDir | wc -l`;
388                # print REPORT_FILE "existsDir now equals $existsDir\n";
389                if ($existsDir == 1) {
390                print REPORT_FILE "dependency directory '$dependencyDir' already exists\n";
391                # simply copy the file
392                if  ($sourceSubDir eq "") {     
393                        `cp $samplesRootDir/$target/$dependencyDir/$dependencyFile ./$dependencyDir`;
394                } else {
395                        `cp $samplesRootDir/$target/$sourceSubDir/$dependencyDir/$dependencyFile ./$dependencyDir`; # should merge the two with '.' for $sourceSubDir
396                }
397
398                } else {
399#                   print REPORT_FILE "dependency directory '$dependencyDir' will be created\n";
400                # first create the directory, then copy the file
401                mkdir($dependencyDir,0777);
402                if ($sourceSubDir eq "") {
403                        `cp $samplesRootDir/$target/$dependencyDir/$dependencyFile ./$dependencyDir`;
404                } else {
405                        `cp $samplesRootDir/$target/$sourceSubDir/$dependencyDir/$dependencyFile ./$dependencyDir`; # should merge the two with '.' for $sourceSubDir
406
407                }
408                }
409
410
411                @secondLevelInputs = split /,/, $dependencyList{"$target/$dependencyFile"}; 
412                # prefixed with $target to avoid name clashes (may be too coarse!)
413                foreach $secondLevelInput (@secondLevelInputs) {
414                print REPORT_FILE "Second-level copy of $secondLevelInput\n";
415                $_ = $secondLevelInput;
416                if (/\.\.\/([\w\d\-_\.\/]+)/) { # ../dir/file or ../file formats
417                        my $term;
418                        if (/(..\/[\w\d\-_]+)\/([\w\d-_\.]+)/) { # ../dir/file format only
419                        $secondDependencyDir = $1;
420                        $secondDependencyFile = $2;
421                        } else {
422                        $secondDependencyDir = '..';
423                        $secondDependencyFile = my $term;
424                        }
425
426                        $existsSecondDir = `ls -d $dependencyDir/$secondDependencyDir | wc -l`;
427                        if ($existsSecondDir) {
428                        print REPORT_FILE "dependency second directory '$dependencyDir/$secondDependencyDir' already exists\n";
429                        # simply copy the file
430                        if  ($sourceSubDir eq "") {
431                                `cp $samplesRootDir/$target/$dependencyDir/$secondDependencyDir/$secondDependencyFile ./$dependencyDir/$secondDependencyDir`;
432                        } else {
433                                # current focus
434                                `cp $samplesRootDir/$target/$sourceSubDir/$dependencyDir/$secondDependencyDir/$secondDependencyFile ./$dependencyDir/$secondDependencyDir`; # should merge the two with '.' for $sourceSubDir
435                                print REPORT_FILE "now copying second-level $samplesRootDir/$target/$sourceSubDir/$dependencyDir/$secondDependencyDir/$secondDependencyFile into ./$dependencyDir/$secondDependencyDir\n";
436                        }
437                        } else {
438                        print REPORT_FILE "Not ready yet to handle creation of secondary dir/n";
439                        $testReport .= "ERROR: ($makefile) Not ready yet to handle creation of second-level dir\n";
440                        }
441                } else {
442                        # the second-level related file is located under the same directory
443                        if ($sourceSubDir eq "") {
444                        `cp $samplesRootDir/$target/$dependencyDir/secondLevelInput ./$dependencyDir`;
445                        } else {
446                        `cp $samplesRootDir/$target/$sourceSubDir/$dependencyDir/$secondLevelInput ./$dependencyDir`;
447                        }                   }
448
449                } # second level
450       
451        } 
452        else {
453
454                # --- below to handle the specific case of twiss lhc.madx -> temp contents seem to be cleaned-up from .mad files...
455                if ($input =~ /([\w\-_\d\.]+)\/([\w\d\-_\.]+)/) {
456
457                # specific case of a file being called in a subdir of current directory
458                my $calledFileSubDir = $1;
459                my $calledFile = $2;
460                # $calledFileSubDir = 'temp'; # FORCE FOR DBG
461                # with the above, for lhc.out of twiss target, we indeed
462                # find the .mad files under 'TEMP', but if we keep the name they disappear
463                # check if the subdir already exists - if not create it
464                my $existsDir = `ls -d $calledFileSubDir | wc -l`;
465
466                my $pwd = `pwd`; chop $pwd;
467                if ($existsDir==1) {
468                } else {
469                        # DBG: where we end-up for specific case of MB.12.mad
470                        mkdir($calledFileSubDir,0777);
471                        # add this dir to the list of input subdirectories that should be transferred from the workdir
472                        # in which the MAD command is executed into the "inputs" directory (otherwise the directory
473                        # would later go under "outputs" and undergo the side-by-side comparison...)
474                        @inputSubdirectories = ( @inputSubdirectories, $calledFileSubDir );
475
476                }
477                # and now do the copy
478                # DBG: we end-up copying MB.12.mad into ./temp
479                # print REPORT_FILE "DIRECTORY: now copying $samplesRootDir/$target/$input into ./$calledFileSubDir\n";
480                if ($sourceSubDir eq ""){
481                        `cp $samplesRootDir/$target/$input ./$calledFileSubDir`;
482                } else {
483                        `cp $samplesRootDir/$target/$sourceSubDir/$input ./$calledFileSubDir`;
484                }
485               
486
487                #    @what = `ls ./$calledFileSubDir`;
488                #   $howMany = scalar(@what);
489                #    print REPORT_FILE "DIRECTORY $howMany contents of $pwd/$calledFileSubDir =\n";
490                #    foreach $line (@what ) { print REPORT_FILE "$line\n"; }
491                # --- above to handle the specific case of twiss lhc.madx
492
493
494                } else {
495                # file to be called in the same directory as the input file
496                # print REPORT_FILE "for target '$target' and test input '$infilename', now copying additional '$input'\n";
497                if ($sourceSubDir eq "") {
498                        `cp $samplesRootDir/$target/$input .`;
499                } else {
500                        `cp $samplesRootDir/$target/$sourceSubDir/$input .`;
501                }
502                } # file to be called located in the same directory as the command's input file
503        }
504
505        }
506
507
508
509        # check whether we should call madx or madxp
510        my $madLink;
511        $_ = $command;
512        /.\/(madxp?)[\s\t]*/;
513        if ($1 eq "madxp") { 
514                $madLink = $madxpLink; 
515                $madProgram = "madxp"; 
516        } else {
517                if ($1 eq "madx") { 
518                        $madLink = $madxLink; 
519                        $madProgram = "madx"; 
520                } else {
521                        $madLink = "."; 
522                        $madProgram = "linkUnknown";
523                }
524        }
525
526        `ln -s $madLink $madProgram`;
527
528        # DBG: for twiss - test 5, MAD.12.mad etc in temp are replaced by MAD.12 etc...
529        # hence temp is removed and rewritten whereas this does not seem to be the case
530        # in the reference directory ... rights?
531       
532        if ($regressionTest ==0) { 
533                # For Makefile_develop and Makefile_nag, we want to see stderr
534                # => also redirect the standard error
535                # by replacing: 'madx(p) < file.madx > file.out'
536                # with:         '(madx(p) <file.madx > file.out) >& stderr_redirected'
537                my $redirectedExecutableCommand = "($executableCommand) >& $stderrFile";
538                $executableCommand = $redirectedExecutableCommand;
539        }
540       
541        $testCaseStartTime = localtime;
542        # run the test
543        `$executableCommand`; 
544        $testCaseEndTime = localtime;
545
546        # retrieve the 'output file' name with a regular expression
547        $_ = $command;
548        /[\s\t]([\w._\d]*).out/;
549        $outfilename = $1 . ".out";
550
551
552        # list all by-product output files
553        @allFilesNow = `ls`; # list of all input + output files after invoking 'mad' command
554       
555        # remove the madx link from the list of files to be moved
556
557        # grow the list of input files with the list of subdirectory so that they move together under 'inputs'
558        foreach $dir (@inputSubdirectories){
559        push (@inputs, $dir);
560        }
561
562        @outputs = ();
563        foreach $file (@allFilesNow){
564        chop $file;
565        $isInput = 0;
566        foreach $input (@inputs){
567                if ($file eq $input) {
568                $isInput =1;
569                }
570        }
571        if (($isInput == 0) && ($file ne "madx") && ($file ne "madxp")) {       
572                # ignore the madx/madxp entries which should stay on top
573                push (@outputs, $file);
574        }
575        } ;
576
577        #DBG
578        my $dbg =1 ;
579        if ($dbg==1){
580        print REPORT_FILE "--- for $testCaseDir ---\n";
581        print REPORT_FILE "list of input files: @inputs\n";
582        print REPORT_FILE "list of output files: @outputs\n";
583        print REPORT_FILE "------------------------\n";
584        }
585
586        # now move inputs and outputs into dedicated subdirectory
587        $inputSubdir = "$localTestDir/$target/$testCaseDir/input";
588        $outputSubdir = "$localTestDir/$target/$testCaseDir/output";
589        mkdir($inputSubdir, 0777) or die "fail to create directory $inputSubdir\n";
590        mkdir($outputSubdir, 0777) or die "fail to create directory $outputSubdir\n";   
591
592        foreach $file (@inputs) { 
593        # SPECIFIC CASE: files that must be stored in the locally stored hierarchy
594        # with MAD call instructions referring to a relative path...
595        $_ = $file;
596        if (/..\//) { next; #skip. Later on should also deal with the case of directories under the test dir...
597                } else {
598                        `mv $file $inputSubdir/`;                         
599                }
600        }
601        foreach $file (@outputs) {`mv $file $outputSubdir/`; }
602
603
604        chdir($outputSubdir) or die "fail to chdir to $outputSubdir\n";
605
606        if ($regressionTest) { # i.e. makefile == Makefile_develop
607                # now compare desired output and actual output
608
609                # let's try to do a blind diff without trying to cure any 'standard' discrepancy
610                $diffResFilename = "DIFFERENCES.txt";
611                open (OUT,">$diffResFilename");
612                foreach $file (@outputs) {
613
614                # specific case: 'temp' entry refers to a temporary file name
615                # (if other files, should be omitted in the same way...)
616                if ($file eq "temp") { next; }
617
618                # specific case: skip Postcript '.ps' and '.eps' files
619                # (eventually Poscript files should be removed from the examples' reference CVS repo)
620                if ($file =~ /\.ps$/) { next; }
621                if ($file =~ /\.eps$/) { next; }
622
623                # check there is always two files to be compared
624                if ($sourceSubDir  eq "") {
625                        $fileCount = `ls $samplesRootDir/$target/$file | wc -l`;
626                        chop $fileCount;
627                } else {
628                        $fileCount =  `ls $samplesRootDir/$target/$sourceSubDir/$file | wc -l`;
629                        chop $fileCount;
630                }
631                if ($fileCount == 0) {
632                        print OUT "# FAIL TO COMPARE $file: no such file for reference => FAILURE\n";
633                        $testReport .="<tr class='omit'><td width=\"70%\">$file</td><td width=\"30%\">no file for reference</td></tr>\n";
634                } else {
635
636                        my $detailsLink;
637                        my $detailsHtmlFile;
638
639                        # specific case when the HTML file name is of the form XX.map or XX.map.htm
640                        # webserver will fail to display the HTML although one can open it form the webfolder...
641                        # to overcome this limitation, we need to juggle with the HTML file name
642                        $_ = $file;
643                        s/\.map$/\.maAap/g;
644                        $f = $_;
645               
646
647                        # handle both cases where there is a $sourceSubDir or not...
648                        $detailsLink = "./details/DiffResult_"."$target"."_"."$testCaseDir"."_"."$f.htm"; # weblink
649                        $detailsHtmlFile = "$htmlRootDir/details/DiffResult_"."$target"."_"."$testCaseDir"."_"."$f.htm"; # deliver             
650               
651                        if ($sourceSubDir eq "") {
652                        $madDiffRes = 
653                                `$localRootDir/MadDiff.pl ./$file $samplesRootDir/$target/$file $detailsHtmlFile`;
654                        } else {
655                        $madDiffRes =
656                                `$localRootDir/MadDiff.pl ./$file $samplesRootDir/$target/$sourceSubDir/$file $detailsHtmlFile`;
657                        }
658
659               
660                        $testReport .= "<tr class='$madDiffRes'><td width=\"70%\">$file</td><td width=\"30%\"><a href=\"$detailsLink\">$madDiffRes</a></td></tr>\n";
661                        print OUT "#COMPARING $file yields $madDiffRes\n";
662                       
663                        # summarize the information in $outcome{$target}
664                        if ($madDiffRes eq 'failure'){
665                                $outcome{$target}='failure';
666                        } else {
667                                if ($madDiffRes eq 'warning'){
668                                        if ($outcome{$target} eq 'success'){
669                                                $outcome{$target}='warning';
670                                        }
671                                        # otherwise, $outcome{$target} shall keep its value
672                                        # whether it is 'success' or 'failure'
673                                }
674                        }
675
676                }
677                }
678                close(OUT);     
679        } else {
680                # what we do to process the outcome of tests
681                # compiled with Makefile_develop and Makefile_nag
682               
683                # info can be either (1) per-file : does it exist or not
684                # or (2) per test-case i.e. [a] do we reach completion in the main output file
685                # and if not, and [b] what is the stderr if any.
686       
687                # let's go for (2), i.e. per $testCaseDir
688               
689                # (1) try to open the output file, according to it show the
690                # cell as green / orange / red for completed / incomplete / absent
691                my $existsOutput = 0;
692                foreach $file (@outputs){
693                        if ($file eq $outfilename) {
694                                $existsOutput = 1;
695                        }
696                }
697               
698                my $finishedNormally = 0;
699                if ($existsOutput) {
700                        # now check whether the output completed normally
701                        open OUTFILE, "<$outputSubdir/$outfilename"; # output just moved
702                        while (<OUTFILE>){
703                                if (/\+[\s\t]+MAD\-X[\s\t]+([\d\.]+)[\s\t]+finished normally[\s\t]+\+/){
704                                        $finishedNormally = 1;
705                                }
706                        }
707                        close OUTFILE; 
708                }
709               
710                my $existsStderr = 0;
711                @stderrFiles = `ls $outputSubdir/$stderrFile`;
712                if (scalar(@stderrFiles) >0) {
713                        # check if not empty
714                        my $linesCount = `wc -l $stderrFile`;
715                        if ($linesCount >0) {
716                                $existsStderr=1;
717                        }
718                }
719               
720                my $outputStatus; # used by CSS to apply font-color on stderr web page
721               
722                if ($existsOutput ==0 ){
723                        $outputStatus = 'failure';
724                } else {
725                        if ($finishedNormally) {
726                                if ($existsStderr) {
727                                        $outputStatus = 'warning';
728                                } else {
729                                        $outputStatus = 'success'; # no link to stderr
730                                }
731                        } else {
732                                $outputStatus = 'failure';
733                        }
734                }
735               
736                # update $outcome{$target}
737                # summarize the information in $outcome{$target}
738                if ($outputStatus eq 'failure'){
739                        $outcome{$target}='failure';
740                } else {
741                        if ($outputStatus eq 'warning'){
742                                if ($outcome{$target} eq 'success'){
743                                        $outcome{$target}='warning';
744                                }
745                                # otherwise, $outcome{$target} shall keep its value
746                                # whether it is 'success' or 'failure'
747                        }
748                }               
749               
750               
751               
752                               
753                # (2) if there is an stderr file, then create an HTML file
754                # and draw a link from the main web page
755
756                # HTML files and links to make stderr viewable from the web
757                my $m;
758                if ($makefile eq "Makefile_develop") {
759                        $m="dev";
760                }
761                if ($makefile eq "Makefile_nag"){
762                        $m="nag";
763                }
764                       
765                # weblink:
766                my $errorLink = "<a href=\"./details/Error_".$m."_".$target."_".$testCaseDir.".htm"."\">$m</a>";
767                # deliver:
768                my $errorHtmlFile = "$htmlRootDir/details/Error_".$m."_".$target."_".$testCaseDir.".htm"; 
769                `touch $errorHtmlFile`; # for the time-being
770               
771               
772                errorWebPage("$outputSubdir/$stderrFile",
773                        $errorHtmlFile,
774                        $outputStatus,
775                        $testCaseStartTime,
776                        $testCaseEndTime);
777               
778                my $key = $target . "_" . $testCaseDir;
779                if ($makefile eq "Makefile_develop") {
780                        $dev{$key}="<td class=\"$outputStatus\">$errorLink</td>";
781                }
782                if ($makefile eq "Makefile_nag"){
783                        $nag{$key}="<td class=\"$outputStatus\">$errorLink</td>";
784                }
785
786
787                       
788        }
789} # tests
790
791        if ($regressionTest) {
792        $testReport .= "</table>\n"; # end of table per target
793        }
794} # targets
795} # for each Makefile_develop, Makefile_nag, Makefile ...
796
797$endTime = localtime;
798
799# we know that at this stage $makefile equals "Makefile" anyway
800# i.e. that we are finally performing regression testing
801
802# create web page
803my $html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">';
804$html .= "<html>\n";
805$html .= "<head>\n";
806$html .= "<title>MAD test result</title>\n";
807$html .= "<link rel=stylesheet href=\"./MadTestWebStyle.css\" type=\"text/css\">"; 
808# CSS stylesheet
809$html .= "</head>\n";
810$html .= "<!-- automatically generated by the MAD testing script -->\n";
811$html .= "<body>\n";
812$html .= "<p>Test started $startTime, ended $endTime</p>\n";
813$html .= "\n<p>To update example X: \n";
814$html .= "'cvs -d:gserver:isscvs.cern.ch/local/reps/madx-examples checkout madX-examples/REF/X' ";
815$html .= "then modify input files, re-run and commit outputs to the CVS.</p>\n";
816$html .= $testReport;
817$html .= "</body>\n";
818$html .= "</html>\n";
819open(OUTHTML, ">$htmlFile");
820print OUTHTML $html;
821close OUTHTML;
822
823# back to the initial directory
824chdir $localRootDir;
825
826# then send e-mails to the people responsible for the various tests' targets
827if (($debugMode ==0) && ($silentMode==0) ) { # for time being, do not notify anybody
828        foreach $target (@targets){
829                # do we need to notify anyone for this target?
830                if (($outcome{$target} eq 'failure')||($outcome{$target} eq 'warning')){
831                        # retreive the responsible person for each test target
832                        $responsible{$target} = `xsltproc --stringparam what responsible --stringparam target $target ProcessScenario.xsl TestScenario.xml`;   
833                        # retreive e-mail address of the responsible person
834                        my $emailRecipient = $responsible{$target};
835                        my $emailSubject = "MAD Unsucessful test for '$target'";
836                        my $emailContent .= "The test that started on $startTime and completed on $endTime resulted in a $outcome{$target}.\n";
837                        $emailContent .= "See detailed report on:\n";
838                        $emailContent .= "http://test-mad-automation.web.cern.ch/test-mad-automation\n";
839                        $emailContent .= "\nThis e-mail has been sent to you because you are registered as the responsible person for the '$target' package\n";
840                        my $msg = MIME::Lite->new(
841                                From       =>   'Jean-Luc.Nougaret@cern.ch',
842                                'Reply-To' =>   'mad-automation-admin@cern.ch',
843                                To         =>   $emailRecipient,
844                                Cc         =>   'mad-automation-admin@cern.ch',
845                                Subject    =>   $emailSubject,
846                                Data       =>   $emailContent
847                        );
848                        $msg->send;
849                        print REPORT_FILE "sent e-mail to $emailRecipient\n";
850                } else {
851                        # for this targets, all tests were sucessful => no need to notify
852                }
853        }
854}
855
856# for debug, inform me that the test prog ran till completion
857my $lastMsg = MIME::Lite->new(
858                              From         =>   'Jean-Luc.Nougaret@cern.ch',
859                              To           =>   'Jean-Luc.Nougaret@cern.ch',
860                              Subject      =>   'Last message from MadTestPy.pl',
861                              Data         =>   'MadTestPy.pl ran succesfully till completion (not killed)'
862                              );
863$lastMsg->send;
864
865
866print REPORT_FILE "script terminated\n";
867close REPORT_FILE;
868
869sub getListOfDependantFiles {
870my $parentFilename = $_[0];
871my $dependentFileList = "";
872open(IN,$parentFilename);
873
874LINE: while(<IN>){
875        # take into account MAD various ways of reading a file, namely using either "call,file" or "readmytable,file"
876        my $fileRetreival = 0 ;
877        my $childCount = 0;
878        my @childs;
879        # MAD syntax too permissive: hard to grep commands
880        # not left-anchored as can be an action after an 'if'
881        # but make sure it has not been commented (negated !) as is frequently the case...
882
883        if (/^[\s\t]*!/) { next LINE; } # this is a comment (!) - do not bother
884
885        if (/[\s\t]*[Rr][Ee][Aa][Dd][Mm][Yy][Tt][Aa][Bb][Ll][Ee],?[\s\t]*[Ff][Ii][Ll][Ee][\s\t]*=[\s\t]*[\"\']?([\w\._\-\d\/]+)[\"\']?[\s\t]*/){
886        @childs[$childCount++] = $1;
887        $fileRetreival = 1;
888
889        }
890
891        if (/[\s\t]*[Cc][Aa][Ll][Ll],?[\s\t]*[Ff][Ii][Ll][Ee][\s\t]*=[\s\t]*[\"\']?([\w\._\-\d\/]+)[\"\']?[\s\t]*;/) {
892        @childs[$childCount++] = $1;
893        $fileRetreival = 1;
894        }
895       
896        # another way to read a table
897        if (/[\s\t]*[Rr][Ee][Aa][Dd][Tt][Aa][Bb][Ll][Ee],?[\s\t]*[Ff][Ii][Ll][Ee][\s\t]*=[\s\t]*[\"\']?([\w\._\-\d\/]+)[\"\']?[\s\t]*;/){
898        @childs[$childCount++] = $1;
899        $fileRetreival = 1;         
900        }
901
902        # another - rare - instruction that calls a script available in the input directory
903        # along the other input files. Such script must be copied locally along the other
904        # files.
905        # this is for instance the case for the read.magnet.errors perl-script
906        # in twiss/test_5/ or foot
907        if (/[Ss][Yy][Ss][Tt][Ee][Mm][\s\t]*,?[\s\t]*[\"\']([\w\._\-\d]+)[\s\t]*<?[\s\t]*([\w\.\_\-\d\/]*)[\s\t]*>?(.*)[\"\']/){
908                my $cmd=$1;
909                my $arg=$2;
910               
911                if (($cmd =~/mkdir/)||($cmd =~/ls/)||($cmd =~ /cat/)||($cmd =~/rm/)||($cmd =~ /grep/) ||($cmd =~ /echo/) || ($cmd =~ /ln/) || ($cmd =~ /cp/)){
912                        # command invocation, not implying a file call
913               
914                } else {
915               
916                    # ... many other cases like 'mkdir' to be handled before we conclude
917                    # the command corresponds to a file...
918
919                    if (($cmd ne "perl") && ($cmd ne "gnuplot") && ($cmd ne "python")){
920                        @childs[$childCount++] = $cmd; # the command ...
921                    }
922                    if ($arg ne "") {
923                        @childs[$childCount++] = $arg; # as well as its argument if any
924                        # print "found command '$cmd', with input argument '$arg'\n";
925                    }
926
927                    $fileRetreival = 1;
928                }
929            }
930        # NOTE: the above is FRAGILE. In many cases, one might expect the System call
931        # to start with a command not corresponding to a local file in the input dir.
932       
933       
934        # another - rare -  instruction that calls a file from another
935        if (/[\s\t]*sxfread[\s\t]*,?[\s\t]*file[\s\t]*=[\s\t]*[\"\']?([\w\._\-\d\/]+)[\"\']?[\s\t]*;/) {
936        @childs[$childCount++] = $1;
937        $fileRetreival = 1;
938        }
939
940
941        if ($fileRetreival == 1) {
942        #    $child = $1;
943        # before adding this child, make sure it's not already part of the childs the parent depends from
944        foreach $child (@childs) {
945                if ($dependentFileList =~ /$child,/) {
946                        # print REPORT_FILE "'$child' already belonging to dependentFileList '$dependentFileList' => omit insertion\n";
947                } else {
948                        # print REPORT_FILE "add child '$child' to list '$dependentFileList'\n";
949                        $dependentFileList = $dependentFileList . $child . ",";
950                }
951        }
952        }
953}
954close(IN);
955$_ = $dependentFileList ; # output arg
956}
957
958sub errorWebPage {
959        my $errorFile = $_[0];
960        my $htmlFile = $_[1];
961        my $outputStatus = $_[2];
962        my $startTime = $_[3];
963        my $endTime = $_[4];
964        my $contents ="";
965       
966        $contents .= "<table width=\"75%\" border=\"0\">\n";
967        $contents .= "<p>Test started $startTime, ended $endTime.<p>\n";       
968        $contents .= "<tr class=$outputStatus><td width=\"80%\">Contents of stderr</td><td width=\"20%\">$outputStatus</td></tr>\n";
969
970        open(INERROR, "<$errorFile");
971        while (<INERROR>){
972                chop;
973                $contents .= "<tr><td colspan=\"2\">$_</td><tr>\n";
974        }
975        $contents .= "</table>\n";
976        close(INERROR);
977       
978        # create web page
979        my $html = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">';
980        $html .= "<html>\n";
981        $html .= "<head>\n";
982        $html .= "<title>MAD stderr file</title>\n";
983        $html .= "<link rel=stylesheet href=\"../MadTestWebStyle.css\" type=\"text/css\">"; 
984        # CSS stylesheet
985        $html .= "</head>\n";
986        $html .= "<!-- automatically generated by the MAD testing script -->\n";
987        $html .= "<body>\n";
988        $html .= $contents;
989        $html .= "</body>\n";
990        $html .= "</html>\n";
991        open(OUTHTML, ">$htmlFile");
992        print OUTHTML $html;
993        close OUTHTML;
994}
995
Note: See TracBrowser for help on using the repository browser.