Add a redo.py script which takes a session directory name as arg and digs into the directory
to find out the tests which failed/errored and need re-running. The dotest.py test driver script is modified to allow specifying multiple -f testclass.testmethod in the command line to accommodate the redo functionality. An example, $ ./redo.py -n 2011-07-29-11_50_14 adding filterspec: TargetAPITestCase.test_find_global_variables_with_dwarf adding filterspec: DisasmAPITestCase.test_with_dsym Running ./dotest.py -v -f TargetAPITestCase.test_find_global_variables_with_dwarf -f DisasmAPITestCase.test_with_dsym ... ---------------------------------------------------------------------- Collected 2 tests 1: test_with_dsym (TestDisasmAPI.DisasmAPITestCase) Exercise getting SBAddress objects, disassembly, and SBAddress APIs. ... ok 2: test_find_global_variables_with_dwarf (TestTargetAPI.TargetAPITestCase) Exercise SBTarget.FindGlobalVariables() API. ... ok ---------------------------------------------------------------------- Ran 2 tests in 15.328s OK llvm-svn: 136533
This commit is contained in:
		
							parent
							
								
									9760f04ef9
								
							
						
					
					
						commit
						4a57d122fe
					
				| 
						 | 
					@ -102,8 +102,8 @@ dumpSysPath = False
 | 
				
			||||||
# By default, failfast is False.  Use '-F' to overwrite it.
 | 
					# By default, failfast is False.  Use '-F' to overwrite it.
 | 
				
			||||||
failfast = False
 | 
					failfast = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The filter (testclass.testmethod) used to admit tests into our test suite.
 | 
					# The filters (testclass.testmethod) used to admit tests into our test suite.
 | 
				
			||||||
filterspec = None
 | 
					filters = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# If '-g' is specified, the filterspec is not exclusive.  If a test module does
 | 
					# If '-g' is specified, the filterspec is not exclusive.  If a test module does
 | 
				
			||||||
# not contain testclass.testmethod which matches the filterspec, the whole test
 | 
					# not contain testclass.testmethod which matches the filterspec, the whole test
 | 
				
			||||||
| 
						 | 
					@ -296,7 +296,7 @@ def parseOptionsAndInitTestdirs():
 | 
				
			||||||
    global delay
 | 
					    global delay
 | 
				
			||||||
    global dumpSysPath
 | 
					    global dumpSysPath
 | 
				
			||||||
    global failfast
 | 
					    global failfast
 | 
				
			||||||
    global filterspec
 | 
					    global filters
 | 
				
			||||||
    global fs4all
 | 
					    global fs4all
 | 
				
			||||||
    global ignore
 | 
					    global ignore
 | 
				
			||||||
    global skipLongRunningTest
 | 
					    global skipLongRunningTest
 | 
				
			||||||
| 
						 | 
					@ -381,7 +381,7 @@ def parseOptionsAndInitTestdirs():
 | 
				
			||||||
            index += 1
 | 
					            index += 1
 | 
				
			||||||
            if index >= len(sys.argv) or sys.argv[index].startswith('-'):
 | 
					            if index >= len(sys.argv) or sys.argv[index].startswith('-'):
 | 
				
			||||||
                usage()
 | 
					                usage()
 | 
				
			||||||
            filterspec = sys.argv[index]
 | 
					            filters.append(sys.argv[index])
 | 
				
			||||||
            index += 1
 | 
					            index += 1
 | 
				
			||||||
        elif sys.argv[index].startswith('-g'):
 | 
					        elif sys.argv[index].startswith('-g'):
 | 
				
			||||||
            fs4all = False
 | 
					            fs4all = False
 | 
				
			||||||
| 
						 | 
					@ -662,7 +662,7 @@ def visit(prefix, dir, names):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    global suite
 | 
					    global suite
 | 
				
			||||||
    global regexp
 | 
					    global regexp
 | 
				
			||||||
    global filterspec
 | 
					    global filters
 | 
				
			||||||
    global fs4all
 | 
					    global fs4all
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for name in names:
 | 
					    for name in names:
 | 
				
			||||||
| 
						 | 
					@ -689,7 +689,8 @@ def visit(prefix, dir, names):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Thoroughly check the filterspec against the base module and admit
 | 
					            # Thoroughly check the filterspec against the base module and admit
 | 
				
			||||||
            # the (base, filterspec) combination only when it makes sense.
 | 
					            # the (base, filterspec) combination only when it makes sense.
 | 
				
			||||||
            if filterspec:
 | 
					            filterspec = None
 | 
				
			||||||
 | 
					            for filterspec in filters:
 | 
				
			||||||
                # Optimistically set the flag to True.
 | 
					                # Optimistically set the flag to True.
 | 
				
			||||||
                filtered = True
 | 
					                filtered = True
 | 
				
			||||||
                module = __import__(base)
 | 
					                module = __import__(base)
 | 
				
			||||||
