acts_job_info.py revision 54f38a41e6676c65b741932e61cf139a95efd756
1a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake# Copyright 2017 The Chromium Authors. All rights reserved. 2a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake# Use of this source code is governed by a BSD-style license that can be 3a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake# found in the LICENSE file. 40c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 50c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peakeimport glob 6a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakeimport json 7a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakeimport os 8a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 959325d258052f28b10407f8adb500e0545764388Benny Peakeimport logging 1059325d258052f28b10407f8adb500e0545764388Benny Peake 11a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakefrom autotest_lib.site_utils.sponge_lib import autotest_job_info 12a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 13a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 146ade820e4f4843cef1b6a4e086db769d6ef088edBenny PeakeUNKNOWN_EFFORT_NAME = 'UNKNOWN_BUILD' 156ade820e4f4843cef1b6a4e086db769d6ef088edBenny PeakeUNKNOWN_ENV_NAME = 'UNKNOWN_BOARD' 166ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 176ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 18a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakeclass ACTSSummaryEnums(object): 19a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """A class contains the attribute names used in a ACTS summary.""" 20a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 21a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake Requested = 'Requested' 22a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake Failed = 'Failed' 23a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake Unknown = 'Unknown' 24a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 25a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 26a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakeclass ACTSRecordEnums(object): 27a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """A class contains the attribute names used in an ACTS record.""" 28a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 29a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake BeginTime = 'Begin Time' 30a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake Details = 'Details' 31a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake EndTime = 'End Time' 32a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake Extras = 'Extras' 33a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake ExtraErrors = 'Extra Errors' 34a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake Result = 'Result' 35a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake TestClass = 'Test Class' 36a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake TestName = 'Test Name' 37a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake UID = 'UID' 38a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 39a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 40a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakeclass ACTSTaskInfo(autotest_job_info.AutotestTaskInfo): 41a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """Task info for an ACTS test.""" 42a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 43a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake tags = autotest_job_info.AutotestTaskInfo.tags + ['acts', 'testtracker'] 44a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake logs = autotest_job_info.AutotestTaskInfo.logs + ['results'] 45a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 46a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def __init__(self, test, job): 47a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """ 48a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @param test: The autotest test for this ACTS test. 49a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @param job: The job info that is the parent ot this task. 50a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """ 51a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake super(ACTSTaskInfo, self).__init__(test, job) 52a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 53a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake summary_location = os.path.join( 540c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake self.results_dir, 'results/latest/test_run_summary.json') 550c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 560c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake build_info_location = os.path.join(self.results_dir, 570c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 'results/BUILD_INFO-*') 580c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake build_info_files = glob.iglob(build_info_location) 590c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 600c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake try: 610c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake build_info_file = next(build_info_files) 620c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake logging.info('Using build info file: %s', build_info_file) 630c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake with open(build_info_file) as fd: 640c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake self.build_info = json.load(fd) 650c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake except Exception as e: 660c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake logging.exception(e) 670c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake logging.error('Bad build info file.') 680c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake self.build_info = {} 690c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 700c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake try: 710c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake build_prop_str = self.build_info['build_prop'] 720c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake prop_dict = {} 730c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake self.build_info['build_prop'] = prop_dict 740c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake lines = build_prop_str.splitlines() 750c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake for line in lines: 760c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake parts = line.split('=') 770c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 780c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake if len(parts) != 2: 790c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake continue 800c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake 810c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake prop_dict[parts[0]] = parts[1] 820c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake except Exception as e: 830c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake logging.exception(e) 840c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake logging.error('Bad build prop data, using default empty dict') 850c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake self.build_info['build_prop'] = {} 86a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 8759325d258052f28b10407f8adb500e0545764388Benny Peake try: 8859325d258052f28b10407f8adb500e0545764388Benny Peake with open(summary_location) as fd: 8959325d258052f28b10407f8adb500e0545764388Benny Peake self._acts_summary = json.load(fd) 90a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 9159325d258052f28b10407f8adb500e0545764388Benny Peake self._summary_block = self._acts_summary['Summary'] 92a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 9359325d258052f28b10407f8adb500e0545764388Benny Peake record_block = self._acts_summary['Results'] 9459325d258052f28b10407f8adb500e0545764388Benny Peake self._records = list(ACTSRecord(record) for record in record_block) 9559325d258052f28b10407f8adb500e0545764388Benny Peake self.is_valid = True 9659325d258052f28b10407f8adb500e0545764388Benny Peake except Exception as e: 970c4bbc47993f20b8d17a1f39d1d1b621ce6b8b6eBenny Peake logging.exception(e) 9859325d258052f28b10407f8adb500e0545764388Benny Peake logging.error('Bad acts data, reverting to autotest only.') 9959325d258052f28b10407f8adb500e0545764388Benny Peake self.is_valid = False 10059325d258052f28b10407f8adb500e0545764388Benny Peake self.tags = autotest_job_info.AutotestTaskInfo.tags 101a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 102a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 103a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def test_case_count(self): 104a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The number of test cases run.""" 105a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._summary_block[ACTSSummaryEnums.Requested] 106a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 107a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 108a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def failed_case_count(self): 109a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The number of failed test cases.""" 110a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._summary_block[ACTSSummaryEnums.Failed] 111a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 112a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 113a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def error_case_count(self): 114a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The number of errored test cases.""" 115a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._summary_block[ACTSSummaryEnums.Unknown] 116a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 117a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 118a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def records(self): 119a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """All records of test cases in the ACTS tests.""" 120a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._records 121a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 122a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 123a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def effort_name(self): 124a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The test tracker effort name.""" 1256ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake build_id = self.build_info.get('build_prop', {}).get('ro.build.id') 1266ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake if build_id and any(c.isdigit() for c in build_id): 1276ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return build_id 1286ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake else: 1296ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake build_version = self.build_info.get('build_prop', {}).get( 1306ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 'ro.build.version.incremental', UNKNOWN_EFFORT_NAME) 1316ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return build_version 1326ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 133a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 134a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 135a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def project_id(self): 136a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The test tracker project id.""" 13745fa8a3818e928bd232ddb9bab6f2fc5f6d83681Benny Peake if 'param-testtracker_project_id' in self.keyvals: 1386ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self.keyvals.get('param-testtracker_project_id') 13945fa8a3818e928bd232ddb9bab6f2fc5f6d83681Benny Peake else: 1406ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self.keyvals.get('param-test_tracker_project_id') 141a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 142a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 143a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def environment(self): 144a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The name of the enviroment for test tracker.""" 1456ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self.build_info.get('build_prop', {}).get('ro.product.board', 1466ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake UNKNOWN_ENV_NAME) 147a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 14854f38a41e6676c65b741932e61cf139a95efd756Benny Peake @property 14954f38a41e6676c65b741932e61cf139a95efd756Benny Peake def extra_environment(self): 15054f38a41e6676c65b741932e61cf139a95efd756Benny Peake """Extra environment info about the task.""" 15154f38a41e6676c65b741932e61cf139a95efd756Benny Peake if 'param-testtracker_extra_env' in self.keyvals: 15254f38a41e6676c65b741932e61cf139a95efd756Benny Peake extra = self.keyvals.get('param-testtracker_extra_env', []) 15354f38a41e6676c65b741932e61cf139a95efd756Benny Peake else: 15454f38a41e6676c65b741932e61cf139a95efd756Benny Peake extra = self.keyvals.get('param-testtracker_extra_env', []) 15554f38a41e6676c65b741932e61cf139a95efd756Benny Peake 15654f38a41e6676c65b741932e61cf139a95efd756Benny Peake if not isinstance(extra, list): 15754f38a41e6676c65b741932e61cf139a95efd756Benny Peake extra = [extra] 15854f38a41e6676c65b741932e61cf139a95efd756Benny Peake 15954f38a41e6676c65b741932e61cf139a95efd756Benny Peake return extra 16054f38a41e6676c65b741932e61cf139a95efd756Benny Peake 161a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 162a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peakeclass ACTSRecord(object): 163a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """A single record of a test case in an ACTS test.""" 164a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 165a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake tags = ['acts', 'testtracker'] 166a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 167a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def __init__(self, json_record): 168a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """ 169a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @param json_record: The json info for this record 170a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """ 171a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake self._json_record = json_record 172a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 173a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 174a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def test_class(self): 175a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The test class that was run.""" 176a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._json_record[ACTSRecordEnums.TestClass] 177a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 178a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 179a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def test_case(self): 180a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The test case that was run. None implies all in the class.""" 1816ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self._json_record.get(ACTSRecordEnums.TestName) 182a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 183a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 184a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def uid(self): 185a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The uid of the test case.""" 1866ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self._json_record.get(ACTSRecordEnums.UID) 187a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 188a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 189a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def status(self): 190a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The status of the test case.""" 191a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._json_record[ACTSRecordEnums.Result] 192a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 193a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 194a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def start_time(self): 195a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The start time of the test case.""" 196a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._json_record[ACTSRecordEnums.BeginTime] / 1000.0 197a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 198a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 199a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def end_time(self): 200a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The end time of the test case.""" 201a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return self._json_record[ACTSRecordEnums.EndTime] / 1000.0 202a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 203a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 204a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def details(self): 205a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """Details about the test case.""" 2066ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self._json_record.get(ACTSRecordEnums.Details) 207a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 208a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 209a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def extras(self): 210a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """Extra info about the test case.""" 2116ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self._json_record.get(ACTSRecordEnums.Extras) 212a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 213a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 214a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def extra_errors(self): 215a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """Extra errors about the test case.""" 2166ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self._json_record.get(ACTSRecordEnums.ExtraErrors) 2176ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 2186ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake @property 2196ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake def extra_environment(self): 2206ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake """Extra details about the environment for this test.""" 2216ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake extras = self.extras 2226ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake if not extras: 2236ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return None 2246ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 2256ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake test_tracker_info = self.extras.get('test_tracker_info') 2266ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake if not test_tracker_info: 2276ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self.extras.get('test_tracker_environment_info') 2286ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake 2296ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return test_tracker_info.get('extra_environment') 230a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 231a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake @property 232a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake def uuid(self): 233a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake """The test tracker uuid of the test case.""" 234a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake extras = self.extras 235a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake if not extras: 236a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake return None 237a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 2386ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake test_tracker_info = self.extras.get('test_tracker_info') 239a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake if not test_tracker_info: 2406ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return self.extras.get('test_tracker_uuid') 241a6bcf7f18aded465d734820b73eef14a5ec10d46Benny Peake 2426ade820e4f4843cef1b6a4e086db769d6ef088edBenny Peake return test_tracker_info.get('test_tracker_uuid') 243