| # Copyright 2017 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import glob |
| import json |
| import os |
| |
| import logging |
| |
| from autotest_lib.site_utils.sponge_lib import autotest_job_info |
| |
| |
| UNKNOWN_EFFORT_NAME = 'UNKNOWN_BUILD' |
| UNKNOWN_ENV_NAME = 'UNKNOWN_BOARD' |
| |
| |
| class ACTSSummaryEnums(object): |
| """A class contains the attribute names used in a ACTS summary.""" |
| |
| Requested = 'Requested' |
| Failed = 'Failed' |
| Unknown = 'Unknown' |
| |
| |
| class ACTSRecordEnums(object): |
| """A class contains the attribute names used in an ACTS record.""" |
| |
| BeginTime = 'Begin Time' |
| Details = 'Details' |
| EndTime = 'End Time' |
| Extras = 'Extras' |
| ExtraErrors = 'Extra Errors' |
| Result = 'Result' |
| TestClass = 'Test Class' |
| TestName = 'Test Name' |
| UID = 'UID' |
| |
| |
| class ACTSTaskInfo(autotest_job_info.AutotestTaskInfo): |
| """Task info for an ACTS test.""" |
| |
| tags = autotest_job_info.AutotestTaskInfo.tags + ['acts', 'testtracker'] |
| logs = autotest_job_info.AutotestTaskInfo.logs + ['results'] |
| |
| def __init__(self, test, job): |
| """ |
| @param test: The autotest test for this ACTS test. |
| @param job: The job info that is the parent ot this task. |
| """ |
| super(ACTSTaskInfo, self).__init__(test, job) |
| |
| summary_location = os.path.join( |
| self.results_dir, 'results/latest/test_run_summary.json') |
| |
| build_info_location = os.path.join(self.results_dir, |
| 'results/BUILD_INFO-*') |
| build_info_files = glob.iglob(build_info_location) |
| |
| try: |
| build_info_file = next(build_info_files) |
| logging.info('Using build info file: %s', build_info_file) |
| with open(build_info_file) as fd: |
| self.build_info = json.load(fd) |
| except Exception as e: |
| logging.exception(e) |
| logging.error('Bad build info file.') |
| self.build_info = {} |
| |
| try: |
| build_prop_str = self.build_info['build_prop'] |
| prop_dict = {} |
| self.build_info['build_prop'] = prop_dict |
| lines = build_prop_str.splitlines() |
| for line in lines: |
| parts = line.split('=') |
| |
| if len(parts) != 2: |
| continue |
| |
| prop_dict[parts[0]] = parts[1] |
| except Exception as e: |
| logging.exception(e) |
| logging.error('Bad build prop data, using default empty dict') |
| self.build_info['build_prop'] = {} |
| |
| try: |
| with open(summary_location) as fd: |
| self._acts_summary = json.load(fd) |
| |
| self._summary_block = self._acts_summary['Summary'] |
| |
| record_block = self._acts_summary['Results'] |
| self._records = list(ACTSRecord(record) for record in record_block) |
| self.is_valid = True |
| except Exception as e: |
| logging.exception(e) |
| logging.error('Bad acts data, reverting to autotest only.') |
| self.is_valid = False |
| self.tags = autotest_job_info.AutotestTaskInfo.tags |
| |
| @property |
| def test_case_count(self): |
| """The number of test cases run.""" |
| return self._summary_block[ACTSSummaryEnums.Requested] |
| |
| @property |
| def failed_case_count(self): |
| """The number of failed test cases.""" |
| return self._summary_block[ACTSSummaryEnums.Failed] |
| |
| @property |
| def error_case_count(self): |
| """The number of errored test cases.""" |
| return self._summary_block[ACTSSummaryEnums.Unknown] |
| |
| @property |
| def records(self): |
| """All records of test cases in the ACTS tests.""" |
| return self._records |
| |
| @property |
| def owner(self): |
| """The owner of the task.""" |
| if 'param-testtracker_owner' in self.keyvals: |
| return self.keyvals['param-testtracker_owner'].strip("'").strip('"') |
| elif 'param-test_tracker_owner' in self.keyvals: |
| return self.keyvals['param-testtracker_owner'].strip("'").strip('"') |
| else: |
| return self._job.user.strip("'").strip('"') |
| |
| @property |
| def effort_name(self): |
| """The test tracker effort name.""" |
| build_id = self.build_info.get('build_prop', {}).get('ro.build.id') |
| if build_id and any(c.isdigit() for c in build_id): |
| return build_id |
| else: |
| build_version = self.build_info.get('build_prop', {}).get( |
| 'ro.build.version.incremental', UNKNOWN_EFFORT_NAME) |
| return build_version |
| |
| |
| @property |
| def project_id(self): |
| """The test tracker project id.""" |
| if 'param-testtracker_project_id' in self.keyvals: |
| return self.keyvals.get('param-testtracker_project_id') |
| else: |
| return self.keyvals.get('param-test_tracker_project_id') |
| |
| @property |
| def environment(self): |
| """The name of the enviroment for test tracker.""" |
| build_props = self.build_info.get('build_prop', {}) |
| |
| if 'ro.product.board' in build_props: |
| board = build_props['ro.product.board'] |
| elif 'ro.build.product' in build_props: |
| board = build_props['ro.build.product'] |
| else: |
| board = UNKNOWN_ENV_NAME |
| |
| return board |
| |
| @property |
| def extra_environment(self): |
| """Extra environment info about the task.""" |
| if 'param-testtracker_extra_env' in self.keyvals: |
| extra = self.keyvals.get('param-testtracker_extra_env', []) |
| else: |
| extra = self.keyvals.get('param-test_tracker_extra_env', []) |
| |
| if not isinstance(extra, list): |
| extra = [extra] |
| |
| return extra |
| |
| |
| class ACTSRecord(object): |
| """A single record of a test case in an ACTS test.""" |
| |
| tags = ['acts', 'testtracker'] |
| |
| def __init__(self, json_record): |
| """ |
| @param json_record: The json info for this record |
| """ |
| self._json_record = json_record |
| |
| @property |
| def test_class(self): |
| """The test class that was run.""" |
| return self._json_record[ACTSRecordEnums.TestClass] |
| |
| @property |
| def test_case(self): |
| """The test case that was run. None implies all in the class.""" |
| return self._json_record.get(ACTSRecordEnums.TestName) |
| |
| @property |
| def uid(self): |
| """The uid of the test case.""" |
| return self._json_record.get(ACTSRecordEnums.UID) |
| |
| @property |
| def status(self): |
| """The status of the test case.""" |
| return self._json_record[ACTSRecordEnums.Result] |
| |
| @property |
| def start_time(self): |
| """The start time of the test case.""" |
| return self._json_record[ACTSRecordEnums.BeginTime] / 1000.0 |
| |
| @property |
| def end_time(self): |
| """The end time of the test case.""" |
| return self._json_record[ACTSRecordEnums.EndTime] / 1000.0 |
| |
| @property |
| def details(self): |
| """Details about the test case.""" |
| return self._json_record.get(ACTSRecordEnums.Details) |
| |
| @property |
| def extras(self): |
| """Extra info about the test case.""" |
| return self._json_record.get(ACTSRecordEnums.Extras) |
| |
| @property |
| def extra_errors(self): |
| """Extra errors about the test case.""" |
| return self._json_record.get(ACTSRecordEnums.ExtraErrors) |
| |
| @property |
| def extra_environment(self): |
| """Extra details about the environment for this test.""" |
| extras = self.extras |
| if not extras: |
| return None |
| |
| test_tracker_info = self.extras.get('test_tracker_info') |
| if not test_tracker_info: |
| return self.extras.get('test_tracker_environment_info') |
| |
| return test_tracker_info.get('extra_environment') |
| |
| @property |
| def uuid(self): |
| """The test tracker uuid of the test case.""" |
| extras = self.extras |
| if not extras: |
| return None |
| |
| test_tracker_info = self.extras.get('test_tracker_info') |
| if not test_tracker_info: |
| return self.extras.get('test_tracker_uuid') |
| |
| return test_tracker_info.get('test_tracker_uuid') |