@@ -308,8 +308,7 @@ def __call__(self, data):
308
308
if time_match :
309
309
pkg_name = time_match .group (1 )
310
310
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
313
312
314
313
315
314
class TestFileStatus :
@@ -318,7 +317,8 @@ class TestFileStatus:
318
317
The latter means that the file had a .fail extension.
319
318
'''
320
319
321
- def __init__ (self , status , abspath ):
320
+ def __init__ (self , test_status , status , abspath ):
321
+ self .test_status = test_status
322
322
self .status = status
323
323
self .abspath = abspath
324
324
if status == "OK" :
@@ -331,6 +331,17 @@ def __init__(self, status, abspath):
331
331
else :
332
332
raise ValueError ('Invalid test file status: %s (allowed: "OK", "FAILED")' % status )
333
333
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
+
334
345
335
346
class TestStatus :
336
347
'''Records the test status of a package. status ends up as either "OK" or "FAILED",
@@ -342,17 +353,57 @@ class TestStatus:
342
353
def __init__ (self ):
343
354
self .status = "UNKNOWN"
344
355
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 )
345
383
346
384
347
385
def _pkg_testdir (rvm , pkg_name ):
348
386
return join (get_fastr_repo_dir (), 'test.' + rvm , pkg_name )
349
387
350
388
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
+
351
401
def _get_test_outputs (rvm , pkg_name , test_info ):
352
402
pkg_testdir = _pkg_testdir (rvm , pkg_name )
403
+ test_status = None
353
404
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 )
356
407
for f in files :
357
408
ext = os .path .splitext (f )[1 ]
358
409
# suppress .pdf's for now (we can't compare them)
@@ -370,7 +421,7 @@ def _get_test_outputs(rvm, pkg_name, test_info):
370
421
371
422
absfile = join (root , f )
372
423
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 )
374
425
375
426
376
427
def _args_to_forward_to_gnur (args ):
@@ -451,24 +502,27 @@ def _failed_outputs(outputs):
451
502
# In addition to the similar comment for GNU R, this can happen
452
503
# if, say, the JVM crashes (possible with native code packages)
453
504
logging .info ("{0}: FastR test had .fail outputs" .format (pkg ))
454
- fastr_test_status .status = "FAILED"
505
+ fastr_test_status .set_status_code ( "FAILED" )
455
506
456
507
# Now for each successful GNU R output we compare content (assuming FastR didn't fail)
457
508
for gnur_test_output_relpath , gnur_testfile_status in gnur_outputs .iteritems ():
458
509
# Can't compare if either GNUR or FastR failed
459
510
if gnur_testfile_status .status == "FAILED" :
460
- fastr_test_status .status = "INDETERMINATE"
461
- break
511
+ fastr_test_status .set_status_code ( "INDETERMINATE" )
512
+ continue
462
513
463
514
if not gnur_test_output_relpath in fastr_outputs :
464
515
# FastR crashed on this test
465
- fastr_test_status .status = "FAILED"
516
+ fastr_test_status .set_status_code ( "FAILED" )
466
517
logging .info ("{0}: FastR is missing output file: {1}" .format (pkg , gnur_test_output_relpath ))
467
- break
518
+ continue
468
519
469
520
fastr_testfile_status = fastr_outputs [gnur_test_output_relpath ]
470
521
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
472
526
473
527
gnur_content = None
474
528
with open (gnur_testfile_status .abspath ) as f :
@@ -499,18 +553,18 @@ def _failed_outputs(outputs):
499
553
500
554
if fastr_invalid_numbers or total_fastr > total_gnur :
501
555
# 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" )
504
558
fastr_testfile_status .status = "FAILED"
505
559
elif total_fastr < total_gnur :
506
560
# 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" )
509
563
fastr_testfile_status .status = "FAILED"
510
564
else :
511
565
# The total numbers are equal, so we are fine.
512
566
fastr_testfile_status .status = "OK"
513
- fastr_testfile_status .report = ok , skipped , failed
567
+ fastr_testfile_status .set_report ( ok , skipped , failed )
514
568
else :
515
569
result , n_tests_passed , n_tests_failed = fuzzy_compare (gnur_content , fastr_content ,
516
570
gnur_testfile_status .abspath ,
@@ -519,23 +573,21 @@ def _failed_outputs(outputs):
519
573
dump_preprocessed = get_opts ().dump_preprocessed )
520
574
if result == - 1 :
521
575
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" )
523
577
# 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 )
526
579
elif result != 0 :
527
- fastr_test_status .status = "FAILED"
580
+ fastr_test_status .set_status_code ( "FAILED" )
528
581
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 )
530
583
logging .info ("{0}: FastR output mismatch: {1}" .format (pkg , gnur_test_output_relpath ))
531
- # break
532
584
else :
533
585
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 )
535
587
536
588
# we started out as UNKNOWN
537
589
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" )
539
591
540
592
# write out a file with the test status for each output (that exists)
541
593
with open (join (_pkg_testdir ('fastr' , pkg ), 'testfile_status' ), 'w' ) as f :
@@ -546,21 +598,25 @@ def _failed_outputs(outputs):
546
598
test_output_file = join (_pkg_testdir ('fastr' , pkg ), relpath )
547
599
548
600
if os .path .exists (test_output_file ):
549
- ok , skipped , failed = fastr_testfile_status .report
601
+ ok , skipped , failed = fastr_testfile_status .get_report ()
550
602
f .write ("{0} {1} {2} {3}\n " .format (relpath , ok , skipped , failed ))
551
603
elif fastr_testfile_status .status == "FAILED" :
552
604
# In case of status == "FAILED", also try suffix ".fail" because we just do not know if the test
553
605
# failed and finished or just never finished.
554
606
relpath_fail = fastr_relpath + ".fail"
555
607
test_output_file_fail = join (_pkg_testdir ('fastr' , pkg ), relpath_fail )
556
608
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 ()
558
610
f .write ("{0} {1} {2} {3}\n " .format (relpath_fail , ok , skipped , failed ))
559
611
else :
560
612
logging .info ("File {0} or {1} does not exist" .format (test_output_file , test_output_file_fail ))
561
613
else :
562
614
logging .info ("File {0} does not exist" .format (test_output_file ))
563
615
616
+
617
+ with open (join (_pkg_testdir ('fastr' , pkg ), 'test_time' ), 'w' ) as f :
618
+ f .write (str (fastr_test_status .test_time ))
619
+
564
620
logging .info ('END checking ' + pkg )
565
621
566
622
@@ -668,6 +724,64 @@ def installpkgs(args, **kwargs):
668
724
return _installpkgs (rargs )
669
725
670
726
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
+
671
785
def pkgtest_cmp (args ):
672
786
gnur_filename = args [0 ]
673
787
fastr_filename = args [1 ]
0 commit comments