@@ -308,8 +308,7 @@ def __call__(self, data):
308308 if time_match :
309309 pkg_name = time_match .group (1 )
310310 test_time = time_match .group (2 )
311- with open (join (_pkg_testdir ('fastr' , pkg_name ), 'test_time' ), 'w' ) as f :
312- f .write (test_time )
311+ get_pkg_test_status (self .test_info , pkg_name ).test_time = test_time
313312
314313
315314class TestFileStatus :
@@ -318,7 +317,8 @@ class TestFileStatus:
318317 The latter means that the file had a .fail extension.
319318 '''
320319
321- def __init__ (self , status , abspath ):
320+ def __init__ (self , test_status , status , abspath ):
321+ self .test_status = test_status
322322 self .status = status
323323 self .abspath = abspath
324324 if status == "OK" :
@@ -331,6 +331,17 @@ def __init__(self, status, abspath):
331331 else :
332332 raise ValueError ('Invalid test file status: %s (allowed: "OK", "FAILED")' % status )
333333
334+ def set_report (self , ok , skipped , failed ):
335+ self .report = ok , skipped , failed
336+
337+ def get_report (self ):
338+ if self .test_status .is_status_indeterminate ():
339+ ok , skipped , failed = self .report
340+ return ok , 0 , skipped + failed
341+ else :
342+ return self .report
343+
344+
334345
335346class TestStatus :
336347 '''Records the test status of a package. status ends up as either "OK" or "FAILED",
@@ -342,17 +353,57 @@ class TestStatus:
342353 def __init__ (self ):
343354 self .status = "UNKNOWN"
344355 self .testfile_outputs = dict ()
356+ self .test_time = 0.0
357+
358+ def set_status_indeterminate (self ):
359+ self .status = "INDETERMINATE"
360+ self .test_time = - 1.0
361+
362+ def is_status_indeterminate (self ):
363+ if self .status == "INDETERMINATE" :
364+ assert self .test_time == - 1.0
365+ return True
366+ return False
367+
368+ def set_status_code (self , new_status ):
369+ if self .status == "INDETERMINATE" :
370+ assert self .test_time < 0.0
371+ elif self .status == "FAILED" and new_status == "INDETERMINATE" :
372+ self .set_status_indeterminate ()
373+ else :
374+ assert self .status == "OK" or self .status == "FAILED" or self .status == "UNKNOWN"
375+ assert new_status in ["OK" , "FAILED" , "INDETERMINATE" ]
376+ if new_status == "INDETERMINATE" :
377+ self .set_status_indeterminate ()
378+ else :
379+ self .status = new_status
380+
381+ def __str__ (self ):
382+ return "Test Status:\n %s (time: %s s)" % (self .status , self .test_time )
345383
346384
347385def _pkg_testdir (rvm , pkg_name ):
348386 return join (get_fastr_repo_dir (), 'test.' + rvm , pkg_name )
349387
350388
389+ def get_pkg_test_status (test_info , pkg_name ):
390+ '''
391+ Get the test status (class TestStatus) for a given package.
392+ It is created on demand if does not exist yet.
393+ '''
394+ test_status = test_info .get (pkg_name )
395+ if not test_status :
396+ test_status = TestStatus ()
397+ test_info [pkg_name ] = test_status
398+ return test_status
399+
400+
351401def _get_test_outputs (rvm , pkg_name , test_info ):
352402 pkg_testdir = _pkg_testdir (rvm , pkg_name )
403+ test_status = None
353404 for root , _ , files in os .walk (pkg_testdir ):
354- if not test_info . has_key ( pkg_name ) :
355- test_info [ pkg_name ] = TestStatus ( )
405+ if not test_status :
406+ test_status = get_pkg_test_status ( test_info , pkg_name )
356407 for f in files :
357408 ext = os .path .splitext (f )[1 ]
358409 # suppress .pdf's for now (we can't compare them)
@@ -370,7 +421,7 @@ def _get_test_outputs(rvm, pkg_name, test_info):
370421
371422 absfile = join (root , f )
372423 relfile = relpath (absfile , pkg_testdir )
373- test_info [ pkg_name ] .testfile_outputs [relfile ] = TestFileStatus (status , absfile )
424+ test_status .testfile_outputs [relfile ] = TestFileStatus (test_status , status , absfile )
374425
375426
376427def _args_to_forward_to_gnur (args ):
@@ -451,24 +502,27 @@ def _failed_outputs(outputs):
451502 # In addition to the similar comment for GNU R, this can happen
452503 # if, say, the JVM crashes (possible with native code packages)
453504 logging .info ("{0}: FastR test had .fail outputs" .format (pkg ))
454- fastr_test_status .status = "FAILED"
505+ fastr_test_status .set_status_code ( "FAILED" )
455506
456507 # Now for each successful GNU R output we compare content (assuming FastR didn't fail)
457508 for gnur_test_output_relpath , gnur_testfile_status in gnur_outputs .iteritems ():
458509 # Can't compare if either GNUR or FastR failed
459510 if gnur_testfile_status .status == "FAILED" :
460- fastr_test_status .status = "INDETERMINATE"
461- break
511+ fastr_test_status .set_status_code ( "INDETERMINATE" )
512+ continue
462513
463514 if not gnur_test_output_relpath in fastr_outputs :
464515 # FastR crashed on this test
465- fastr_test_status .status = "FAILED"
516+ fastr_test_status .set_status_code ( "FAILED" )
466517 logging .info ("{0}: FastR is missing output file: {1}" .format (pkg , gnur_test_output_relpath ))
467- break
518+ continue
468519
469520 fastr_testfile_status = fastr_outputs [gnur_test_output_relpath ]
470521 if fastr_testfile_status .status == "FAILED" :
471- break
522+ # Don't do fuzzy-compare.
523+ # It may only be fuzzy-compare because if we would have a test framework, the status would not be
524+ # "FAILED" since a test framework cannot produce ".fail" output files.
525+ continue
472526
473527 gnur_content = None
474528 with open (gnur_testfile_status .abspath ) as f :
@@ -499,18 +553,18 @@ def _failed_outputs(outputs):
499553
500554 if fastr_invalid_numbers or total_fastr > total_gnur :
501555 # If FastR's numbers are invalid or GnuR ran fewer tests than FastR, we cannot trust the FastR numbers
502- fastr_testfile_status .report = 0 , gnur_skipped , gnur_ok + gnur_failed
503- fastr_test_status .status = "FAILED"
556+ fastr_testfile_status .set_report ( 0 , gnur_skipped , gnur_ok + gnur_failed )
557+ fastr_test_status .set_status_code ( "FAILED" )
504558 fastr_testfile_status .status = "FAILED"
505559 elif total_fastr < total_gnur :
506560 # If FastR ran fewer tests than GnuR, we complement the missing ones as failing
507- fastr_testfile_status .report = ok , skipped , failed + (total_gnur - total_fastr )
508- fastr_test_status .status = "FAILED"
561+ fastr_testfile_status .set_report ( ok , skipped , failed + (total_gnur - total_fastr ) )
562+ fastr_test_status .set_status_code ( "FAILED" )
509563 fastr_testfile_status .status = "FAILED"
510564 else :
511565 # The total numbers are equal, so we are fine.
512566 fastr_testfile_status .status = "OK"
513- fastr_testfile_status .report = ok , skipped , failed
567+ fastr_testfile_status .set_report ( ok , skipped , failed )
514568 else :
515569 result , n_tests_passed , n_tests_failed = fuzzy_compare (gnur_content , fastr_content ,
516570 gnur_testfile_status .abspath ,
@@ -519,23 +573,21 @@ def _failed_outputs(outputs):
519573 dump_preprocessed = get_opts ().dump_preprocessed )
520574 if result == - 1 :
521575 logging .info ("{0}: content malformed: {1}" .format (pkg , gnur_test_output_relpath ))
522- fastr_test_status .status = "INDETERMINATE"
576+ fastr_test_status .set_status_code ( "INDETERMINATE" )
523577 # we don't know how many tests are in there, so consider the whole file to be one big skipped test
524- fastr_testfile_status .report = 0 , 1 , 0
525- # break
578+ fastr_testfile_status .set_report (0 , 1 , 0 )
526579 elif result != 0 :
527- fastr_test_status .status = "FAILED"
580+ fastr_test_status .set_status_code ( "FAILED" )
528581 fastr_testfile_status .status = "FAILED"
529- fastr_testfile_status .report = n_tests_passed , 0 , n_tests_failed
582+ fastr_testfile_status .set_report ( n_tests_passed , 0 , n_tests_failed )
530583 logging .info ("{0}: FastR output mismatch: {1}" .format (pkg , gnur_test_output_relpath ))
531- # break
532584 else :
533585 fastr_testfile_status .status = "OK"
534- fastr_testfile_status .report = n_tests_passed , 0 , n_tests_failed
586+ fastr_testfile_status .set_report ( n_tests_passed , 0 , n_tests_failed )
535587
536588 # we started out as UNKNOWN
537589 if not (fastr_test_status .status == "INDETERMINATE" or fastr_test_status .status == "FAILED" ):
538- fastr_test_status .status = "OK"
590+ fastr_test_status .set_status_code ( "OK" )
539591
540592 # write out a file with the test status for each output (that exists)
541593 with open (join (_pkg_testdir ('fastr' , pkg ), 'testfile_status' ), 'w' ) as f :
@@ -546,21 +598,25 @@ def _failed_outputs(outputs):
546598 test_output_file = join (_pkg_testdir ('fastr' , pkg ), relpath )
547599
548600 if os .path .exists (test_output_file ):
549- ok , skipped , failed = fastr_testfile_status .report
601+ ok , skipped , failed = fastr_testfile_status .get_report ()
550602 f .write ("{0} {1} {2} {3}\n " .format (relpath , ok , skipped , failed ))
551603 elif fastr_testfile_status .status == "FAILED" :
552604 # In case of status == "FAILED", also try suffix ".fail" because we just do not know if the test
553605 # failed and finished or just never finished.
554606 relpath_fail = fastr_relpath + ".fail"
555607 test_output_file_fail = join (_pkg_testdir ('fastr' , pkg ), relpath_fail )
556608 if os .path .exists (test_output_file_fail ):
557- ok , skipped , failed = fastr_testfile_status .report
609+ ok , skipped , failed = fastr_testfile_status .get_report ()
558610 f .write ("{0} {1} {2} {3}\n " .format (relpath_fail , ok , skipped , failed ))
559611 else :
560612 logging .info ("File {0} or {1} does not exist" .format (test_output_file , test_output_file_fail ))
561613 else :
562614 logging .info ("File {0} does not exist" .format (test_output_file ))
563615
616+
617+ with open (join (_pkg_testdir ('fastr' , pkg ), 'test_time' ), 'w' ) as f :
618+ f .write (str (fastr_test_status .test_time ))
619+
564620 logging .info ('END checking ' + pkg )
565621
566622
@@ -668,6 +724,64 @@ def installpkgs(args, **kwargs):
668724 return _installpkgs (rargs )
669725
670726
727+ def pkgtest_check (args ):
728+ '''
729+ This function allows to do only the checking part on an existing test output
730+ (i.e. 'test.fastr' and 'test.gnur' directories).
731+ It will try to re-create
732+ :param args:
733+ :return:
734+ '''
735+ parser = argparse .ArgumentParser (prog = "pkgtest" , description = 'FastR package testing.' )
736+ parser .add_argument ('--fastr-home' , metavar = 'FASTR_HOME' , dest = "fastr_home" , type = str , default = None ,
737+ required = True , help = 'The FastR standalone repo home directory (required).' )
738+ parser .add_argument ('-v' , '--verbose' , dest = "verbose" , action = "store_const" , const = 1 , default = 0 ,
739+ help = 'Do verbose logging.' )
740+ parser .add_argument ('-V' , '--very-verbose' , dest = "verbose" , action = "store_const" , const = 2 ,
741+ help = 'Do verbose logging.' )
742+ parser .add_argument ('--dump-preprocessed' , dest = "dump_preprocessed" , action = "store_true" ,
743+ help = 'Dump processed output files where replacement filters have been applied.' )
744+ parser .add_argument ('pkg_name' , metavar = "PKG_NAME" ,
745+ help = 'Package name for checking.' )
746+
747+ import util
748+ _opts = parser .parse_args (args = args , namespace = util .get_opts ())
749+
750+ log_format = '%(message)s'
751+ if _opts .verbose == 1 :
752+ log_level = logging .DEBUG
753+ elif _opts .verbose == 2 :
754+ log_level = VERY_VERBOSE
755+ else :
756+ log_level = logging .INFO
757+ logging .basicConfig (level = log_level , format = log_format )
758+
759+ # also log to console
760+ console_handler = logging .StreamHandler (stream = sys .stdout )
761+ console_handler .setLevel (log_level )
762+ console_handler .setFormatter (logging .Formatter (log_format ))
763+ logging .getLogger ("" ).addHandler (console_handler )
764+
765+ # if not :
766+ # print("Missing required argument 'pkg_name'")
767+ # return 1
768+
769+ pkg_name = _opts .pkg_name
770+ fastr_testdir = _pkg_testdir ("fastr" , pkg_name )
771+ if not os .path .isdir (fastr_testdir ):
772+ print ("test directory '%s' does not exist" % fastr_testdir )
773+ return 1
774+
775+ gnur_testdir = _pkg_testdir ("gnur" , pkg_name )
776+ if not os .path .isdir (gnur_testdir ):
777+ print ("test directory '%s' does not exist" % gnur_testdir )
778+ return 1
779+
780+ fastr_test_info = dict ()
781+ _get_test_outputs ("fastr" , pkg_name , fastr_test_info )
782+ return _set_test_status (fastr_test_info )
783+
784+
671785def pkgtest_cmp (args ):
672786 gnur_filename = args [0 ]
673787 fastr_filename = args [1 ]
0 commit comments