Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(296)

Side by Side Diff: trace_test_cases.py

Issue 19917006: Move all googletest related scripts into googletest/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: Remove unnecessary pylint warning disable Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tests/trace_test_cases_smoke_test.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Traces each test cases of a google-test executable individually.
7
8 Gives detailed information about each test case. The logs can be read afterward
9 with ./trace_inputs.py read -l /path/to/executable.logs
10 """
11
12 import logging
13 import multiprocessing
14 import os
15 import re
16 import sys
17 import time
18
19 import run_test_cases
20 import trace_inputs
21
22 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
23 ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR))
24
25
26 def sanitize_test_case_name(test_case):
27 """Removes characters that are valid as test case names but invalid as file
28 names.
29 """
30 return test_case.replace('/', '-')
31
32
33 class Tracer(object):
34 def __init__(self, tracer, cmd, cwd_dir, progress):
35 # Constants
36 self.tracer = tracer
37 self.cmd = cmd[:]
38 self.cwd_dir = cwd_dir
39 self.progress = progress
40
41 def map(self, test_case):
42 """Traces a single test case and returns its output."""
43 cmd = self.cmd[:]
44 cmd.append('--gtest_filter=%s' % test_case)
45 tracename = sanitize_test_case_name(test_case)
46
47 out = []
48 for retry in range(5):
49 start = time.time()
50 returncode, output = self.tracer.trace(cmd, self.cwd_dir, tracename, True)
51 duration = time.time() - start
52 # TODO(maruel): Define a way to detect if a strace log is valid.
53 valid = True
54 out.append(
55 {
56 'test_case': test_case,
57 'tracename': tracename,
58 'returncode': returncode,
59 'duration': duration,
60 'valid': valid,
61 'output': output,
62 })
63 logging.debug(
64 'Tracing %s done: %d, %.1fs' % (test_case, returncode, duration))
65 if retry:
66 self.progress.update_item(
67 '%s - %d' % (test_case, retry), True, not valid)
68 else:
69 self.progress.update_item(test_case, True, not valid)
70 if valid:
71 break
72 return out
73
74
75 def trace_test_cases(cmd, cwd_dir, test_cases, jobs, logname):
76 """Traces each test cases individually but all in parallel."""
77 assert os.path.isabs(cwd_dir) and os.path.isdir(cwd_dir), cwd_dir
78
79 if not test_cases:
80 return []
81
82 # Resolve any symlink.
83 cwd_dir = os.path.realpath(cwd_dir)
84 assert os.path.isdir(cwd_dir)
85
86 api = trace_inputs.get_api()
87 api.clean_trace(logname)
88
89 jobs = jobs or multiprocessing.cpu_count()
90 # Try to do black magic here by guessing a few of the run_test_cases.py
91 # flags. It's cheezy but it works.
92 for i, v in enumerate(cmd):
93 if v.endswith('run_test_cases.py'):
94 # Found it. Process the arguments here.
95 _, options, _ = run_test_cases.process_args(cmd[i:])
96 # Always override with the lowest value.
97 jobs = min(options.jobs, jobs)
98 break
99
100 progress = run_test_cases.Progress(len(test_cases))
101 with run_test_cases.ThreadPool(progress, jobs, jobs,
102 len(test_cases)) as pool:
103 with api.get_tracer(logname) as tracer:
104 function = Tracer(tracer, cmd, cwd_dir, progress).map
105 for test_case in test_cases:
106 pool.add_task(0, function, test_case)
107
108 results = pool.join()
109 print('')
110 return results
111
112
113 def write_details(logname, outfile, root_dir, blacklist, results):
114 """Writes an .test_cases file with all the information about each test
115 case.
116 """
117 api = trace_inputs.get_api()
118 logs = dict(
119 (i.pop('trace'), i) for i in api.parse_log(logname, blacklist, None))
120 results_processed = {}
121 exception = None
122 for items in results:
123 item = items[-1]
124 assert item['valid']
125 # Load the results;
126 log_dict = logs[item['tracename']]
127 if log_dict.get('exception'):
128 exception = exception or log_dict['exception']
129 continue
130 trace_result = log_dict['results']
131 if root_dir:
132 trace_result = trace_result.strip_root(root_dir)
133 results_processed[item['test_case']] = {
134 'trace': trace_result.flatten(),
135 'duration': item['duration'],
136 'output': item['output'],
137 'returncode': item['returncode'],
138 }
139
140 # Make it dense if there is more than 20 results.
141 trace_inputs.write_json(
142 outfile,
143 results_processed,
144 len(results_processed) > 20)
145 if exception:
146 raise exception[0], exception[1], exception[2]
147
148
149 def main():
150 """CLI frontend to validate arguments."""
151 run_test_cases.run_isolated.disable_buffering()
152 parser = run_test_cases.OptionParserTestCases(
153 usage='%prog <options> [gtest]')
154 parser.format_description = lambda *_: parser.description
155 parser.add_option(
156 '-o', '--out',
157 help='output file, defaults to <executable>.test_cases')
158 parser.add_option(
159 '-r', '--root-dir',
160 help='Root directory under which file access should be noted')
161 # TODO(maruel): Add support for options.timeout.
162 parser.remove_option('--timeout')
163 options, args = parser.parse_args()
164
165 if not args:
166 parser.error(
167 'Please provide the executable line to run, if you need fancy things '
168 'like xvfb, start this script from *inside* xvfb, it\'ll be much faster'
169 '.')
170
171 cmd = run_test_cases.fix_python_path(args)
172 cmd[0] = os.path.abspath(cmd[0])
173 if not os.path.isfile(cmd[0]):
174 parser.error('Tracing failed for: %s\nIt doesn\'t exit' % ' '.join(cmd))
175
176 if not options.out:
177 options.out = '%s.test_cases' % cmd[-1]
178 options.out = os.path.abspath(options.out)
179 if options.root_dir:
180 options.root_dir = os.path.abspath(options.root_dir)
181 logname = options.out + '.log'
182
183 def blacklist(f):
184 return any(re.match(b, f) for b in options.blacklist)
185
186 test_cases = parser.process_gtest_options(cmd, os.getcwd(), options)
187
188 # Then run them.
189 print('Tracing...')
190 results = trace_test_cases(
191 cmd,
192 os.getcwd(),
193 test_cases,
194 options.jobs,
195 logname)
196 print('Reading trace logs...')
197 write_details(logname, options.out, options.root_dir, blacklist, results)
198 return 0
199
200
201 if __name__ == '__main__':
202 sys.exit(main())
OLDNEW
« no previous file with comments | « tests/trace_test_cases_smoke_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698