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

Side by Side Diff: scripts/slave/recipe_modules/auto_bisect/test_api.py

Issue 2247373002: Refactor stages 1, 2 and test_api overhaul. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Addressing all early feedback. Created 4 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
OLDNEW
(Empty)
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 import math
5
6 from collections import defaultdict
7
8 from recipe_engine import recipe_test_api
9
10 from auto_bisect import revision_state
11
12
13 class AutoBisectTestApi(recipe_test_api.RecipeTestApi):
14 def buildbot_job_status_mock(self, bb_data_list):
15 if bb_data_list:
16 return bb_data_list.pop()
17 return self.m.json.output_stream(
18 {'build': {
19 'result': 'SUCCESS',
20 'status': 'COMPLETED'}})
21
22 def compare_samples_data(self, data, rev_a, rev_b):
dtu 2016/09/13 23:57:28 This logic feels too complex for a test, and is in
RobertoCN 2016/09/21 22:22:48 Simplified it a lot, PTAL. Now any revision that h
23 values_a = data[rev_a.commit_hash].get('parsed_values', [])[
24 :rev_a.test_run_count]
25 values_b = data[rev_b.commit_hash].get('parsed_values', [])[
26 :rev_b.test_run_count]
27 while len(values_a) < rev_a.test_run_count:
28 if values_a:
29 values_a.append(values_a[-1])
30 else:
31 values_a.append(0)
32
33 while len(values_b) < rev_b.test_run_count:
34 if values_b:
35 values_b.append(values_b[-1])
36 else:
37 values_b.append(0)
38
39 avg = lambda x: sum(x)/float((len(x) or 1))
40 mean_a = avg(values_a)
41 mean_b = avg(values_b)
42 var_a = map (lambda x: (x - mean_a) ** 2, values_a)
43 var_b = map (lambda x: (x - mean_b) ** 2, values_b)
44 std_dev_a = math.sqrt(avg(var_a))
45 std_dev_b = math.sqrt(avg(var_b))
46 result = revision_state.NEED_MORE_DATA
47 if len(values_a) >= 5 and len(values_b) >= 5:
48 if mean_a != mean_b:
49 result = revision_state.SIGNIFICANTLY_DIFFERENT
50 # TODO(robertocn): Add a test that uses this clause.
51 if len(values_a) >= 18 and len(values_b) >= 18: # pragma: no cover
52 if mean_a == mean_b:
53 result = revision_state.NOT_SIGNIFICANTLY_DIFFERENT
54 return self.m.json.output_stream(
55 {
56 'sample_a': {
57 'debug_values': values_a,
58 'mean': mean_a,
59 'std_dev': std_dev_a
60 },
61 'sample_b': {
62 'debug_values': values_b,
63 'mean': mean_b,
64 'std_dev': std_dev_b,
65 },
66 'result': result
67 })
68
69 @recipe_test_api.mod_test_data
70 def hash_cp_map(self, items):
71 result = {}
72 for item in items:
73 if 'hash' in item and 'commit_pos' in item:
dtu 2016/09/13 23:57:28 Is there ever a case where 'hash' (and/or 'commit_
RobertoCN 2016/09/21 22:22:49 'hash' will always be there, 'commit_pos' may not.
74 result[item['commit_pos']] = self.m.json.output_stream(
75 {'git_sha': item['hash']})
76 return result
77
78 @recipe_test_api.mod_test_data
79 @staticmethod
80 def revision_data(items):
dtu 2016/09/13 23:57:28 As far as I can tell, this is only used in one pla
RobertoCN 2016/09/21 22:22:49 compare_sample_data cannot look up data on the con
81 result = {}
82 for item in items:
83 if 'hash' in item:
84 result[item['hash']] = item
85 return result
86
87 @recipe_test_api.mod_test_data
88 def revision_list(self, items):
89 result = {}
90 for item in items:
91 if 'hash' in item:
92 depot = item.get('depot', 'chromium')
93 result.setdefault(depot, [])
94 result[depot].append([item['hash'], item.get('commit_pos')])
95 # Exclude the start of the revision range.
96 result['chromium'] = result['chromium'][1:]
dtu 2016/09/13 23:57:28 Special-casing chromium is weird. Should this appl
RobertoCN 2016/09/21 22:22:48 We special case the topmost repo because the last
97 for depot in result:
98 result[depot] = self.m.json.output_stream(result[depot])
99 return result
100
101 @recipe_test_api.mod_test_data
102 def deps_change(self, items):
103 # If the revision has the key DEPS_change, we mock the result of git show to
104 # appear as if DEPS was among the files changed by the CL.
105 result = {}
106 for item in items:
107 if 'hash' in item:
108 git_output = ''
109 if 'DEPS_change' in item:
110 git_output = 'DEPS'
111 result[item['hash']] = self.m.raw_io.stream_output(git_output)
dtu 2016/09/13 23:57:28 This line assumes 'hash' is in item, whereas the p
RobertoCN 2016/09/21 22:22:48 Done.
112 return result
113
114 @recipe_test_api.mod_test_data
115 def diff_patch(self):
116 return self.m.raw_io.stream_output("""
117 diff --git a/DEPS b/DEPS
118 index 029be3b..2b3ea0a 100644
119 --- a/DEPS
120 +++ b/DEPS
121 @@ -13,7 +13,7 @@ deps = {
122 '@98fc59a5896f4ea990a4d527548204fed8f06c64',
123 'build/third_party/infra_libs':
124 'https://chromium.googlesource.com/infra/infra/packages/infra_libs.git'
125 - '@a13e6745a4edd01fee683e4157ea0195872e64eb',
126 + '@15ea0920b5f83d0aff4bd042e95bc388d069d51c',
127 'build/third_party/lighttpd':
128 'https://chromium.googlesource.com/chromium/deps/lighttpd.git'
129 '@9dfa55d15937a688a92cbf2b7a8621b0927d06eb',
130 """)
131
132 @recipe_test_api.mod_test_data
133 def deps(self, items):
134 result = {}
135 for item in items:
136 if 'hash' in item:
137 deps_content = ''
138 if 'DEPS' in item:
139 deps_content = item['DEPS']
140 result[item['hash']] = self.m.raw_io.stream_output(deps_content)
141 return result
142
143 @recipe_test_api.placeholder_step_data
144 @staticmethod
145 def exists_result(exists=True):
dtu 2016/09/13 23:57:28 Make protected or private. style guide: Don't use
RobertoCN 2016/09/21 22:22:49 https://cs.chromium.org/search/?q=@staticmethod+fi
146 if exists:
147 return 'GS location exists', 0, ''
148 return 'GS location does not exist', 1, ''
dtu 2016/09/13 23:57:28 Sorry, I can't figure out why this is the return v
RobertoCN 2016/09/21 22:22:49 the placeholder_step_data decorator converts this
149
150 @recipe_test_api.mod_test_data
151 def gsutil_exists(self, items):
152 result = {}
153 for item in items:
154 if 'hash' in item and 'gsutil_exists' in item:
155 result[item['hash']] = [self.exists_result(i)
156 for i in item['gsutil_exists']]
dtu 2016/09/13 23:57:28 Does it need to be a list? I don't see any case wh
RobertoCN 2016/09/21 22:22:49 We need to be able to return false for a number of
157 return result
158
159 @recipe_test_api.mod_test_data
160 def run_results(self, items):
161 def single_result(v):
162 return self.m.raw_io.stream_output(
163 data=v.get('stdout', 'text from actual benchmark, (ignored)'),
164 retcode=v.get('retcode', 0)) + self.m.raw_io.output(
165 data=v.get('stdout', 'text from actual benchmark, (ignored)'))
dtu 2016/09/13 23:57:28 nit: Can you assign v.get(...) to a variable and r
RobertoCN 2016/09/21 22:22:49 Done.
166
167 result = {'default': self.m.raw_io.stream_output('mock output', retcode=0)}
168 for item in items:
169 if 'hash' in item and 'test_results' in item:
170 result[item['hash']] = [single_result(v) for v in item['test_results']]
171 return result
172
173 @recipe_test_api.mod_test_data
174 def cl_info(self, items):
175 result = {}
176 for item in items:
177 if 'hash' in item:
178 if 'cl_info' in item:
dtu 2016/09/13 23:57:28 info = item.get('cl_info', {})
RobertoCN 2016/09/21 22:22:48 Done.
179 info = item['cl_info']
180 else:
181 info = {}
182 result[item['hash']] = self.m.json.output_stream(info)
183 return result
184
185 @recipe_test_api.mod_test_data
186 def build_status(self, items):
187 result = {}
188 for item in items:
189 if 'hash' in item and 'build_status' in item:
190 result[item['hash']] = []
191 for entry in item['build_status']:
192 result[item['hash']].append(self.m.json.output_stream(entry))
193 return result
194
195 def __call__(self, config_items):
196 return (
197 self.revision_data(config_items)
198 + self.hash_cp_map(config_items)
199 + self.revision_list(config_items)
200 + self.run_results(config_items)
201 + self.deps_change(config_items)
202 + self.deps(config_items)
203 + self.cl_info (config_items)
204 + self.diff_patch()
205 + self.gsutil_exists(config_items)
206 + self.build_status(config_items)
207 )
208
209 # """Takes massive dictionary to populate test_data for all steps."""
210 # get commit hash
211 # get test results(gsutil) ?
212 # fetch deps
213 # generating patch
214 # reading culprit information
215 # expanding revision range
216 # hashing modified deps
217 # fetch builder state
218 # fetch build details
219 # (check image) gsutil
220 #
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698