@@ -455,6 +455,13 @@ def addSuccess(self, test):
455
455
super (FaucetCleanupResult , self ).addSuccess (test )
456
456
457
457
458
+ def debug_exception_handler (etype , value , trace ):
459
+ import traceback
460
+ import pdb
461
+ traceback .print_exception (etype , value , trace )
462
+ print ()
463
+ pdb .pm ()
464
+
458
465
def test_runner (root_tmpdir , resultclass , failfast = False ):
459
466
resultclass .root_tmpdir = root_tmpdir
460
467
return unittest .TextTestRunner (verbosity = 255 , resultclass = resultclass , failfast = failfast )
@@ -472,13 +479,19 @@ def run_parallel_test_suites(root_tmpdir, resultclass, parallel_tests):
472
479
return results
473
480
474
481
475
- def run_single_test_suites (root_tmpdir , resultclass , single_tests ):
482
+ def run_single_test_suites (debug , root_tmpdir , resultclass , single_tests ):
476
483
results = []
477
484
# TODO: Tests that are serialized generally depend on hardcoded ports.
478
485
# Make them use dynamic ports.
479
486
if single_tests .countTestCases ():
480
487
single_runner = test_runner (root_tmpdir , resultclass )
481
- results .append (single_runner .run (single_tests ))
488
+ if debug :
489
+ oldexcepthook = sys .excepthook
490
+ sys .excepthook = debug_exception_handler
491
+ single_tests .debug ()
492
+ sys .excepthook = oldexcepthook
493
+ else :
494
+ results .append (single_runner .run (single_tests ))
482
495
return results
483
496
484
497
@@ -496,7 +509,10 @@ def report_tests(test_status, test_list, result):
496
509
test_duration_secs = result .test_duration_secs [test_class .id ()]
497
510
tests_json .update ({
498
511
test_class .id (): {
499
- 'status' : test_status , 'output' : test_text , 'test_duration_secs' : test_duration_secs }})
512
+ 'status' : test_status ,
513
+ 'output' : test_text ,
514
+ 'test_duration_secs' : test_duration_secs
515
+ }})
500
516
return tests_json
501
517
502
518
@@ -529,14 +545,14 @@ def report_results(results, hw_config, report_json_filename):
529
545
report_json_file .write (json .dumps (report_json ))
530
546
531
547
532
- def run_test_suites (report_json_filename , hw_config , root_tmpdir ,
548
+ def run_test_suites (debug , report_json_filename , hw_config , root_tmpdir ,
533
549
resultclass , single_tests , parallel_tests , sanity_result ):
534
550
print ('running %u tests in parallel and %u tests serial' % (
535
551
parallel_tests .countTestCases (), single_tests .countTestCases ()))
536
552
results = []
537
553
results .append (sanity_result )
538
554
results .extend (run_parallel_test_suites (root_tmpdir , resultclass , parallel_tests ))
539
- results .extend (run_single_test_suites (root_tmpdir , resultclass , single_tests ))
555
+ results .extend (run_single_test_suites (debug , root_tmpdir , resultclass , single_tests ))
540
556
report_results (results , hw_config , report_json_filename )
541
557
successful_results = [result for result in results if result .wasSuccessful ()]
542
558
return len (results ) == len (successful_results )
@@ -612,7 +628,7 @@ def clean_test_dirs(root_tmpdir, all_successful, sanity, keep_logs, dumpfail):
612
628
dump_failed_test (test_name , test_dir )
613
629
614
630
615
- def run_tests (module , hw_config , requested_test_classes , dumpfail ,
631
+ def run_tests (module , hw_config , requested_test_classes , dumpfail , debug ,
616
632
keep_logs , serial , repeat , excluded_test_classes , report_json_filename ,
617
633
port_order ):
618
634
"""Actually run the test suites, potentially in parallel."""
@@ -643,10 +659,11 @@ def run_tests(module, hw_config, requested_test_classes, dumpfail,
643
659
sanity_result = run_sanity_test_suite (root_tmpdir , resultclass , sanity_tests )
644
660
if sanity_result .wasSuccessful ():
645
661
while True :
646
- all_successful = run_test_suites (
647
- report_json_filename , hw_config , root_tmpdir ,
648
- resultclass , copy .deepcopy (single_tests ),
649
- copy .deepcopy (parallel_tests ), sanity_result )
662
+ all_successful = run_test_suites (debug , report_json_filename ,
663
+ hw_config , root_tmpdir , resultclass ,
664
+ copy .deepcopy (single_tests ),
665
+ copy .deepcopy (parallel_tests ),
666
+ sanity_result )
650
667
if not repeat :
651
668
break
652
669
if not all_successful :
@@ -679,6 +696,8 @@ def parse_args():
679
696
'-c' , '--clean' , action = 'store_true' , help = 'run mininet cleanup' )
680
697
parser .add_argument (
681
698
'-d' , '--dumpfail' , action = 'store_true' , help = 'dump logs for failed tests' )
699
+ parser .add_argument (
700
+ '--debug' , action = 'store_true' , help = 'enter debug breakpoint on assertion failure' )
682
701
parser .add_argument (
683
702
'-k' , '--keep_logs' , action = 'store_true' , help = 'keep logs even for OK tests' )
684
703
loglevels = ('debug' , 'error' , 'warning' , 'info' , 'output' )
@@ -728,7 +747,7 @@ def parse_args():
728
747
729
748
730
749
return (
731
- requested_test_classes , args .clean , args .dumpfail ,
750
+ requested_test_classes , args .clean , args .dumpfail , args . debug ,
732
751
args .keep_logs , args .nocheck , args .serial , args .repeat ,
733
752
excluded_test_classes , report_json_filename , port_order ,
734
753
args .loglevel , args .profile )
@@ -739,7 +758,7 @@ def test_main(module):
739
758
740
759
print ('testing module %s' % module )
741
760
742
- (requested_test_classes , clean , dumpfail , keep_logs , nocheck ,
761
+ (requested_test_classes , clean , dumpfail , debug , keep_logs , nocheck ,
743
762
serial , repeat , excluded_test_classes , report_json_filename , port_order ,
744
763
loglevel , profile ) = parse_args ()
745
764
@@ -769,7 +788,7 @@ def test_main(module):
769
788
pr .enable ()
770
789
771
790
run_tests (
772
- module , hw_config , requested_test_classes , dumpfail ,
791
+ module , hw_config , requested_test_classes , dumpfail , debug ,
773
792
keep_logs , serial , repeat , excluded_test_classes , report_json_filename , port_order )
774
793
775
794
if profile :
0 commit comments