@@ -312,8 +312,7 @@ def __call__(self, data):
312312 if time_match :
313313 pkg_name = time_match .group (1 )
314314 test_time = time_match .group (2 )
315- with open (join (_pkg_testdir ('fastr' , pkg_name ), 'test_time' ), 'w' ) as f :
316- f .write (test_time )
315+ get_pkg_test_status (self .test_info , pkg_name ).test_time = test_time
317316
318317
319318class TestFileStatus :
@@ -322,7 +321,8 @@ class TestFileStatus:
322321 The latter means that the file had a .fail extension.
323322 '''
324323
325- def __init__ (self , status , abspath ):
324+ def __init__ (self , test_status , status , abspath ):
325+ self .test_status = test_status
326326 self .status = status
327327 self .abspath = abspath
328328 if status == "OK" :
@@ -335,6 +335,17 @@ def __init__(self, status, abspath):
335335 else :
336336 raise ValueError ('Invalid test file status: %s (allowed: "OK", "FAILED")' % status )
337337
338+ def set_report (self , ok , skipped , failed ):
339+ self .report = ok , skipped , failed
340+
341+ def get_report (self ):
342+ if self .test_status .is_status_indeterminate ():
343+ ok , skipped , failed = self .report
344+ return ok , 0 , skipped + failed
345+ else :
346+ return self .report
347+
348+
338349
339350class TestStatus :
340351 '''Records the test status of a package. status ends up as either "OK" or "FAILED",
@@ -346,17 +357,57 @@ class TestStatus:
346357 def __init__ (self ):
347358 self .status = "UNKNOWN"
348359 self .testfile_outputs = dict ()
360+ self .test_time = 0.0
361+
362+ def set_status_indeterminate (self ):
363+ self .status = "INDETERMINATE"
364+ self .test_time = - 1.0
365+
366+ def is_status_indeterminate (self ):
367+ if self .status == "INDETERMINATE" :
368+ assert self .test_time == - 1.0
369+ return True
370+ return False
371+
372+ def set_status_code (self , new_status ):
373+ if self .status == "INDETERMINATE" :
374+ assert self .test_time < 0.0
375+ elif self .status == "FAILED" and new_status == "INDETERMINATE" :
376+ self .set_status_indeterminate ()
377+ else :
378+ assert self .status == "OK" or self .status == "FAILED" or self .status == "UNKNOWN"
379+ assert new_status in ["OK" , "FAILED" , "INDETERMINATE" ]
380+ if new_status == "INDETERMINATE" :
381+ self .set_status_indeterminate ()
382+ else :
383+ self .status = new_status
384+
385+ def __str__ (self ):
386+ return "Test Status:\n %s (time: %s s)" % (self .status , self .test_time )
349387
350388
351389def _pkg_testdir (rvm , pkg_name ):
352390 return join (get_fastr_repo_dir (), 'test.' + rvm , pkg_name )
353391
354392
393+ def get_pkg_test_status (test_info , pkg_name ):
394+ '''
395+ Get the test status (class TestStatus) for a given package.
396+ It is created on demand if does not exist yet.
397+ '''
398+ test_status = test_info .get (pkg_name )
399+ if not test_status :
400+ test_status = TestStatus ()
401+ test_info [pkg_name ] = test_status
402+ return test_status
403+
404+
355405def _get_test_outputs (rvm , pkg_name , test_info ):
356406 pkg_testdir = _pkg_testdir (rvm , pkg_name )
407+ test_status = None
357408 for root , _ , files in os .walk (pkg_testdir ):
358- if not test_info . has_key ( pkg_name ) :
359- test_info [ pkg_name ] = TestStatus ( )
409+ if not test_status :
410+ test_status = get_pkg_test_status ( test_info , pkg_name )
360411 for f in files :
361412 ext = os .path .splitext (f )[1 ]
362413 # suppress .pdf's for now (we can't compare them)
@@ -374,7 +425,7 @@ def _get_test_outputs(rvm, pkg_name, test_info):
374425
375426 absfile = join (root , f )
376427 relfile = relpath (absfile , pkg_testdir )
377- test_info [ pkg_name ] .testfile_outputs [relfile ] = TestFileStatus (status , absfile )
428+ test_status .testfile_outputs [relfile ] = TestFileStatus (test_status , status , absfile )
378429
379430
380431def _args_to_forward_to_gnur (args ):
@@ -455,24 +506,27 @@ def _failed_outputs(outputs):
455506 # In addition to the similar comment for GNU R, this can happen
456507 # if, say, the JVM crashes (possible with native code packages)
457508 logging .info ("{0}: FastR test had .fail outputs" .format (pkg ))
458- fastr_test_status .status = "FAILED"
509+ fastr_test_status .set_status_code ( "FAILED" )
459510
460511 # Now for each successful GNU R output we compare content (assuming FastR didn't fail)
461512 for gnur_test_output_relpath , gnur_testfile_status in gnur_outputs .iteritems ():
462513 # Can't compare if either GNUR or FastR failed
463514 if gnur_testfile_status .status == "FAILED" :
464- fastr_test_status .status = "INDETERMINATE"
465- break
515+ fastr_test_status .set_status_code ( "INDETERMINATE" )
516+ continue
466517
467518 if not gnur_test_output_relpath in fastr_outputs :
468519 # FastR crashed on this test
469- fastr_test_status .status = "FAILED"
520+ fastr_test_status .set_status_code ( "FAILED" )
470521 logging .info ("{0}: FastR is missing output file: {1}" .format (pkg , gnur_test_output_relpath ))
471- break
522+ continue
472523
473524 fastr_testfile_status = fastr_outputs [gnur_test_output_relpath ]
474525 if fastr_testfile_status .status == "FAILED" :
475- break
526+ # Don't do fuzzy-compare.
527+ # It may only be fuzzy-compare because if we would have a test framework, the status would not be
528+ # "FAILED" since a test framework cannot produce ".fail" output files.
529+ continue
476530
477531 gnur_content = None
478532 with open (gnur_testfile_status .abspath ) as f :
@@ -503,18 +557,18 @@ def _failed_outputs(outputs):
503557
504558 if fastr_invalid_numbers or total_fastr > total_gnur :
505559 # If FastR's numbers are invalid or GnuR ran fewer tests than FastR, we cannot trust the FastR numbers
506- fastr_testfile_status .report = 0 , gnur_skipped , gnur_ok + gnur_failed
507- fastr_test_status .status = "FAILED"
560+ fastr_testfile_status .set_report ( 0 , gnur_skipped , gnur_ok + gnur_failed )
561+ fastr_test_status .set_status_code ( "FAILED" )
508562 fastr_testfile_status .status = "FAILED"
509563 elif total_fastr < total_gnur :
510564 # If FastR ran fewer tests than GnuR, we complement the missing ones as failing
511- fastr_testfile_status .report = ok , skipped , failed + (total_gnur - total_fastr )
512- fastr_test_status .status = "FAILED"
565+ fastr_testfile_status .set_report ( ok , skipped , failed + (total_gnur - total_fastr ) )
566+ fastr_test_status .set_status_code ( "FAILED" )
513567 fastr_testfile_status .status = "FAILED"
514568 else :
515569 # The total numbers are equal, so we are fine.
516570 fastr_testfile_status .status = "OK"
517- fastr_testfile_status .report = ok , skipped , failed
571+ fastr_testfile_status .set_report ( ok , skipped , failed )
518572 else :
519573 result , n_tests_passed , n_tests_failed = fuzzy_compare (gnur_content , fastr_content ,
520574 gnur_testfile_status .abspath ,
@@ -523,23 +577,21 @@ def _failed_outputs(outputs):
523577 dump_preprocessed = get_opts ().dump_preprocessed )
524578 if result == - 1 :
525579 logging .info ("{0}: content malformed: {1}" .format (pkg , gnur_test_output_relpath ))
526- fastr_test_status .status = "INDETERMINATE"
580+ fastr_test_status .set_status_code ( "INDETERMINATE" )
527581 # we don't know how many tests are in there, so consider the whole file to be one big skipped test
528- fastr_testfile_status .report = 0 , 1 , 0
529- # break
582+ fastr_testfile_status .set_report (0 , 1 , 0 )
530583 elif result != 0 :
531- fastr_test_status .status = "FAILED"
584+ fastr_test_status .set_status_code ( "FAILED" )
532585 fastr_testfile_status .status = "FAILED"
533- fastr_testfile_status .report = n_tests_passed , 0 , n_tests_failed
586+ fastr_testfile_status .set_report ( n_tests_passed , 0 , n_tests_failed )
534587 logging .info ("{0}: FastR output mismatch: {1}" .format (pkg , gnur_test_output_relpath ))
535- # break
536588 else :
537589 fastr_testfile_status .status = "OK"
538- fastr_testfile_status .report = n_tests_passed , 0 , n_tests_failed
590+ fastr_testfile_status .set_report ( n_tests_passed , 0 , n_tests_failed )
539591
540592 # we started out as UNKNOWN
541593 if not (fastr_test_status .status == "INDETERMINATE" or fastr_test_status .status == "FAILED" ):
542- fastr_test_status .status = "OK"
594+ fastr_test_status .set_status_code ( "OK" )
543595
544596 # write out a file with the test status for each output (that exists)
545597 with open (join (_pkg_testdir ('fastr' , pkg ), 'testfile_status' ), 'w' ) as f :
@@ -550,21 +602,25 @@ def _failed_outputs(outputs):
550602 test_output_file = join (_pkg_testdir ('fastr' , pkg ), relpath )
551603
552604 if os .path .exists (test_output_file ):
553- ok , skipped , failed = fastr_testfile_status .report
605+ ok , skipped , failed = fastr_testfile_status .get_report ()
554606 f .write ("{0} {1} {2} {3}\n " .format (relpath , ok , skipped , failed ))
555607 elif fastr_testfile_status .status == "FAILED" :
556608 # In case of status == "FAILED", also try suffix ".fail" because we just do not know if the test
557609 # failed and finished or just never finished.
558610 relpath_fail = fastr_relpath + ".fail"
559611 test_output_file_fail = join (_pkg_testdir ('fastr' , pkg ), relpath_fail )
560612 if os .path .exists (test_output_file_fail ):
561- ok , skipped , failed = fastr_testfile_status .report
613+ ok , skipped , failed = fastr_testfile_status .get_report ()
562614 f .write ("{0} {1} {2} {3}\n " .format (relpath_fail , ok , skipped , failed ))
563615 else :
564616 logging .info ("File {0} or {1} does not exist" .format (test_output_file , test_output_file_fail ))
565617 else :
566618 logging .info ("File {0} does not exist" .format (test_output_file ))
567619
620+
621+ with open (join (_pkg_testdir ('fastr' , pkg ), 'test_time' ), 'w' ) as f :
622+ f .write (str (fastr_test_status .test_time ))
623+
568624 logging .info ('END checking ' + pkg )
569625
570626
@@ -672,6 +728,64 @@ def installpkgs(args, **kwargs):
672728 return _installpkgs (rargs )
673729
674730
731+ def pkgtest_check (args ):
732+ '''
733+ This function allows to do only the checking part on an existing test output
734+ (i.e. 'test.fastr' and 'test.gnur' directories).
735+ It will try to re-create
736+ :param args:
737+ :return:
738+ '''
739+ parser = argparse .ArgumentParser (prog = "pkgtest" , description = 'FastR package testing.' )
740+ parser .add_argument ('--fastr-home' , metavar = 'FASTR_HOME' , dest = "fastr_home" , type = str , default = None ,
741+ required = True , help = 'The FastR standalone repo home directory (required).' )
742+ parser .add_argument ('-v' , '--verbose' , dest = "verbose" , action = "store_const" , const = 1 , default = 0 ,
743+ help = 'Do verbose logging.' )
744+ parser .add_argument ('-V' , '--very-verbose' , dest = "verbose" , action = "store_const" , const = 2 ,
745+ help = 'Do verbose logging.' )
746+ parser .add_argument ('--dump-preprocessed' , dest = "dump_preprocessed" , action = "store_true" ,
747+ help = 'Dump processed output files where replacement filters have been applied.' )
748+ parser .add_argument ('pkg_name' , metavar = "PKG_NAME" ,
749+ help = 'Package name for checking.' )
750+
751+ import util
752+ _opts = parser .parse_args (args = args , namespace = util .get_opts ())
753+
754+ log_format = '%(message)s'
755+ if _opts .verbose == 1 :
756+ log_level = logging .DEBUG
757+ elif _opts .verbose == 2 :
758+ log_level = VERY_VERBOSE
759+ else :
760+ log_level = logging .INFO
761+ logging .basicConfig (level = log_level , format = log_format )
762+
763+ # also log to console
764+ console_handler = logging .StreamHandler (stream = sys .stdout )
765+ console_handler .setLevel (log_level )
766+ console_handler .setFormatter (logging .Formatter (log_format ))
767+ logging .getLogger ("" ).addHandler (console_handler )
768+
769+ # if not :
770+ # print("Missing required argument 'pkg_name'")
771+ # return 1
772+
773+ pkg_name = _opts .pkg_name
774+ fastr_testdir = _pkg_testdir ("fastr" , pkg_name )
775+ if not os .path .isdir (fastr_testdir ):
776+ print ("test directory '%s' does not exist" % fastr_testdir )
777+ return 1
778+
779+ gnur_testdir = _pkg_testdir ("gnur" , pkg_name )
780+ if not os .path .isdir (gnur_testdir ):
781+ print ("test directory '%s' does not exist" % gnur_testdir )
782+ return 1
783+
784+ fastr_test_info = dict ()
785+ _get_test_outputs ("fastr" , pkg_name , fastr_test_info )
786+ return _set_test_status (fastr_test_info )
787+
788+
675789def pkgtest_cmp (args ):
676790 gnur_filename = args [0 ]
677791 fastr_filename = args [1 ]
0 commit comments