| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 The Value hierarchy provides a way of representing the values measurements | 5 The Value hierarchy provides a way of representing the values measurements |
| 6 produce such that they can be merged across runs, grouped by page, and output | 6 produce such that they can be merged across runs, grouped by page, and output |
| 7 to different targets. | 7 to different targets. |
| 8 | 8 |
| 9 The core Value concept provides the basic functionality: | 9 The core Value concept provides the basic functionality: |
| 10 - association with a page, may be none | 10 - association with a page, may be none |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 # value is being interpreted actually affects the conversion. This is insane, | 35 # value is being interpreted actually affects the conversion. This is insane, |
| 36 # but there you have it. There are three contexts in which Values are converted | 36 # but there you have it. There are three contexts in which Values are converted |
| 37 # for use by buildbot, represented by these output-intent values. | 37 # for use by buildbot, represented by these output-intent values. |
| 38 PER_PAGE_RESULT_OUTPUT_CONTEXT = 'per-page-result-output-context' | 38 PER_PAGE_RESULT_OUTPUT_CONTEXT = 'per-page-result-output-context' |
| 39 COMPUTED_PER_PAGE_SUMMARY_OUTPUT_CONTEXT = 'merged-pages-result-output-context' | 39 COMPUTED_PER_PAGE_SUMMARY_OUTPUT_CONTEXT = 'merged-pages-result-output-context' |
| 40 SUMMARY_RESULT_OUTPUT_CONTEXT = 'summary-result-output-context' | 40 SUMMARY_RESULT_OUTPUT_CONTEXT = 'summary-result-output-context' |
| 41 | 41 |
| 42 class Value(object): | 42 class Value(object): |
| 43 """An abstract value produced by a telemetry page test. | 43 """An abstract value produced by a telemetry page test. |
| 44 """ | 44 """ |
| 45 def __init__(self, page, name, units, important, description): | 45 def __init__(self, page, name, units, important, description, |
| 46 interaction_record): |
| 46 """A generic Value object. | 47 """A generic Value object. |
| 47 | 48 |
| 48 Args: | 49 Args: |
| 49 page: A Page object, may be given as None to indicate that the value | 50 page: A Page object, may be given as None to indicate that the value |
| 50 represents results for multiple pages. | 51 represents results for multiple pages. |
| 51 name: A value name string, may contain a dot. Values from the same test | 52 name: A value name string, may contain a dot. Values from the same test |
| 52 with the same prefix before the dot may be considered to belong to | 53 with the same prefix before the dot may be considered to belong to |
| 53 the same chart. | 54 the same chart. |
| 54 units: A units string. | 55 units: A units string. |
| 55 important: Whether the value is "important". Causes the value to appear | 56 important: Whether the value is "important". Causes the value to appear |
| 56 by default in downstream UIs. | 57 by default in downstream UIs. |
| 57 description: A string explaining in human-understandable terms what this | 58 description: A string explaining in human-understandable terms what this |
| 58 value represents. | 59 value represents. |
| 60 interaction_record: The string label of the TimelineInteractionRecord with |
| 61 which this value is associated. |
| 59 """ | 62 """ |
| 60 # TODO(eakuefner): Check user story here after migration (crbug.com/442036) | 63 # TODO(eakuefner): Check user story here after migration (crbug.com/442036) |
| 61 if not isinstance(name, basestring): | 64 if not isinstance(name, basestring): |
| 62 raise ValueError('name field of Value must be string.') | 65 raise ValueError('name field of Value must be string.') |
| 63 if not isinstance(units, basestring): | 66 if not isinstance(units, basestring): |
| 64 raise ValueError('units field of Value must be string.') | 67 raise ValueError('units field of Value must be string.') |
| 65 if not isinstance(important, bool): | 68 if not isinstance(important, bool): |
| 66 raise ValueError('important field of Value must be bool.') | 69 raise ValueError('important field of Value must be bool.') |
| 67 if not ((description is None) or isinstance(description, basestring)): | 70 if not ((description is None) or isinstance(description, basestring)): |
| 68 raise ValueError('description field of Value must absent or string.') | 71 raise ValueError('description field of Value must absent or string.') |
| 72 if not ((interaction_record is None) or |
| 73 isinstance(interaction_record, basestring)): |
| 74 raise ValueError('interaction_record field of Value must absent or ' |
| 75 'string.') |
| 69 | 76 |
| 70 self.page = page | 77 self.page = page |
| 71 self.name = name | 78 self.name = name |
| 72 self.units = units | 79 self.units = units |
| 73 self.important = important | 80 self.important = important |
| 74 self.description = description | 81 self.description = description |
| 82 self.interaction_record = interaction_record |
| 75 | 83 |
| 76 def IsMergableWith(self, that): | 84 def IsMergableWith(self, that): |
| 77 return (self.units == that.units and | 85 return (self.units == that.units and |
| 78 type(self) == type(that) and | 86 type(self) == type(that) and |
| 79 self.important == that.important) | 87 self.important == that.important and |
| 88 self.interaction_record == that.interaction_record) |
| 80 | 89 |
| 81 @classmethod | 90 @classmethod |
| 82 def MergeLikeValuesFromSamePage(cls, values): | 91 def MergeLikeValuesFromSamePage(cls, values): |
| 83 """Combines the provided list of values into a single compound value. | 92 """Combines the provided list of values into a single compound value. |
| 84 | 93 |
| 85 When a page runs multiple times, it may produce multiple values. This | 94 When a page runs multiple times, it may produce multiple values. This |
| 86 function is given the same-named values across the multiple runs, and has | 95 function is given the same-named values across the multiple runs, and has |
| 87 the responsibility of producing a single result. | 96 the responsibility of producing a single result. |
| 88 | 97 |
| 89 It must return a single Value. If merging does not make sense, the | 98 It must return a single Value. If merging does not make sense, the |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 d = { | 198 d = { |
| 190 'name': self.name, | 199 'name': self.name, |
| 191 'type': self.GetJSONTypeName(), | 200 'type': self.GetJSONTypeName(), |
| 192 'units': self.units, | 201 'units': self.units, |
| 193 'important': self.important | 202 'important': self.important |
| 194 } | 203 } |
| 195 | 204 |
| 196 if self.description: | 205 if self.description: |
| 197 d['description'] = self.description | 206 d['description'] = self.description |
| 198 | 207 |
| 208 if self.interaction_record: |
| 209 d['interaction_record'] = self.interaction_record |
| 210 |
| 199 if self.page: | 211 if self.page: |
| 200 d['page_id'] = self.page.id | 212 d['page_id'] = self.page.id |
| 201 | 213 |
| 202 return d | 214 return d |
| 203 | 215 |
| 204 def AsDictWithoutBaseClassEntries(self): | 216 def AsDictWithoutBaseClassEntries(self): |
| 205 full_dict = self.AsDict() | 217 full_dict = self.AsDict() |
| 206 base_dict_keys = set(self._AsDictImpl().keys()) | 218 base_dict_keys = set(self._AsDictImpl().keys()) |
| 207 | 219 |
| 208 # Extracts only entries added by the subclass. | 220 # Extracts only entries added by the subclass. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 d['description'] = None | 287 d['description'] = None |
| 276 | 288 |
| 277 page_id = value_dict.get('page_id', None) | 289 page_id = value_dict.get('page_id', None) |
| 278 if page_id: | 290 if page_id: |
| 279 d['page'] = page_dict[int(page_id)] | 291 d['page'] = page_dict[int(page_id)] |
| 280 else: | 292 else: |
| 281 d['page'] = None | 293 d['page'] = None |
| 282 | 294 |
| 283 d['important'] = False | 295 d['important'] = False |
| 284 | 296 |
| 297 interaction_record = value_dict.get('interaction_record', None) |
| 298 if interaction_record: |
| 299 d['interaction_record'] = interaction_record |
| 300 else: |
| 301 d['interaction_record'] = None |
| 302 |
| 285 return d | 303 return d |
| 286 | 304 |
| 287 def ValueNameFromTraceAndChartName(trace_name, chart_name=None): | 305 def ValueNameFromTraceAndChartName(trace_name, chart_name=None): |
| 288 """Mangles a trace name plus optional chart name into a standard string. | 306 """Mangles a trace name plus optional chart name into a standard string. |
| 289 | 307 |
| 290 A value might just be a bareword name, e.g. numPixels. In that case, its | 308 A value might just be a bareword name, e.g. numPixels. In that case, its |
| 291 chart may be None. | 309 chart may be None. |
| 292 | 310 |
| 293 But, a value might also be intended for display with other values, in which | 311 But, a value might also be intended for display with other values, in which |
| 294 case the chart name indicates that grouping. So, you might have | 312 case the chart name indicates that grouping. So, you might have |
| (...skipping 14 matching lines...) Expand all Loading... |
| 309 whereas telemetry represents values with a chart_name.trace_name convention, | 327 whereas telemetry represents values with a chart_name.trace_name convention, |
| 310 where chart_name is optional. This convention is also used by chart_json. | 328 where chart_name is optional. This convention is also used by chart_json. |
| 311 | 329 |
| 312 This converts from the telemetry convention to the buildbot convention, | 330 This converts from the telemetry convention to the buildbot convention, |
| 313 returning a 2-tuple (measurement_name, trace_name). | 331 returning a 2-tuple (measurement_name, trace_name). |
| 314 """ | 332 """ |
| 315 if '.' in value_name: | 333 if '.' in value_name: |
| 316 return value_name.split('.', 1) | 334 return value_name.split('.', 1) |
| 317 else: | 335 else: |
| 318 return value_name, value_name | 336 return value_name, value_name |
| OLD | NEW |