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

Side by Side Diff: scripts/slave/recipe_modules/test_utils/api.py

Issue 339183013: De-duplicate steps between chromium and chromium_trybot recipes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: rebase Created 6 years, 5 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
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # 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
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 from slave import recipe_api 5 from slave import recipe_api
6 6
7 class TestUtilsApi(recipe_api.RecipeApi): 7 class TestUtilsApi(recipe_api.RecipeApi):
8 @staticmethod 8 @staticmethod
9 def format_step_text(data): 9 def format_step_text(data):
10 """ 10 """
(...skipping 17 matching lines...) Expand all
28 # Only displaying the section (even the header) when it's non-empty 28 # Only displaying the section (even the header) when it's non-empty
29 # simplifies caller code. 29 # simplifies caller code.
30 if section[1]: 30 if section[1]:
31 step_text.append('<br/>%s<br/>' % section[0]) 31 step_text.append('<br/>%s<br/>' % section[0])
32 step_text.extend(('%s<br/>' % line for line in section[1])) 32 step_text.extend(('%s<br/>' % line for line in section[1]))
33 else: # pragma: no cover 33 else: # pragma: no cover
34 raise ValueError( 34 raise ValueError(
35 'Expected a one or two-element list, got %r instead.' % section) 35 'Expected a one or two-element list, got %r instead.' % section)
36 return ''.join(step_text) 36 return ''.join(step_text)
37 37
38 class Test(object): 38 def determine_new_failures(self, api, tests, deapply_patch_fn):
39 """
40 Base class for tests that can be retried after deapplying a previously
41 applied patch.
42 """
43
44 @property
45 def name(self): # pragma: no cover
46 """Name of the test."""
47 raise NotImplementedError()
48
49 def pre_run(self, suffix): # pragma: no cover
50 """Steps to execute before running the test."""
51 return []
52
53 def run(self, suffix): # pragma: no cover
54 """Run the test. suffix is 'with patch' or 'without patch'."""
55 raise NotImplementedError()
56
57 def post_run(self, suffix): # pragma: no cover
58 """Steps to execute after running the test."""
59 return []
60
61 def has_valid_results(self, suffix): # pragma: no cover
62 """
63 Returns True if results (failures) are valid.
64
65 This makes it possible to distinguish between the case of no failures
66 and the test failing to even report its results in machine-readable
67 format.
68 """
69 raise NotImplementedError()
70
71 def failures(self, suffix): # pragma: no cover
72 """Return list of failures (list of strings)."""
73 raise NotImplementedError()
74
75 def _step_name(self, suffix):
76 """Helper to uniformly combine tests's name with a suffix."""
77 return '%s (%s)' % (self.name, suffix)
78
79 def determine_new_failures(self, tests, deapply_patch_fn):
80 """ 39 """
81 Utility function for running steps with a patch applied, and retrying 40 Utility function for running steps with a patch applied, and retrying
82 failing steps without the patch. Failures from the run without the patch are 41 failing steps without the patch. Failures from the run without the patch are
83 ignored. 42 ignored.
84 43
85 Args: 44 Args:
45 api - recipe API
agable 2014/06/28 00:05:13 Please call this parent_api (caller_api?) or somet
Paweł Hajdan Jr. 2014/06/28 00:19:01 Done.
86 tests - iterable of objects implementing the Test interface above 46 tests - iterable of objects implementing the Test interface above
87 deapply_patch_fn - function that takes a list of failing tests 47 deapply_patch_fn - function that takes a list of failing tests
88 and undoes any effect of the previously applied patch 48 and undoes any effect of the previously applied patch
89 """ 49 """
90 # Convert iterable to list, since it is enumerated multiple times. 50 # Convert iterable to list, since it is enumerated multiple times.
91 tests = list(tests) 51 tests = list(tests)
92 52
93 if self.m.step_history.failed: 53 if self.m.step_history.failed:
94 yield self.m.python.inline( 54 yield self.m.python.inline(
95 'Aborting due to failed build state', 55 'Aborting due to failed build state',
96 "import sys; sys.exit(1)", 56 "import sys; sys.exit(1)",
97 always_run=True, abort_on_failure=True) 57 always_run=True, abort_on_failure=True)
98 return # won't actually hit this, but be explicit 58 return # won't actually hit this, but be explicit
99 59
100 def run(prefix, tests): 60 def run(prefix, tests):
101 yield (t.pre_run(prefix) for t in tests) 61 yield (t.pre_run(api, prefix) for t in tests)
102 yield (t.run(prefix) for t in tests) 62 yield (t.run(api, prefix) for t in tests)
103 yield (t.post_run(prefix) for t in tests) 63 yield (t.post_run(api, prefix) for t in tests)
104 64
105 yield run('with patch', tests) 65 yield run('with patch', tests)
106 66
107 failing_tests = [] 67 failing_tests = []
108 for t in tests: 68 for t in tests:
109 if not t.has_valid_results('with patch'): 69 if not t.has_valid_results(api, 'with patch'):
110 yield self.m.python.inline( 70 yield self.m.python.inline(
111 t.name, 71 t.name,
112 r""" 72 r"""
113 import sys 73 import sys
114 print 'TEST RESULTS WERE INVALID' 74 print 'TEST RESULTS WERE INVALID'
115 sys.exit(1) 75 sys.exit(1)
116 """, 76 """,
117 always_run=True) 77 always_run=True)
118 elif t.failures('with patch'): 78 elif t.failures(api, 'with patch'):
119 failing_tests.append(t) 79 failing_tests.append(t)
120 if not failing_tests: 80 if not failing_tests:
121 return 81 return
122 82
123 yield deapply_patch_fn(failing_tests) 83 yield deapply_patch_fn(failing_tests)
124 84
125 yield run('without patch', failing_tests) 85 yield run('without patch', failing_tests)
126 yield (self._summarize_retried_test(t) for t in failing_tests) 86 yield (self._summarize_retried_test(api, t) for t in failing_tests)
127 87
128 def _summarize_retried_test(self, test): 88 def _summarize_retried_test(self, api, test):
129 if not test.has_valid_results('without patch'): 89 if not test.has_valid_results(api, 'without patch'):
130 return self.m.python.inline( 90 return self.m.python.inline(
131 test.name, 91 test.name,
132 r""" 92 r"""
133 import sys 93 import sys
134 print 'TEST RESULTS WERE INVALID' 94 print 'TEST RESULTS WERE INVALID'
135 sys.exit(1) 95 sys.exit(1)
136 """, 96 """,
137 always_run=True) 97 always_run=True)
138 98
139 ignored_failures = set(test.failures('without patch')) 99 ignored_failures = set(test.failures(api, 'without patch'))
140 new_failures = set(test.failures('with patch')) - ignored_failures 100 new_failures = set(test.failures(api, 'with patch')) - ignored_failures
141 101
142 def followup_fn(step_result): 102 def followup_fn(step_result):
143 p = step_result.presentation 103 p = step_result.presentation
144 104
145 p.step_text += self.format_step_text([ 105 p.step_text += self.format_step_text([
146 ['failures:', new_failures], 106 ['failures:', new_failures],
147 ['ignored:', ignored_failures] 107 ['ignored:', ignored_failures]
148 ]) 108 ])
149 109
150 if new_failures: 110 if new_failures:
(...skipping 24 matching lines...) Expand all
175 """, 135 """,
176 args=[ 136 args=[
177 self.m.json.input({ 137 self.m.json.input({
178 'new': list(new_failures), 138 'new': list(new_failures),
179 'ignored': list(ignored_failures), 139 'ignored': list(ignored_failures),
180 }) 140 })
181 ], 141 ],
182 followup_fn=followup_fn, 142 followup_fn=followup_fn,
183 always_run=True, 143 always_run=True,
184 ) 144 )
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698