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

Side by Side Diff: tools/flakiness/is_flaky_test.py

Issue 560123004: Rewrote is_flaky.py with use of multiprocessinng (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review Created 6 years, 3 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
« no previous file with comments | « tools/flakiness/is_flaky.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
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 3 # found in the LICENSE file.
5 4
6 """Runs a test repeatedly to measure its flakiness. The return code is non-zero 5 """Unit tests for is_flaky."""
7 if the failure rate is higher than the specified threshold, but is not 100%."""
8 6
9 import argparse 7 import is_flaky
10 import subprocess 8 import subprocess
11 import sys 9 import sys
12 import time 10 import threading
13 11 import unittest
14 def load_options():
15 parser = argparse.ArgumentParser(description=__doc__)
16 parser.add_argument('--retries', default=1000, type=int,
17 help='Number of test retries to measure flakiness.')
18 parser.add_argument('--threshold', default=0.05, type=float,
19 help='Minimum flakiness level at which test is '
20 'considered flaky.')
21 parser.add_argument('--jobs', '-j', type=int, default=1,
22 help='Number of parallel jobs to run tests.')
23 parser.add_argument('command', nargs='+', help='Command to run test.')
24 return parser.parse_args()
25 12
26 13
27 def process_finished(running, num_passed, num_failed): 14 class IsFlakyTest(unittest.TestCase):
28 finished = [p for p in running if p.poll() is not None]
29 running[:] = [p for p in running if p.poll() is None]
30 num_passed += len([p for p in finished if p.returncode == 0])
31 num_failed += len([p for p in finished if p.returncode != 0])
32 print '%d processed finished. Total passed: %d. Total failed: %d' % (
33 len(finished), num_passed, num_failed)
34 return num_passed, num_failed
35 15
16 def setUp(self):
17 self.original_subprocess_check_call = subprocess.check_call
18 subprocess.check_call = self.mock_check_call
19 self.check_call_calls = []
20 self.check_call_results = []
21 is_flaky.load_options = self.mock_load_options
36 22
37 def main(): 23 def tearDown(self):
38 options = load_options() 24 subprocess.check_call = self.original_subprocess_check_call
39 num_passed = num_failed = 0
40 running = []
41 25
42 # Start all retries, while limiting total number of running processes. 26 def mock_check_call(self, command, stdout, stderr):
43 for attempt in range(options.retries): 27 self.check_call_calls.append(command)
44 print 'Starting retry %d out of %d\n' % (attempt + 1, options.retries) 28 if self.check_call_results:
45 running.append(subprocess.Popen(options.command, stdout=subprocess.PIPE, 29 return self.check_call_results.pop(0)
46 stderr=subprocess.STDOUT)) 30 else:
47 while len(running) >= options.jobs: 31 return 0
48 print 'Waiting for previous retries to finish before starting new ones...'
49 time.sleep(0.1)
50 num_passed, num_failed = process_finished(running, num_passed, num_failed)
51 32
33 def mock_load_options(self):
34 class MockOptions():
35 jobs = 2
36 retries = 10
37 threshold = 0.3
38 command = ['command', 'param1', 'param2']
39 return MockOptions()
52 40
53 # Wait for the remaining retries to finish. 41 def testExecutesTestCorrectNumberOfTimes(self):
54 print 'Waiting for the remaining retries to finish...' 42 is_flaky.main()
55 for process in running: 43 self.assertEqual(len(self.check_call_calls), 10)
56 process.wait()
57 44
58 num_passed, num_failed = process_finished(running, num_passed, num_failed) 45 def testExecutesTestWithCorrectArguments(self):
59 if num_passed == 0 or num_failed == 0: 46 is_flaky.main()
60 flakiness = 0 47 for call in self.check_call_calls:
61 else: 48 self.assertEqual(call, ['command', 'param1', 'param2'])
62 flakiness = num_failed / float(options.retries)
63 49
64 print 'Flakiness is %.2f' % flakiness 50 def testReturnsNonFlakyForAllSuccesses(self):
65 if flakiness > options.threshold: 51 self.check_call_results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
66 return 1 52 ret_code = is_flaky.main()
67 else: 53 self.assertEqual(ret_code, 0)
68 return 0 54
55 def testReturnsNonFlakyForAllFailures(self):
56 self.check_call_results = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
57 ret_code = is_flaky.main()
58 self.assertEqual(ret_code, 0)
59
60 def testReturnsNonFlakyForSmallNumberOfFailures(self):
61 self.check_call_results = [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
62 ret_code = is_flaky.main()
63 self.assertEqual(ret_code, 0)
64
65 def testReturnsFlakyForLargeNumberOfFailures(self):
66 self.check_call_results = [1, 1, 1, 0, 1, 0, 0, 0, 0, 0]
67 ret_code = is_flaky.main()
68 self.assertEqual(ret_code, 1)
69 69
70 70
71 if __name__ == '__main__': 71 if __name__ == '__main__':
72 sys.exit(main()) 72 unittest.main()
OLDNEW
« no previous file with comments | « tools/flakiness/is_flaky.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698