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

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: Added tests 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
« tools/flakiness/is_flaky.py ('K') | « 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] 15 """Tests for the is_flaky.py functions."""
qyearsley 2014/09/16 18:52:09 Ojan might think that this docstring is redundant/
Sergiy Byelozyorov 2014/09/17 15:49:33 Done.
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 16
17 def mock_check_call(self, command, stdout, stderr):
18 self.check_call_calls.append(command)
19 if self.check_call_results:
20 return self.check_call_results.pop(0)
21 else:
22 return 0
36 23
37 def main(): 24 def mock_load_options(self):
38 options = load_options() 25 class MockOptions():
39 num_passed = num_failed = 0 26 jobs = 2
40 running = [] 27 retries = 10
28 threshold = 0.3
29 command = ['command', 'param1', 'param2']
30 return MockOptions()
41 31
42 # Start all retries, while limiting total number of running processes. 32 def setUp(self):
43 for attempt in range(options.retries): 33 self.original_subprocess_check_call = subprocess.check_call
44 print 'Starting retry %d out of %d\n' % (attempt + 1, options.retries) 34 subprocess.check_call = self.mock_check_call
qyearsley 2014/09/16 18:52:09 An alternative to this way is using the "mock" mod
Sergiy Byelozyorov 2014/09/17 15:49:33 I'd love that, but mock module is not installed by
45 running.append(subprocess.Popen(options.command, stdout=subprocess.PIPE, 35 self.check_call_calls = []
46 stderr=subprocess.STDOUT)) 36 self.check_call_results = []
47 while len(running) >= options.jobs: 37 is_flaky.load_options = self.mock_load_options
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 38
39 def tearDown(self):
40 subprocess.check_call = self.original_subprocess_check_call
qyearsley 2014/09/16 18:52:09 setUp and tearDown could also be put at the top of
Sergiy Byelozyorov 2014/09/17 15:49:34 Done.
52 41
53 # Wait for the remaining retries to finish. 42 def testExecutesTestCorrectNumberOfTimes(self):
54 print 'Waiting for the remaining retries to finish...' 43 is_flaky.main()
55 for process in running: 44 self.assertEqual(len(self.check_call_calls), 10)
56 process.wait()
57 45
58 num_passed, num_failed = process_finished(running, num_passed, num_failed) 46 def testExecutesTestWithCorrectArguments(self):
59 if num_passed == 0 or num_failed == 0: 47 is_flaky.main()
60 flakiness = 0 48 for call in self.check_call_calls:
61 else: 49 self.assertEqual(call, ['command', 'param1', 'param2'])
62 flakiness = num_failed / float(options.retries)
63 50
64 print 'Flakiness is %.2f' % flakiness 51 def testReturnsNonFlakyForAllSuccesses(self):
65 if flakiness > options.threshold: 52 self.check_call_results = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
66 return 1 53 ret_code = is_flaky.main()
67 else: 54 self.assertEqual(ret_code, 0)
68 return 0 55
56 def testReturnsNonFlakyForAllFailures(self):
57 self.check_call_results = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
58 ret_code = is_flaky.main()
59 self.assertEqual(ret_code, 0)
60
61 def testReturnsNonFlakyForSmallNumberOfFailures(self):
62 self.check_call_results = [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
63 ret_code = is_flaky.main()
64 self.assertEqual(ret_code, 0)
qyearsley 2014/09/16 18:52:09 You might note that this failure rate of 2/10 is l
Sergiy Byelozyorov 2014/09/17 15:49:34 That's right. That's why the return code is 0 - te
65
66 def testReturnsFlakyForLargeNumberOfFailures(self):
67 self.check_call_results = [1, 1, 1, 0, 1, 0, 0, 0, 0, 0]
68 ret_code = is_flaky.main()
69 self.assertEqual(ret_code, 1)
69 70
70 71
71 if __name__ == '__main__': 72 if __name__ == '__main__':
72 sys.exit(main()) 73 unittest.main()
OLDNEW
« tools/flakiness/is_flaky.py ('K') | « tools/flakiness/is_flaky.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698