[plain text]

#!/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, the test driver running the test suite.


./ -h

for help.

import os, sys, datetime
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 = []

# The filename components to match for.  Only files with the contained component names
# will be considered for re-run.  Examples: ['X86_64', 'clang'].
filename_components = []

# There is a known bug with respect to comp_specs and arch_specs, in that if we
# encountered "-C clang" and "-C gcc" when visiting the session files, both
# compilers will end up in the invocation of the test driver when rerunning.
# That is: ./dotest -v -C clang^gcc ... -f ...".  Ditto for "-A" flags.

# The "-C compiler" for comp_specs.
comp_specs = set()
# The "-A arch" for arch_specs.
arch_specs = set()

def usage():
Usage: [-F filename_component] [-n] [session_dir]
where options:
-F : only consider the test for re-run if the session filename conatins the filename component
     for example: -F x86_64
-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.

If sessin_dir is left unspecified, this script uses the heuristic to find the
possible session directories with names starting with %Y-%m-%d- (for example,
2012-01-23-) and employs the one with the latest timestamp."""

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.
filter_pattern = re.compile("^\./dotest\.py.*-f (.*)$")
comp_pattern = re.compile(" -C ([^ ]+) ")
arch_pattern = re.compile(" -A ([^ ]+) ")
def redo(suffix, dir, names):
    """Visitor function for os.path.walk(path, visit, arg)."""
    global redo_specs
    global comp_specs
    global arch_specs
    global filter_pattern
    global comp_pattern
    global arch_pattern
    global filename_components

    for name in names:
        if name.endswith(suffix):
            #print "Find a log file:", name
            if name.startswith("Error") or name.startswith("Failure"):
                if filename_components:
                    if not all([comp in name for comp in filename_components]):
                with open(os.path.join(dir, name), 'r') as log:
                    content =
                    for line in content.splitlines():
                        match = filter_pattern.match(line)
                        if match:
                            filterspec =
                            print "adding filterspec:", filterspec
                            comp =
                            if comp:
                            arch =
                            if arch:

def main():
    """Read the session directory and run the failed test cases one by one."""
    global no_trace
    global redo_specs
    global filename_components

    test_dir = sys.path[0]
    if not test_dir:
        test_dir = os.getcwd()
    if not test_dir.endswith('test'):
        print "This script expects to reside in lldb's test directory."

    index = 1
    while index < len(sys.argv):
        if sys.argv[index].startswith('-h') or sys.argv[index].startswith('--help'):

        if sys.argv[index].startswith('-'):
            # We should continue processing...
            # End of option processing.

        if sys.argv[index] == '-F':
            # Increment by 1 to fetch the filename component spec.
            index += 1
            if index >= len(sys.argv) or sys.argv[index].startswith('-'):
        elif sys.argv[index] == '-n':
            no_trace = True

        index += 1

    if index < len(sys.argv):
        # Get the specified session directory.
        session_dir = sys.argv[index]
        # Use heuristic to find the latest session directory.
        name ="%Y-%m-%d-")
        dirs = [d for d in os.listdir(os.getcwd()) if d.startswith(name)]
        if len(dirs) == 0:
            print "No default session directory found, please specify it explicitly."
        session_dir = max(dirs, key=os.path.getmtime)
        if not session_dir or not os.path.exists(session_dir):
            print "No default session directory found, please specify it explicitly."

    #print "The test directory:", test_dir
    session_dir_path = where(session_dir, test_dir)

    print "Using session dir path:", session_dir_path
    os.path.walk(session_dir_path, redo, ".log")

    if not redo_specs:
        print "No failures/errors recorded within the session directory, please specify a different session directory.\n"

    filters = " -f ".join(redo_specs)
    compilers = ''
    for comp in comp_specs:
        compilers += " -C %s" % (comp)
    archs = ''
    for arch in arch_specs:
        archs += "--arch %s " % (arch)

    command = "./ %s %s -v %s -f " % (compilers, archs, "" if no_trace else "-t")

    print "Running %s" % (command + filters)
    os.system(command + filters)

if __name__ == '__main__':