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

Side by Side Diff: tools/purge_flakies.py

Issue 7688004: Added tools for finding and purging flaky tests (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: ls Created 9 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
« tools/find_flakies.py ('K') | « tools/find_flakies.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) 2011 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 """Runs all the test cases in a given test in parallel with itself, to get at
Paweł Hajdan Jr. 2011/08/19 18:35:50 Would it make sense to combine this in a single fi
clee 2011/08/19 21:06:35 Ideally yes, but the command line options to the t
7 those that hold on to shared resources. The idea is that if a test uses a
8 unary resource, then running many instances of this test will purge out some
9 of them as failures or timeouts.
10 """
11
12
13 import optparse
14 import os
15 import re
16 import subprocess
17 import time
18
19
20 PF_USAGE = 'python %prog [options] path/to/test'
21 PF_DEFAULT_OUTPUT_SUFFIX = '_purges'
22 PF_DEFAULT_NUM_PROCS = 20
23 PF_DEFAULT_NUM_REPEATS = 10
24 PF_DEFAULT_TIMEOUT = 600
25
26
27 def PurgeFlakies(test_path, output_path, num_procs, num_repeats, timeout):
28 test_name_regex = r'((\w+/)?\w+\.\w+(/\d+)?)'
29 test_start = re.compile('\[\s+RUN\s+\] ' + test_name_regex)
30 test_list = []
31
32 # run the test to discover all the test cases
33 proc = subprocess.Popen([test_path], stdout=subprocess.PIPE)
34 while True:
35 line = proc.stdout.readline()
36 if not line:
37 if proc.poll() is not None:
38 break
39 continue
40 print line.rstrip()
41 results = test_start.search(line)
42 if results:
43 test_list.append(results.group(1))
44
45 failures = []
46 index = 0
47 total = len(test_list)
48
49 # run each test case in parallel with itself
50 for test_name in test_list:
51 num_fails = 0
52 num_terminated = 0
53 procs = []
54 args = [test_path, '--gtest_filter=' + test_name,
55 '--gtest_repeat=%i' % num_repeats]
56 while len(procs) < num_procs:
57 procs.append(subprocess.Popen(args))
58 seconds = 0
59 while procs:
60 for proc in procs:
61 if proc.poll() is not None:
62 if proc.returncode != 0:
63 ++num_fails
64 procs.remove(proc)
65 # timeout exceeded, kill the remaining processes and make a note
66 if seconds > timeout:
67 num_fails += len(procs)
68 num_terminated = len(procs)
69 while procs:
70 procs.pop().terminate()
71 time.sleep(1.0)
72 seconds += 1
73 if num_fails:
74 line = '%s: %i failed' % (test_name, num_fails)
75 if num_terminated:
76 line += ' (%i terminated)' % num_terminated
77 failures.append(line)
78 print '%s (%i / %i): %i failed' % (test_name, index, total, num_fails)
79 index += 1
80 time.sleep(1.0)
81
82 # print the results and write the data file
83 print failures
84 data_file = open(output_path, 'w')
85 for line in failures:
86 data_file.write(line + '\n')
87 data_file.close()
88
89
90 def main():
91 parser = optparse.OptionParser(usage=PF_USAGE)
92 parser.add_option(
93 '--output-path',
94 help='path to output file (default is to append "%s" to the end of the'
95 ' test name in the current directory)' % PF_DEFAULT_OUTPUT_SUFFIX)
96 parser.add_option(
97 '--procs', type='int', default=PF_DEFAULT_NUM_PROCS,
98 help='number of parallel test processes to start up'
99 ' (default = %s)' % PF_DEFAULT_NUM_PROCS)
100 parser.add_option(
101 '--repeats', type='int', default=PF_DEFAULT_NUM_REPEATS,
102 help='number of times to repeat each test in each process'
103 ' (default = %s)' % PF_DEFAULT_NUM_REPEATS)
104 parser.add_option(
105 '--timeout', type='int', default=PF_DEFAULT_TIMEOUT,
106 help='test processes are killed if their runtimes exceed the timeout,'
107 ' useful for some tests (default = %s)' % PF_DEFAULT_TIMEOUT)
108 (options, args) = parser.parse_args()
109
110 if not args:
111 parser.error('You must specify a path to test!')
112 if not os.path.exists(args[0]):
113 parser.error('%s does not exist!' % args[0])
114
115 if not options.output_path:
116 options.output_path = os.path.basename(args[0]) + PF_DEFAULT_OUTPUT_SUFFIX
117
118 PurgeFlakies(args[0], options.output_path, options.procs, options.repeats,
119 options.timeout)
120
121
122 if __name__ == '__main__':
123 main()
OLDNEW
« tools/find_flakies.py ('K') | « tools/find_flakies.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698