redo.py revision 9e643dbb9254ad1e0d82b923f58fc64eeeec5be1
1#!/usr/bin/env python
2
3"""
4A simple utility to redo the failed/errored tests.
5
6You need to specify the session directory in order for this script to locate the
7tests which need to be re-run.
8
9See also dotest.py, the test driver running the test suite.
10
11Type:
12
13./dotest.py -h
14
15for help.
16"""
17
18import os, sys
19import re
20
21# If True, redo with no '-t' option for the test driver.
22no_trace = False
23
24# To be filled with the filterspecs found in the session logs.
25redo_specs = []
26
27# There is a known bug with respect to comp_specs and arch_specs, in that if we
28# encountered "-C clang" and "-C gcc" when visiting the session files, both
29# compilers will end up in the invocation of the test driver when rerunning.
30# That is: ./dotest -v -C clang^gcc ... -f ...".  Ditto for "-A" flags.
31# The "-C compiler" for comp_specs.
32comp_specs = set()
33# The "-A arch" for arch_specs.
34arch_specs = set()
35
36def usage():
37    print"""\
38Usage: redo.py [-n] session_dir
39where options:
40-n : when running the tests, do not turn on trace mode, i.e, no '-t' option
41     is passed to the test driver (this will run the tests faster)
42
43and session_dir specifies the session directory which contains previously
44recorded session infos for all the test cases which either failed or errored."""
45    sys.exit(0)
46
47def where(session_dir, test_dir):
48    """Returns the full path to the session directory; None if non-existent."""
49    abspath = os.path.abspath(session_dir)
50    if os.path.isdir(abspath):
51        return abspath
52
53    session_dir_path = os.path.join(test_dir, session_dir)
54    if os.path.isdir(session_dir_path):
55        return session_dir_path
56
57    return None
58
59# This is the pattern for the line from the log file to redo a test.
60# We want the filter spec.
61filter_pattern = re.compile("^\./dotest\.py.*-f (.*)$")
62comp_pattern = re.compile(" -C ([^ ]+) ")
63arch_pattern = re.compile(" -A ([^ ]+) ")
64def redo(suffix, dir, names):
65    """Visitor function for os.path.walk(path, visit, arg)."""
66    global redo_specs
67    global comp_specs
68    global arch_specs
69    global filter_pattern
70    global comp_pattern
71    global arch_pattern
72
73    for name in names:
74        if name.endswith(suffix):
75            #print "Find a log file:", name
76            if name.startswith("Error") or name.startswith("Failure"):
77                with open(os.path.join(dir, name), 'r') as log:
78                    content = log.read()
79                    for line in content.splitlines():
80                        match = filter_pattern.match(line)
81                        if match:
82                            filterspec = match.group(1)
83                            print "adding filterspec:", filterspec
84                            redo_specs.append(filterspec)
85                            comp = comp_pattern.search(line)
86                            if comp:
87                                comp_specs.add(comp.group(1))
88                            arch = arch_pattern.search(line)
89                            if arch:
90                                arch_specs.add(arch.group(1))
91            else:
92                continue
93
94def main():
95    """Read the session directory and run the failed test cases one by one."""
96    global no_trace
97    global redo_specs
98
99    if len(sys.argv) < 2 or len(sys.argv) > 3:
100        usage()
101
102    index = 1
103    while index < len(sys.argv):
104        if sys.argv[index].startswith('-'):
105            # We should continue processing...
106            pass
107        else:
108            # End of option processing.
109            break
110
111        if sys.argv[index] == '-n':
112            no_trace = True
113            index += 1
114
115    session_dir = sys.argv[index]
116
117    test_dir = sys.path[0]
118    if not test_dir.endswith('test'):
119        print "This script expects to reside in lldb's test directory."
120        sys.exit(-1)
121
122    #print "The test directory:", test_dir
123    session_dir_path = where(session_dir, test_dir)
124
125    #print "Session dir path:", session_dir_path
126    os.chdir(test_dir)
127    os.path.walk(session_dir_path, redo, ".log")
128
129    filters = " -f ".join(redo_specs)
130    compilers = (" -C %s" % "^".join(comp_specs)) if comp_specs else None
131    archs = (" -A %s" % "^".join(arch_specs)) if arch_specs else None
132
133    command = "./dotest.py %s %s -v %s -f " % (compilers if compilers else "",
134                                               archs if archs else "",
135                                               "" if no_trace else "-t")
136
137
138    print "Running %s" % (command + filters)
139    os.system(command + filters)
140
141if __name__ == '__main__':
142    main()
143