Home | History | Annotate | Download | only in sponge_lib
      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 
      5 import glob
      6 import json
      7 import os
      8 
      9 import logging
     10 
     11 from autotest_lib.site_utils.sponge_lib import autotest_job_info
     12 
     13 
     14 UNKNOWN_EFFORT_NAME = 'UNKNOWN_BUILD'
     15 UNKNOWN_ENV_NAME = 'UNKNOWN_BOARD'
     16 
     17 
     18 class 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 
     26 class 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 
     40 class 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 
    180 class 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