1*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2019, The Android Open Source Project 2*c2e18aaaSAndroid Build Coastguard Worker# 3*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*c2e18aaaSAndroid Build Coastguard Worker# 7*c2e18aaaSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*c2e18aaaSAndroid Build Coastguard Worker# 9*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License. 14*c2e18aaaSAndroid Build Coastguard Worker 15*c2e18aaaSAndroid Build Coastguard Worker"""Atest test event handler class.""" 16*c2e18aaaSAndroid Build Coastguard Worker 17*c2e18aaaSAndroid Build Coastguard Workerfrom __future__ import print_function 18*c2e18aaaSAndroid Build Coastguard Worker 19*c2e18aaaSAndroid Build Coastguard Workerfrom collections import deque 20*c2e18aaaSAndroid Build Coastguard Workerfrom datetime import timedelta 21*c2e18aaaSAndroid Build Coastguard Workerimport logging 22*c2e18aaaSAndroid Build Coastguard Workerimport time 23*c2e18aaaSAndroid Build Coastguard Worker 24*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_execution_info 25*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_utils 26*c2e18aaaSAndroid Build Coastguard Workerfrom atest import result_reporter 27*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_runners import test_runner_base 28*c2e18aaaSAndroid Build Coastguard Worker 29*c2e18aaaSAndroid Build Coastguard Worker 30*c2e18aaaSAndroid Build Coastguard WorkerEVENT_NAMES = { 31*c2e18aaaSAndroid Build Coastguard Worker 'module_started': 'TEST_MODULE_STARTED', 32*c2e18aaaSAndroid Build Coastguard Worker 'module_ended': 'TEST_MODULE_ENDED', 33*c2e18aaaSAndroid Build Coastguard Worker 'run_started': 'TEST_RUN_STARTED', 34*c2e18aaaSAndroid Build Coastguard Worker 'run_ended': 'TEST_RUN_ENDED', 35*c2e18aaaSAndroid Build Coastguard Worker # Next three are test-level events 36*c2e18aaaSAndroid Build Coastguard Worker 'test_started': 'TEST_STARTED', 37*c2e18aaaSAndroid Build Coastguard Worker 'test_failed': 'TEST_FAILED', 38*c2e18aaaSAndroid Build Coastguard Worker 'test_ended': 'TEST_ENDED', 39*c2e18aaaSAndroid Build Coastguard Worker 'invocation_ended': 'INVOCATION_ENDED', 40*c2e18aaaSAndroid Build Coastguard Worker # Last two failures are runner-level, not test-level. 41*c2e18aaaSAndroid Build Coastguard Worker # Invocation failure is broader than run failure. 42*c2e18aaaSAndroid Build Coastguard Worker 'run_failed': 'TEST_RUN_FAILED', 43*c2e18aaaSAndroid Build Coastguard Worker 'invocation_failed': 'INVOCATION_FAILED', 44*c2e18aaaSAndroid Build Coastguard Worker 'test_ignored': 'TEST_IGNORED', 45*c2e18aaaSAndroid Build Coastguard Worker 'test_assumption_failure': 'TEST_ASSUMPTION_FAILURE', 46*c2e18aaaSAndroid Build Coastguard Worker 'log_association': 'LOG_ASSOCIATION', 47*c2e18aaaSAndroid Build Coastguard Worker} 48*c2e18aaaSAndroid Build Coastguard Worker 49*c2e18aaaSAndroid Build Coastguard WorkerEVENT_PAIRS = { 50*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['module_started']: EVENT_NAMES['module_ended'], 51*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['run_started']: EVENT_NAMES['run_ended'], 52*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['test_started']: EVENT_NAMES['test_ended'], 53*c2e18aaaSAndroid Build Coastguard Worker} 54*c2e18aaaSAndroid Build Coastguard WorkerSTART_EVENTS = list(EVENT_PAIRS.keys()) 55*c2e18aaaSAndroid Build Coastguard WorkerEND_EVENTS = list(EVENT_PAIRS.values()) 56*c2e18aaaSAndroid Build Coastguard WorkerTEST_NAME_TEMPLATE = '%s#%s' 57*c2e18aaaSAndroid Build Coastguard Worker 58*c2e18aaaSAndroid Build Coastguard Worker# time in millisecond. 59*c2e18aaaSAndroid Build Coastguard WorkerONE_SECOND = 1000 60*c2e18aaaSAndroid Build Coastguard WorkerONE_MINUTE = 60000 61*c2e18aaaSAndroid Build Coastguard WorkerONE_HOUR = 3600000 62*c2e18aaaSAndroid Build Coastguard Worker 63*c2e18aaaSAndroid Build Coastguard WorkerCONNECTION_STATE = { 64*c2e18aaaSAndroid Build Coastguard Worker 'current_test': None, 65*c2e18aaaSAndroid Build Coastguard Worker 'test_run_name': None, 66*c2e18aaaSAndroid Build Coastguard Worker 'last_failed': None, 67*c2e18aaaSAndroid Build Coastguard Worker 'last_ignored': None, 68*c2e18aaaSAndroid Build Coastguard Worker 'last_assumption_failed': None, 69*c2e18aaaSAndroid Build Coastguard Worker 'current_group': None, 70*c2e18aaaSAndroid Build Coastguard Worker 'current_group_total': None, 71*c2e18aaaSAndroid Build Coastguard Worker 'test_count': 0, 72*c2e18aaaSAndroid Build Coastguard Worker 'test_start_time': None, 73*c2e18aaaSAndroid Build Coastguard Worker} 74*c2e18aaaSAndroid Build Coastguard Worker 75*c2e18aaaSAndroid Build Coastguard Worker 76*c2e18aaaSAndroid Build Coastguard Workerclass EventHandleError(Exception): 77*c2e18aaaSAndroid Build Coastguard Worker """Raised when handle event error.""" 78*c2e18aaaSAndroid Build Coastguard Worker 79*c2e18aaaSAndroid Build Coastguard Worker 80*c2e18aaaSAndroid Build Coastguard Workerclass EventHandler: 81*c2e18aaaSAndroid Build Coastguard Worker """Test Event handle class.""" 82*c2e18aaaSAndroid Build Coastguard Worker 83*c2e18aaaSAndroid Build Coastguard Worker def __init__(self, reporter, name): 84*c2e18aaaSAndroid Build Coastguard Worker self.reporter = reporter 85*c2e18aaaSAndroid Build Coastguard Worker self.runner_name = name 86*c2e18aaaSAndroid Build Coastguard Worker self.state = CONNECTION_STATE.copy() 87*c2e18aaaSAndroid Build Coastguard Worker self.event_stack = deque() 88*c2e18aaaSAndroid Build Coastguard Worker self.log_associations = [] 89*c2e18aaaSAndroid Build Coastguard Worker self.run_num = 0 90*c2e18aaaSAndroid Build Coastguard Worker 91*c2e18aaaSAndroid Build Coastguard Worker def _module_started(self, event_data): 92*c2e18aaaSAndroid Build Coastguard Worker if atest_execution_info.PREPARE_END_TIME is None: 93*c2e18aaaSAndroid Build Coastguard Worker atest_execution_info.PREPARE_END_TIME = time.time() 94*c2e18aaaSAndroid Build Coastguard Worker self.state['current_group'] = event_data['moduleName'] 95*c2e18aaaSAndroid Build Coastguard Worker self.state['last_failed'] = None 96*c2e18aaaSAndroid Build Coastguard Worker self.state['current_test'] = None 97*c2e18aaaSAndroid Build Coastguard Worker 98*c2e18aaaSAndroid Build Coastguard Worker def _run_started(self, event_data): 99*c2e18aaaSAndroid Build Coastguard Worker # Technically there can be more than one run per module. 100*c2e18aaaSAndroid Build Coastguard Worker self.run_num = event_data.get('runAttempt', 0) 101*c2e18aaaSAndroid Build Coastguard Worker self.state['test_run_name'] = event_data.setdefault('runName', '') 102*c2e18aaaSAndroid Build Coastguard Worker self.state['current_group_total'] = event_data['testCount'] 103*c2e18aaaSAndroid Build Coastguard Worker self.state['test_count'] = 0 104*c2e18aaaSAndroid Build Coastguard Worker self.state['last_failed'] = None 105*c2e18aaaSAndroid Build Coastguard Worker self.state['current_test'] = None 106*c2e18aaaSAndroid Build Coastguard Worker 107*c2e18aaaSAndroid Build Coastguard Worker def _test_started(self, event_data): 108*c2e18aaaSAndroid Build Coastguard Worker name = TEST_NAME_TEMPLATE % ( 109*c2e18aaaSAndroid Build Coastguard Worker event_data['className'], 110*c2e18aaaSAndroid Build Coastguard Worker event_data['testName'], 111*c2e18aaaSAndroid Build Coastguard Worker ) 112*c2e18aaaSAndroid Build Coastguard Worker self.state['current_test'] = name 113*c2e18aaaSAndroid Build Coastguard Worker self.state['test_count'] += 1 114*c2e18aaaSAndroid Build Coastguard Worker self.state['test_start_time'] = event_data['start_time'] 115*c2e18aaaSAndroid Build Coastguard Worker 116*c2e18aaaSAndroid Build Coastguard Worker def _test_failed(self, event_data): 117*c2e18aaaSAndroid Build Coastguard Worker self.state['last_failed'] = { 118*c2e18aaaSAndroid Build Coastguard Worker 'name': TEST_NAME_TEMPLATE % ( 119*c2e18aaaSAndroid Build Coastguard Worker event_data['className'], 120*c2e18aaaSAndroid Build Coastguard Worker event_data['testName'], 121*c2e18aaaSAndroid Build Coastguard Worker ), 122*c2e18aaaSAndroid Build Coastguard Worker 'trace': event_data['trace'], 123*c2e18aaaSAndroid Build Coastguard Worker } 124*c2e18aaaSAndroid Build Coastguard Worker 125*c2e18aaaSAndroid Build Coastguard Worker def _test_ignored(self, event_data): 126*c2e18aaaSAndroid Build Coastguard Worker name = TEST_NAME_TEMPLATE % ( 127*c2e18aaaSAndroid Build Coastguard Worker event_data['className'], 128*c2e18aaaSAndroid Build Coastguard Worker event_data['testName'], 129*c2e18aaaSAndroid Build Coastguard Worker ) 130*c2e18aaaSAndroid Build Coastguard Worker self.state['last_ignored'] = name 131*c2e18aaaSAndroid Build Coastguard Worker 132*c2e18aaaSAndroid Build Coastguard Worker def _test_assumption_failure(self, event_data): 133*c2e18aaaSAndroid Build Coastguard Worker name = TEST_NAME_TEMPLATE % ( 134*c2e18aaaSAndroid Build Coastguard Worker event_data['className'], 135*c2e18aaaSAndroid Build Coastguard Worker event_data['testName'], 136*c2e18aaaSAndroid Build Coastguard Worker ) 137*c2e18aaaSAndroid Build Coastguard Worker self.state['last_assumption_failed'] = name 138*c2e18aaaSAndroid Build Coastguard Worker 139*c2e18aaaSAndroid Build Coastguard Worker def _run_failed(self, event_data): 140*c2e18aaaSAndroid Build Coastguard Worker # Module and Test Run probably started, but failure occurred. 141*c2e18aaaSAndroid Build Coastguard Worker self.reporter.process_test_result( 142*c2e18aaaSAndroid Build Coastguard Worker test_runner_base.TestResult( 143*c2e18aaaSAndroid Build Coastguard Worker runner_name=self.runner_name, 144*c2e18aaaSAndroid Build Coastguard Worker group_name=self.state['current_group'], 145*c2e18aaaSAndroid Build Coastguard Worker test_name=self.state['current_test'], 146*c2e18aaaSAndroid Build Coastguard Worker status=test_runner_base.ERROR_STATUS, 147*c2e18aaaSAndroid Build Coastguard Worker details=event_data['reason'], 148*c2e18aaaSAndroid Build Coastguard Worker test_count=self.state['test_count'], 149*c2e18aaaSAndroid Build Coastguard Worker test_time='', 150*c2e18aaaSAndroid Build Coastguard Worker runner_total=None, 151*c2e18aaaSAndroid Build Coastguard Worker group_total=self.state['current_group_total'], 152*c2e18aaaSAndroid Build Coastguard Worker additional_info={}, 153*c2e18aaaSAndroid Build Coastguard Worker test_run_name=self.state['test_run_name'], 154*c2e18aaaSAndroid Build Coastguard Worker ) 155*c2e18aaaSAndroid Build Coastguard Worker ) 156*c2e18aaaSAndroid Build Coastguard Worker 157*c2e18aaaSAndroid Build Coastguard Worker def _invocation_failed(self, event_data): 158*c2e18aaaSAndroid Build Coastguard Worker # Broadest possible failure. May not even start the module/test run. 159*c2e18aaaSAndroid Build Coastguard Worker self.reporter.process_test_result( 160*c2e18aaaSAndroid Build Coastguard Worker test_runner_base.TestResult( 161*c2e18aaaSAndroid Build Coastguard Worker runner_name=self.runner_name, 162*c2e18aaaSAndroid Build Coastguard Worker group_name=self.state['current_group'], 163*c2e18aaaSAndroid Build Coastguard Worker test_name=self.state['current_test'], 164*c2e18aaaSAndroid Build Coastguard Worker status=test_runner_base.ERROR_STATUS, 165*c2e18aaaSAndroid Build Coastguard Worker details=event_data['cause'], 166*c2e18aaaSAndroid Build Coastguard Worker test_count=self.state['test_count'], 167*c2e18aaaSAndroid Build Coastguard Worker test_time='', 168*c2e18aaaSAndroid Build Coastguard Worker runner_total=None, 169*c2e18aaaSAndroid Build Coastguard Worker group_total=self.state['current_group_total'], 170*c2e18aaaSAndroid Build Coastguard Worker additional_info={}, 171*c2e18aaaSAndroid Build Coastguard Worker test_run_name=self.state['test_run_name'], 172*c2e18aaaSAndroid Build Coastguard Worker ) 173*c2e18aaaSAndroid Build Coastguard Worker ) 174*c2e18aaaSAndroid Build Coastguard Worker 175*c2e18aaaSAndroid Build Coastguard Worker def _invocation_ended(self, event_data): 176*c2e18aaaSAndroid Build Coastguard Worker self.reporter.device_count = event_data.get('device_count', None) 177*c2e18aaaSAndroid Build Coastguard Worker 178*c2e18aaaSAndroid Build Coastguard Worker # pylint: disable=unused-argument 179*c2e18aaaSAndroid Build Coastguard Worker def _run_ended(self, event_data): 180*c2e18aaaSAndroid Build Coastguard Worker # Renew ResultReport if is module level(reporter.silent=False) 181*c2e18aaaSAndroid Build Coastguard Worker if not self.reporter.silent: 182*c2e18aaaSAndroid Build Coastguard Worker self.reporter.set_current_iteration_summary(self.run_num) 183*c2e18aaaSAndroid Build Coastguard Worker self.reporter = result_reporter.ResultReporter(silent=False) 184*c2e18aaaSAndroid Build Coastguard Worker 185*c2e18aaaSAndroid Build Coastguard Worker def _module_ended(self, event_data): 186*c2e18aaaSAndroid Build Coastguard Worker pass 187*c2e18aaaSAndroid Build Coastguard Worker 188*c2e18aaaSAndroid Build Coastguard Worker def _test_ended(self, event_data): 189*c2e18aaaSAndroid Build Coastguard Worker name = TEST_NAME_TEMPLATE % ( 190*c2e18aaaSAndroid Build Coastguard Worker event_data['className'], 191*c2e18aaaSAndroid Build Coastguard Worker event_data['testName'], 192*c2e18aaaSAndroid Build Coastguard Worker ) 193*c2e18aaaSAndroid Build Coastguard Worker test_time = '' 194*c2e18aaaSAndroid Build Coastguard Worker if self.state['test_start_time']: 195*c2e18aaaSAndroid Build Coastguard Worker test_time = self._calc_duration( 196*c2e18aaaSAndroid Build Coastguard Worker event_data['end_time'] - self.state['test_start_time'] 197*c2e18aaaSAndroid Build Coastguard Worker ) 198*c2e18aaaSAndroid Build Coastguard Worker if self.state['last_failed'] and name == self.state['last_failed']['name']: 199*c2e18aaaSAndroid Build Coastguard Worker status = test_runner_base.FAILED_STATUS 200*c2e18aaaSAndroid Build Coastguard Worker trace = self.state['last_failed']['trace'] 201*c2e18aaaSAndroid Build Coastguard Worker self.state['last_failed'] = None 202*c2e18aaaSAndroid Build Coastguard Worker elif ( 203*c2e18aaaSAndroid Build Coastguard Worker self.state['last_assumption_failed'] 204*c2e18aaaSAndroid Build Coastguard Worker and name == self.state['last_assumption_failed'] 205*c2e18aaaSAndroid Build Coastguard Worker ): 206*c2e18aaaSAndroid Build Coastguard Worker status = test_runner_base.ASSUMPTION_FAILED 207*c2e18aaaSAndroid Build Coastguard Worker self.state['last_assumption_failed'] = None 208*c2e18aaaSAndroid Build Coastguard Worker trace = None 209*c2e18aaaSAndroid Build Coastguard Worker elif self.state['last_ignored'] and name == self.state['last_ignored']: 210*c2e18aaaSAndroid Build Coastguard Worker status = test_runner_base.IGNORED_STATUS 211*c2e18aaaSAndroid Build Coastguard Worker self.state['last_ignored'] = None 212*c2e18aaaSAndroid Build Coastguard Worker trace = None 213*c2e18aaaSAndroid Build Coastguard Worker else: 214*c2e18aaaSAndroid Build Coastguard Worker status = test_runner_base.PASSED_STATUS 215*c2e18aaaSAndroid Build Coastguard Worker trace = None 216*c2e18aaaSAndroid Build Coastguard Worker 217*c2e18aaaSAndroid Build Coastguard Worker default_event_keys = ['className', 'end_time', 'testName'] 218*c2e18aaaSAndroid Build Coastguard Worker additional_info = {} 219*c2e18aaaSAndroid Build Coastguard Worker for event_key in event_data.keys(): 220*c2e18aaaSAndroid Build Coastguard Worker if event_key not in default_event_keys: 221*c2e18aaaSAndroid Build Coastguard Worker additional_info[event_key] = event_data.get(event_key, None) 222*c2e18aaaSAndroid Build Coastguard Worker 223*c2e18aaaSAndroid Build Coastguard Worker self.reporter.process_test_result( 224*c2e18aaaSAndroid Build Coastguard Worker test_runner_base.TestResult( 225*c2e18aaaSAndroid Build Coastguard Worker runner_name=self.runner_name, 226*c2e18aaaSAndroid Build Coastguard Worker group_name=self.state['current_group'], 227*c2e18aaaSAndroid Build Coastguard Worker test_name=name, 228*c2e18aaaSAndroid Build Coastguard Worker status=status, 229*c2e18aaaSAndroid Build Coastguard Worker details=trace, 230*c2e18aaaSAndroid Build Coastguard Worker test_count=self.state['test_count'], 231*c2e18aaaSAndroid Build Coastguard Worker test_time=test_time, 232*c2e18aaaSAndroid Build Coastguard Worker runner_total=None, 233*c2e18aaaSAndroid Build Coastguard Worker additional_info=additional_info, 234*c2e18aaaSAndroid Build Coastguard Worker group_total=self.state['current_group_total'], 235*c2e18aaaSAndroid Build Coastguard Worker test_run_name=self.state['test_run_name'], 236*c2e18aaaSAndroid Build Coastguard Worker ) 237*c2e18aaaSAndroid Build Coastguard Worker ) 238*c2e18aaaSAndroid Build Coastguard Worker 239*c2e18aaaSAndroid Build Coastguard Worker def _log_association(self, event_data): 240*c2e18aaaSAndroid Build Coastguard Worker event_data.setdefault('time', time.time()) 241*c2e18aaaSAndroid Build Coastguard Worker self.log_associations.append(event_data) 242*c2e18aaaSAndroid Build Coastguard Worker 243*c2e18aaaSAndroid Build Coastguard Worker switch_handler = { 244*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['module_started']: _module_started, 245*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['run_started']: _run_started, 246*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['test_started']: _test_started, 247*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['test_failed']: _test_failed, 248*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['test_ignored']: _test_ignored, 249*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['test_assumption_failure']: _test_assumption_failure, 250*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['run_failed']: _run_failed, 251*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['invocation_failed']: _invocation_failed, 252*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['invocation_ended']: _invocation_ended, 253*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['test_ended']: _test_ended, 254*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['run_ended']: _run_ended, 255*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['module_ended']: _module_ended, 256*c2e18aaaSAndroid Build Coastguard Worker EVENT_NAMES['log_association']: _log_association, 257*c2e18aaaSAndroid Build Coastguard Worker } 258*c2e18aaaSAndroid Build Coastguard Worker 259*c2e18aaaSAndroid Build Coastguard Worker def process_event(self, event_name, event_data): 260*c2e18aaaSAndroid Build Coastguard Worker """Process the events of the test run and call reporter with results. 261*c2e18aaaSAndroid Build Coastguard Worker 262*c2e18aaaSAndroid Build Coastguard Worker Args: 263*c2e18aaaSAndroid Build Coastguard Worker event_name: A string of the event name. 264*c2e18aaaSAndroid Build Coastguard Worker event_data: A dict of event data. 265*c2e18aaaSAndroid Build Coastguard Worker """ 266*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Processing %s %s', event_name, event_data) 267*c2e18aaaSAndroid Build Coastguard Worker if event_name in START_EVENTS: 268*c2e18aaaSAndroid Build Coastguard Worker self.event_stack.append(event_name) 269*c2e18aaaSAndroid Build Coastguard Worker elif event_name in END_EVENTS: 270*c2e18aaaSAndroid Build Coastguard Worker self._check_events_are_balanced(event_name, self.reporter, event_data) 271*c2e18aaaSAndroid Build Coastguard Worker if event_name in self.switch_handler: 272*c2e18aaaSAndroid Build Coastguard Worker self.switch_handler[event_name](self, event_data) 273*c2e18aaaSAndroid Build Coastguard Worker else: 274*c2e18aaaSAndroid Build Coastguard Worker # TODO(b/128875503): Implement the mechanism to inform not handled 275*c2e18aaaSAndroid Build Coastguard Worker # TF event. 276*c2e18aaaSAndroid Build Coastguard Worker logging.debug('Event[%s] is not processable.', event_name) 277*c2e18aaaSAndroid Build Coastguard Worker 278*c2e18aaaSAndroid Build Coastguard Worker def _check_events_are_balanced( 279*c2e18aaaSAndroid Build Coastguard Worker self, end_event_name, reporter, end_event_data 280*c2e18aaaSAndroid Build Coastguard Worker ): 281*c2e18aaaSAndroid Build Coastguard Worker """Check whether the Start events and End events are balanced. 282*c2e18aaaSAndroid Build Coastguard Worker 283*c2e18aaaSAndroid Build Coastguard Worker When imbalance events are detected, and we understand the case of imbalance, 284*c2e18aaaSAndroid Build Coastguard Worker the events will handled without throwing error; otherwise EventHandleError 285*c2e18aaaSAndroid Build Coastguard Worker will raise. 286*c2e18aaaSAndroid Build Coastguard Worker 287*c2e18aaaSAndroid Build Coastguard Worker Args: 288*c2e18aaaSAndroid Build Coastguard Worker end_event_name: A string of the event name. 289*c2e18aaaSAndroid Build Coastguard Worker reporter: A ResultReporter instance. 290*c2e18aaaSAndroid Build Coastguard Worker end_event_data: A dict of event data. 291*c2e18aaaSAndroid Build Coastguard Worker 292*c2e18aaaSAndroid Build Coastguard Worker Raises: 293*c2e18aaaSAndroid Build Coastguard Worker EventHandleError if we can't handle the imbalance of START/END events. 294*c2e18aaaSAndroid Build Coastguard Worker """ 295*c2e18aaaSAndroid Build Coastguard Worker start_event = self.event_stack.pop() if self.event_stack else None 296*c2e18aaaSAndroid Build Coastguard Worker 297*c2e18aaaSAndroid Build Coastguard Worker def _handle_crashed_test(message): 298*c2e18aaaSAndroid Build Coastguard Worker atest_utils.print_and_log_error(message) 299*c2e18aaaSAndroid Build Coastguard Worker 300*c2e18aaaSAndroid Build Coastguard Worker self.reporter.process_test_result( 301*c2e18aaaSAndroid Build Coastguard Worker test_runner_base.TestResult( 302*c2e18aaaSAndroid Build Coastguard Worker runner_name=self.runner_name, 303*c2e18aaaSAndroid Build Coastguard Worker group_name=self.state['current_group'], 304*c2e18aaaSAndroid Build Coastguard Worker test_name=self.state['current_test'], 305*c2e18aaaSAndroid Build Coastguard Worker status=test_runner_base.ERROR_STATUS, 306*c2e18aaaSAndroid Build Coastguard Worker details=message, 307*c2e18aaaSAndroid Build Coastguard Worker test_count=self.state['test_count'], 308*c2e18aaaSAndroid Build Coastguard Worker test_time='', 309*c2e18aaaSAndroid Build Coastguard Worker runner_total=None, 310*c2e18aaaSAndroid Build Coastguard Worker group_total=self.state['current_group_total'], 311*c2e18aaaSAndroid Build Coastguard Worker additional_info={}, 312*c2e18aaaSAndroid Build Coastguard Worker test_run_name=self.state['test_run_name'], 313*c2e18aaaSAndroid Build Coastguard Worker ) 314*c2e18aaaSAndroid Build Coastguard Worker ) 315*c2e18aaaSAndroid Build Coastguard Worker 316*c2e18aaaSAndroid Build Coastguard Worker if not start_event or EVENT_PAIRS[start_event] != end_event_name: 317*c2e18aaaSAndroid Build Coastguard Worker # Here bubble up the failed trace in the situation having 318*c2e18aaaSAndroid Build Coastguard Worker # TEST_FAILED but never receiving TEST_ENDED. 319*c2e18aaaSAndroid Build Coastguard Worker if self.state['last_failed'] and ( 320*c2e18aaaSAndroid Build Coastguard Worker start_event == EVENT_NAMES['test_started'] 321*c2e18aaaSAndroid Build Coastguard Worker ): 322*c2e18aaaSAndroid Build Coastguard Worker self.reporter.process_test_result( 323*c2e18aaaSAndroid Build Coastguard Worker test_runner_base.TestResult( 324*c2e18aaaSAndroid Build Coastguard Worker runner_name=self.runner_name, 325*c2e18aaaSAndroid Build Coastguard Worker group_name=self.state['current_group'], 326*c2e18aaaSAndroid Build Coastguard Worker test_name=self.state['last_failed']['name'], 327*c2e18aaaSAndroid Build Coastguard Worker status=test_runner_base.FAILED_STATUS, 328*c2e18aaaSAndroid Build Coastguard Worker details=self.state['last_failed']['trace'], 329*c2e18aaaSAndroid Build Coastguard Worker test_count=self.state['test_count'], 330*c2e18aaaSAndroid Build Coastguard Worker test_time='', 331*c2e18aaaSAndroid Build Coastguard Worker runner_total=None, 332*c2e18aaaSAndroid Build Coastguard Worker group_total=self.state['current_group_total'], 333*c2e18aaaSAndroid Build Coastguard Worker additional_info={}, 334*c2e18aaaSAndroid Build Coastguard Worker test_run_name=self.state['test_run_name'], 335*c2e18aaaSAndroid Build Coastguard Worker ) 336*c2e18aaaSAndroid Build Coastguard Worker ) 337*c2e18aaaSAndroid Build Coastguard Worker # Even though we have proceessed the test result here, we still consider 338*c2e18aaaSAndroid Build Coastguard Worker # this case unhandled as we don't have a full understanding about the cause. 339*c2e18aaaSAndroid Build Coastguard Worker # So we don't return here. 340*c2e18aaaSAndroid Build Coastguard Worker raise EventHandleError( 341*c2e18aaaSAndroid Build Coastguard Worker 'Error: Test failed without receiving a test end event' 342*c2e18aaaSAndroid Build Coastguard Worker ) 343*c2e18aaaSAndroid Build Coastguard Worker elif ( 344*c2e18aaaSAndroid Build Coastguard Worker end_event_name == EVENT_NAMES['module_ended'] 345*c2e18aaaSAndroid Build Coastguard Worker and start_event == EVENT_NAMES['run_started'] 346*c2e18aaaSAndroid Build Coastguard Worker ): 347*c2e18aaaSAndroid Build Coastguard Worker _handle_crashed_test( 348*c2e18aaaSAndroid Build Coastguard Worker 'Test run started but did not end. This often happens when the test' 349*c2e18aaaSAndroid Build Coastguard Worker ' binary/app such as android instrumentation app process died.' 350*c2e18aaaSAndroid Build Coastguard Worker ' Test count might be inaccurate.' 351*c2e18aaaSAndroid Build Coastguard Worker ) 352*c2e18aaaSAndroid Build Coastguard Worker return 353*c2e18aaaSAndroid Build Coastguard Worker elif ( 354*c2e18aaaSAndroid Build Coastguard Worker end_event_name == EVENT_NAMES['run_ended'] 355*c2e18aaaSAndroid Build Coastguard Worker and start_event == EVENT_NAMES['test_started'] 356*c2e18aaaSAndroid Build Coastguard Worker ): 357*c2e18aaaSAndroid Build Coastguard Worker _handle_crashed_test( 358*c2e18aaaSAndroid Build Coastguard Worker 'Test started but did not end. This often happens when the test' 359*c2e18aaaSAndroid Build Coastguard Worker ' binary/app such as android instrumentation app process died.' 360*c2e18aaaSAndroid Build Coastguard Worker ' Test count might be inaccurate.' 361*c2e18aaaSAndroid Build Coastguard Worker ) 362*c2e18aaaSAndroid Build Coastguard Worker return 363*c2e18aaaSAndroid Build Coastguard Worker else: 364*c2e18aaaSAndroid Build Coastguard Worker raise EventHandleError( 365*c2e18aaaSAndroid Build Coastguard Worker 'Error: Saw %s Start event and %s End event. These should be equal!' 366*c2e18aaaSAndroid Build Coastguard Worker % (start_event, end_event_name) 367*c2e18aaaSAndroid Build Coastguard Worker ) 368*c2e18aaaSAndroid Build Coastguard Worker 369*c2e18aaaSAndroid Build Coastguard Worker @staticmethod 370*c2e18aaaSAndroid Build Coastguard Worker def _calc_duration(duration): 371*c2e18aaaSAndroid Build Coastguard Worker """Convert duration from ms to 3h2m43.034s. 372*c2e18aaaSAndroid Build Coastguard Worker 373*c2e18aaaSAndroid Build Coastguard Worker Args: 374*c2e18aaaSAndroid Build Coastguard Worker duration: millisecond 375*c2e18aaaSAndroid Build Coastguard Worker 376*c2e18aaaSAndroid Build Coastguard Worker Returns: 377*c2e18aaaSAndroid Build Coastguard Worker string in h:m:s, m:s, s or millis, depends on the duration. 378*c2e18aaaSAndroid Build Coastguard Worker """ 379*c2e18aaaSAndroid Build Coastguard Worker delta = timedelta(milliseconds=duration) 380*c2e18aaaSAndroid Build Coastguard Worker timestamp = str(delta).split(':') # hh:mm:microsec 381*c2e18aaaSAndroid Build Coastguard Worker 382*c2e18aaaSAndroid Build Coastguard Worker if duration < ONE_SECOND: 383*c2e18aaaSAndroid Build Coastguard Worker return '({}ms)'.format(duration) 384*c2e18aaaSAndroid Build Coastguard Worker if duration < ONE_MINUTE: 385*c2e18aaaSAndroid Build Coastguard Worker return '({:.3f}s)'.format(float(timestamp[2])) 386*c2e18aaaSAndroid Build Coastguard Worker if duration < ONE_HOUR: 387*c2e18aaaSAndroid Build Coastguard Worker return '({0}m{1:.3f}s)'.format(timestamp[1], float(timestamp[2])) 388*c2e18aaaSAndroid Build Coastguard Worker return '({0}h{1}m{2:.3f}s)'.format( 389*c2e18aaaSAndroid Build Coastguard Worker timestamp[0], timestamp[1], float(timestamp[2]) 390*c2e18aaaSAndroid Build Coastguard Worker ) 391