| 
						 | 
					@ -702,13 +703,19 @@ def visit(prefix, dir, names):
 | 
				
			||||||
                        # The filterspec has failed.
 | 
					                        # The filterspec has failed.
 | 
				
			||||||
                        filtered = False
 | 
					                        filtered = False
 | 
				
			||||||
                        break
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # If we reach here, we have a good filterspec.  Add it.
 | 
				
			||||||
 | 
					                if filtered:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Forgo this module if the (base, filterspec) combo is invalid
 | 
					            # Forgo this module if the (base, filterspec) combo is invalid
 | 
				
			||||||
            # and no '-g' option is specified
 | 
					            # and no '-g' option is specified
 | 
				
			||||||
                if fs4all and not filtered:
 | 
					            if filters and fs4all and not filtered:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
            # Add either the filtered test case or the entire test class.
 | 
					            # Add either the filtered test case or the entire test class.
 | 
				
			||||||
            if filterspec and filtered:
 | 
					            if filterspec and filtered:
 | 
				
			||||||
 | 
					                #print "adding filter spec %s to module %s" % (filterspec, module)
 | 
				
			||||||
                suite.addTests(
 | 
					                suite.addTests(
 | 
				
			||||||
                    unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
 | 
					                    unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,114 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					A simple utility to redo the failed/errored tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You need to specify the session directory in order for this script to locate the
 | 
				
			||||||
 | 
					tests which need to be re-run.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also dotest.py, the test driver running the test suite.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Type:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					./dotest.py -h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					for help.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os, sys
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If True, redo with no '-t' option for the test driver.
 | 
				
			||||||
 | 
					no_trace = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# To be filled with the filterspecs found in the session logs.
 | 
				
			||||||
 | 
					redo_specs = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def usage():
 | 
				
			||||||
 | 
					    print"""\
 | 
				
			||||||
 | 
					Usage: redo.py [-n] session_dir
 | 
				
			||||||
 | 
					where options:
 | 
				
			||||||
 | 
					-n : when running the tests, do not turn on trace mode, i.e, no '-t' option
 | 
				
			||||||
 | 
					     is passed to the test driver (this will run the tests faster)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					and session_dir specifies the session directory which contains previously
 | 
				
			||||||
 | 
					recorded session infos for all the test cases which either failed or errored."""
 | 
				
			||||||
 | 
					    sys.exit(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def where(session_dir, test_dir):
 | 
				
			||||||
 | 
					    """Returns the full path to the session directory; None if non-existent."""
 | 
				
			||||||
 | 
					    abspath = os.path.abspath(session_dir)
 | 
				
			||||||
 | 
					    if os.path.isdir(abspath):
 | 
				
			||||||
 | 
					        return abspath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    session_dir_path = os.path.join(test_dir, session_dir)
 | 
				
			||||||
 | 
					    if os.path.isdir(session_dir_path):
 | 
				
			||||||
 | 
					        return session_dir_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This is the pattern for the line from the log file to redo a test.
 | 
				
			||||||
 | 
					# We want the filter spec.
 | 
				
			||||||
 | 
					pattern = re.compile("^\./dotest\.py.*-f (.*)$")
 | 
				
			||||||
 | 
					def redo(suffix, dir, names):
 | 
				
			||||||
 | 
					    """Visitor function for os.path.walk(path, visit, arg)."""
 | 
				
			||||||
 | 
					    global redo_specs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for name in names:
 | 
				
			||||||
 | 
					        if name.endswith(suffix):
 | 
				
			||||||
 | 
					            #print "Find a log file:", name
 | 
				
			||||||
 | 
					            if name.startswith("Error") or name.startswith("Failure"):
 | 
				
			||||||
 | 
					                with open(os.path.join(dir, name), 'r') as log:
 | 
				
			||||||
 | 
					                    content = log.read()
 | 
				
			||||||
 | 
					                    for line in content.splitlines():
 | 
				
			||||||
 | 
					                        match = pattern.match(line)
 | 
				
			||||||
 | 
					                        if match:
 | 
				
			||||||
 | 
					                            filterspec = match.group(1)
 | 
				
			||||||
 | 
					                            print "adding filterspec:", filterspec
 | 
				
			||||||
 | 
					                            redo_specs.append(filterspec)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    """Read the session directory and run the failed test cases one by one."""
 | 
				
			||||||
 | 
					    global no_trace
 | 
				
			||||||
 | 
					    global redo_specs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if len(sys.argv) < 2 or len(sys.argv) > 3:
 | 
				
			||||||
 | 
					        usage()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    index = 1
 | 
				
			||||||
 | 
					    while index < len(sys.argv):
 | 
				
			||||||
 | 
					        if sys.argv[index].startswith('-'):
 | 
				
			||||||
 | 
					            # We should continue processing...
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # End of option processing.
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if sys.argv[index] == '-n':
 | 
				
			||||||
 | 
					            no_trace = True
 | 
				
			||||||
 | 
					            index += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    session_dir = sys.argv[index]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test_dir = sys.path[0]
 | 
				
			||||||
 | 
					    if not test_dir.endswith('test'):
 | 
				
			||||||
 | 
					        print "This script expects to reside in lldb's test directory."
 | 
				
			||||||
 | 
					        sys.exit(-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #print "The test directory:", test_dir
 | 
				
			||||||
 | 
					    session_dir_path = where(session_dir, test_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #print "Session dir path:", session_dir_path
 | 
				
			||||||
 | 
					    os.chdir(test_dir)
 | 
				
			||||||
 | 
					    os.path.walk(session_dir_path, redo, ".log")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    command = "./dotest.py -v %s -f " % ("" if no_trace else "-t")
 | 
				
			||||||
 | 
					    filters = " -f ".join(redo_specs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print "Running %s" % (command + filters)
 | 
				
			||||||
 | 
					    os.system(command + filters)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
		Loading…
	
		Reference in New Issue