Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / tools / flakiness / find_flakiness.py
1 #!/usr/bin/env python
2 # Copyright 2011 The Chromium Authors
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Contains two functions that run different test cases and the same test
7 case in parallel repeatedly to identify flaky tests.
8 """
9
10 from __future__ import print_function
11
12 import os
13 import re
14 import subprocess
15 import time
16
17
18 # Defaults for FindShardingFlakiness().
19 FF_DATA_SUFFIX = '_flakies'
20 FF_SLEEP_INTERVAL = 10.0
21 FF_NUM_ITERATIONS = 100
22 FF_SUPERVISOR_ARGS = ['-r3', '--random-seed']
23
24 # Defaults for FindUnaryFlakiness().
25 FF_OUTPUT_SUFFIX = '_purges'
26 FF_NUM_PROCS = 20
27 FF_NUM_REPEATS = 10
28 FF_TIMEOUT = 600
29
30
31 def FindShardingFlakiness(test_path, data_path, supervisor_args):
32   """Finds flaky test cases by sharding and running a test for the specified
33   number of times. The data file is read at the beginning of each run to find
34   the last known counts and is overwritten at the end of each run with the new
35   counts. There is an optional sleep interval between each run so the script can
36   be killed without losing the data, useful for overnight (or weekend!) runs.
37   """
38
39   failed_tests = {}
40   # Read a previously written data file.
41   if os.path.exists(data_path):
42     data_file = open(data_path, 'r')
43     num_runs = int(data_file.readline().split(' ')[0])
44     num_passes = int(data_file.readline().split(' ')[0])
45     for line in data_file:
46       if line:
47         split_line = line.split(' -> ')
48         failed_tests[split_line[0]] = int(split_line[1])
49     data_file.close()
50   # No data file found.
51   else:
52     num_runs = 0
53     num_passes = 0
54
55   log_lines = False
56   args = ['python', '../sharding_supervisor/sharding_supervisor.py']
57   args.extend(supervisor_args + [test_path])
58   proc = subprocess.Popen(args, stderr=subprocess.PIPE)
59
60   # Shard the test and collect failures.
61   while True:
62     line = proc.stderr.readline()
63     if not line:
64       if proc.poll() is not None:
65         break
66       continue
67     print(line.rstrip())
68     if log_lines:
69       line = line.rstrip()
70       if line in failed_tests:
71         failed_tests[line] += 1
72       else:
73         failed_tests[line] = 1
74     elif line.find('FAILED TESTS:') >= 0:
75       log_lines = True
76   num_runs += 1
77   if proc.returncode == 0:
78     num_passes += 1
79
80   # Write the data file and print results.
81   data_file = open(data_path, 'w')
82   print('%i runs' % num_runs)
83   data_file.write('%i runs\n' % num_runs)
84   print('%i passes' % num_passes)
85   data_file.write('%i passes\n' % num_passes)
86   for (test, count) in failed_tests.iteritems():
87     print('%s -> %i' % (test, count))
88     data_file.write('%s -> %i\n' % (test, count))
89   data_file.close()
90
91
92 def FindUnaryFlakiness(test_path, output_path, num_procs, num_repeats, timeout):
93   """Runs all the test cases in a given test in parallel with itself, to get at
94   those that hold on to shared resources. The idea is that if a test uses a
95   unary resource, then running many instances of this test will purge out some
96   of them as failures or timeouts.
97   """
98
99   test_name_regex = r'((\w+/)?\w+\.\w+(/\d+)?)'
100   test_start = re.compile('\[\s+RUN\s+\] ' + test_name_regex)
101   test_list = []
102
103   # Run the test to discover all the test cases.
104   proc = subprocess.Popen([test_path], stdout=subprocess.PIPE)
105   while True:
106     line = proc.stdout.readline()
107     if not line:
108       if proc.poll() is not None:
109         break
110       continue
111     print(line.rstrip())
112     results = test_start.search(line)
113     if results:
114       test_list.append(results.group(1))
115
116   failures = []
117   index = 0
118   total = len(test_list)
119
120   # Run each test case in parallel with itself.
121   for test_name in test_list:
122     num_fails = 0
123     num_terminated = 0
124     procs = []
125     args = [test_path, '--gtest_filter=' + test_name,
126             '--gtest_repeat=%i' % num_repeats]
127     while len(procs) < num_procs:
128       procs.append(subprocess.Popen(args))
129     seconds = 0
130     while procs:
131       for proc in procs:
132         if proc.poll() is not None:
133           if proc.returncode != 0:
134             ++num_fails
135           procs.remove(proc)
136       # Timeout exceeded, kill the remaining processes and make a note.
137       if seconds > timeout:
138         num_fails += len(procs)
139         num_terminated = len(procs)
140         while procs:
141           procs.pop().terminate()
142       time.sleep(1.0)
143       seconds += 1
144     if num_fails:
145       line = '%s: %i failed' % (test_name, num_fails)
146       if num_terminated:
147         line += ' (%i terminated)' % num_terminated
148       failures.append(line)
149     print('%s (%i / %i): %i failed' % (test_name, index, total, num_fails))
150     index += 1
151     time.sleep(1.0)
152
153   # Print the results and write the data file.
154   print(failures)
155   data_file = open(output_path, 'w')
156   for line in failures:
157     data_file.write(line + '\n')
158   data_file.close()
159
160
161 def main():
162   if not args:
163     parser.error('You must specify a path to test!')
164   if not os.path.exists(args[0]):
165     parser.error('%s does not exist!' % args[0])
166
167   data_path = os.path.basename(args[0]) + FF_DATA_SUFFIX
168   output_path = os.path.basename(args[0]) + FF_OUTPUT_SUFFIX
169
170   for i in range(FF_NUM_ITERATIONS):
171     FindShardingFlakiness(args[0], data_path, FF_SUPERVISOR_ARGS)
172     print('That was just iteration %i of %i.' % (i + 1, FF_NUM_ITERATIONS))
173     time.sleep(FF_SLEEP_INTERVAL)
174
175   FindUnaryFlakiness(
176       args[0], output_path, FF_NUM_PROCS, FF_NUM_REPEATS, FF_TIMEOUT)
177
178
179 if __name__ == '__main__':
180   main()