• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 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
5import glob
6import json
7import os
8
9import logging
10
11from autotest_lib.site_utils.sponge_lib import autotest_job_info
12
13
14UNKNOWN_EFFORT_NAME = 'UNKNOWN_BUILD'
15UNKNOWN_ENV_NAME = 'UNKNOWN_BOARD'
16
17
18class ACTSSummaryEnums(object):
19    """A class contains the attribute names used in a ACTS summary."""
20
21    Requested = 'Requested'
22    Failed = 'Failed'
23    Unknown = 'Unknown'
24
25
26class ACTSRecordEnums(object):
27    """A class contains the attribute names used in an ACTS record."""
28
29    BeginTime = 'Begin Time'
30    Details = 'Details'
31    EndTime = 'End Time'
32    Extras = 'Extras'
33    ExtraErrors = 'Extra Errors'
34    Result = 'Result'
35    TestClass = 'Test Class'
36    TestName = 'Test Name'
37    UID = 'UID'
38
39
40class ACTSTaskInfo(autotest_job_info.AutotestTaskInfo):
41    """Task info for an ACTS test."""
42
43    tags = autotest_job_info.AutotestTaskInfo.tags + ['acts', 'testtracker']
44    logs = autotest_job_info.AutotestTaskInfo.logs + ['results']
45
46    def __init__(self, test, job):
47        """
48        @param test: The autotest test for this ACTS test.
49        @param job: The job info that is the parent ot this task.
50        """
51        super(ACTSTaskInfo, self).__init__(test, job)
52
53        summary_location = os.path.join(
54                self.results_dir, 'results/latest/test_run_summary.json')
55
56        build_info_location = os.path.join(self.results_dir,
57                'results/BUILD_INFO-*')
58        build_info_files = glob.iglob(build_info_location)
59
60        try:
61            build_info_file = next(build_info_files)
62            logging.info('Using build info file: %s', build_info_file)
63            with open(build_info_file) as fd:
64                self.build_info = json.load(fd)
65        except Exception as e:
66            logging.exception(e)
67            logging.error('Bad build info file.')
68            self.build_info = {}
69
70        try:
71            build_prop_str = self.build_info['build_prop']
72            prop_dict = {}
73            self.build_info['build_prop'] = prop_dict
74            lines = build_prop_str.splitlines()
75            for line in lines:
76                parts = line.split('=')
77
78                if len(parts) != 2:
79                    continue
80
81                prop_dict[parts[0]] = parts[1]
82        except Exception as e:
83            logging.exception(e)
84            logging.error('Bad build prop data, using default empty dict')
85            self.build_info['build_prop'] = {}
86
87        try:
88            with open(summary_location) as fd:
89                self._acts_summary = json.load(fd)
90
91            self._summary_block = self._acts_summary['Summary']
92
93            record_block = self._acts_summary['Results']
94            self._records = list(ACTSRecord(record) for record in record_block)
95            self.is_valid = True
96        except Exception as e:
97            logging.exception(e)
98            logging.error('Bad acts data, reverting to autotest only.')
99            self.is_valid = False
100            self.tags = autotest_job_info.AutotestTaskInfo.tags
101
102    @property
103    def test_case_count(self):
104        """The number of test cases run."""
105        return self._summary_block[ACTSSummaryEnums.Requested]
106
107    @property
108    def failed_case_count(self):
109        """The number of failed test cases."""
110        return self._summary_block[ACTSSummaryEnums.Failed]
111
112    @property
113    def error_case_count(self):
114        """The number of errored test cases."""
115        return self._summary_block[ACTSSummaryEnums.Unknown]
116
117    @property
118    def records(self):
119        """All records of test cases in the ACTS tests."""
120        return self._records
121
122    @property
123    def owner(self):
124        """The owner of the task."""
125        if 'param-testtracker_owner' in self.keyvals:
126            return self.keyvals['param-testtracker_owner'].strip("'").strip('"')
127        elif 'param-test_tracker_owner' in self.keyvals:
128            return self.keyvals['param-testtracker_owner'].strip("'").strip('"')
129        else:
130            return self._job.user.strip("'").strip('"')
131
132    @property
133    def effort_name(self):
134        """The test tracker effort name."""
135        build_id = self.build_info.get('build_prop', {}).get('ro.build.id')
136        if build_id and any(c.isdigit() for c in build_id):
137            return build_id
138        else:
139            build_version = self.build_info.get('build_prop', {}).get(
140                    'ro.build.version.incremental', UNKNOWN_EFFORT_NAME)
141            return build_version
142
143
144    @property
145    def project_id(self):
146        """The test tracker project id."""
147        if 'param-testtracker_project_id' in self.keyvals:
148            return self.keyvals.get('param-testtracker_project_id')
149        else:
150            return self.keyvals.get('param-test_tracker_project_id')
151
152    @property
153    def environment(self):
154        """The name of the enviroment for test tracker."""
155        build_props = self.build_info.get('build_prop', {})
156
157        if 'ro.product.board' in build_props:
158            board = build_props['ro.product.board']
159        elif 'ro.build.product' in build_props:
160            board = build_props['ro.build.product']
161        else:
162            board = UNKNOWN_ENV_NAME
163
164        return board
165
166    @property
167    def extra_environment(self):
168        """Extra environment info about the task."""
169        if 'param-testtracker_extra_env' in self.keyvals:
170            extra = self.keyvals.get('param-testtracker_extra_env', [])
171        else:
172            extra = self.keyvals.get('param-test_tracker_extra_env', [])
173
174        if not isinstance(extra, list):
175            extra = [extra]
176
177        return extra
178
179
180class ACTSRecord(object):
181    """A single record of a test case in an ACTS test."""
182
183    tags = ['acts', 'testtracker']
184
185    def __init__(self, json_record):
186        """
187        @param json_record: The json info for this record
188        """
189        self._json_record = json_record
190
191    @property
192    def test_class(self):
193        """The test class that was run."""
194        return self._json_record[ACTSRecordEnums.TestClass]
195
196    @property
197    def test_case(self):
198        """The test case that was run. None implies all in the class."""
199        return self._json_record.get(ACTSRecordEnums.TestName)
200
201    @property
202    def uid(self):
203        """The uid of the test case."""
204        return self._json_record.get(ACTSRecordEnums.UID)
205
206    @property
207    def status(self):
208        """The status of the test case."""
209        return self._json_record[ACTSRecordEnums.Result]
210
211    @property
212    def start_time(self):
213        """The start time of the test case."""
214        return self._json_record[ACTSRecordEnums.BeginTime] / 1000.0
215
216    @property
217    def end_time(self):
218        """The end time of the test case."""
219        return self._json_record[ACTSRecordEnums.EndTime] / 1000.0
220
221    @property
222    def details(self):
223        """Details about the test case."""
224        return self._json_record.get(ACTSRecordEnums.Details)
225
226    @property
227    def extras(self):
228        """Extra info about the test case."""
229        return self._json_record.get(ACTSRecordEnums.Extras)
230
231    @property
232    def extra_errors(self):
233        """Extra errors about the test case."""
234        return self._json_record.get(ACTSRecordEnums.ExtraErrors)
235
236    @property
237    def extra_environment(self):
238        """Extra details about the environment for this test."""
239        extras = self.extras
240        if not extras:
241            return None
242
243        test_tracker_info = self.extras.get('test_tracker_info')
244        if not test_tracker_info:
245            return self.extras.get('test_tracker_environment_info')
246
247        return test_tracker_info.get('extra_environment')
248
249    @property
250    def uuid(self):
251        """The test tracker uuid of the test case."""
252        extras = self.extras
253        if not extras:
254            return None
255
256        test_tracker_info = self.extras.get('test_tracker_info')
257        if not test_tracker_info:
258            return self.extras.get('test_tracker_uuid')
259
260        return test_tracker_info.get('test_tracker_uuid')
261