15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python2.4 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright 2008, The Android Open Source Project 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the "License"); 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# you may not use this file except in compliance with the License. 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# You may obtain a copy of the License at 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://www.apache.org/licenses/LICENSE-2.0 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Unless required by applicable law or agreed to in writing, software 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distributed under the License is distributed on an "AS IS" BASIS, 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# See the License for the specific language governing permissions and 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# limitations under the License. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Module that assists in parsing the output of "am instrument" commands run on 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the device.""" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import string 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ParseAmInstrumentOutput(result): 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Given the raw output of an "am instrument" command that targets and 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InstrumentationTestRunner, return structured data. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result (string): Raw output of "am instrument" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Return 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (test_results, inst_finished_bundle) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_results (list of am_output_parser.TestResult) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inst_finished_bundle (dict): Key/value pairs contained in the bundle that is 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code of the Instrumentation process, any error codes reported by the 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) activity manager, and any results explicity added by the instrumentation 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code. 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$') 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_results = [] 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inst_finished_bundle = {} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_block_string = "" 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in result.splitlines(): 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_block_string += line + '\n' 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if "INSTRUMENTATION_STATUS_CODE:" in line: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_result = TestResult(result_block_string) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if test_result.GetStatusCode() == 1: # The test started 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif test_result.GetStatusCode() in [0, -1, -2]: 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) test_results.append(test_result) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_block_string = "" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if "INSTRUMENTATION_CODE:" in line: 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_block_string = "" 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (test_results, inst_finished_bundle) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _ParseInstrumentationFinishedBundle(result): 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Given the raw output of "am instrument" returns a dictionary of the 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key/value pairs from the bundle passed into 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ActivityManager.finishInstrumentation(). 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result (string): Raw output of "am instrument" 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Return: 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) inst_finished_bundle (dict): Key/value pairs contained in the bundle that is 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code of the Instrumentation process, any error codes reported by the 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) activity manager, and any results explicity added by the instrumentation 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$') 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$') 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict = {} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = '' 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val = '' 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_tag = '' 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for line in result.split('\n'): 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line = line.strip(string.whitespace) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if re_result.match(line): 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_tag = 'INSTRUMENTATION_RESULT' 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = re_result.search(line).group(1).strip(string.whitespace) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if key.startswith('performance.'): 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = key[len('performance.'):] 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val = re_result.search(line).group(2).strip(string.whitespace) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict[key] = float(val) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except ValueError: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict[key] = val 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except TypeError: 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict[key] = val 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif re_code.match(line): 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_tag = 'INSTRUMENTATION_CODE' 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = 'code' 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val = re_code.search(line).group(1).strip(string.whitespace) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict[key] = val 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif 'INSTRUMENTATION_ABORTED:' in line: 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_tag = 'INSTRUMENTATION_ABORTED' 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = 'INSTRUMENTATION_ABORTED' 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) val = '' 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict[key] = val 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif last_tag == 'INSTRUMENTATION_RESULT': 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict[key] += '\n' + line 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not result_dict.has_key('code'): 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict['code'] = '0' 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_dict['shortMsg'] = "No result returned from instrumentation" 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result_dict 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TestResult(object): 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A class that contains information about a single test result.""" 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, result_block_string): 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_block_string (string): Is a single "block" of output. A single 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "block" would be either a "test started" status report, or a "test 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finished" status report. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._test_name = None 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._status_code = None 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._failure_reason = None 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._fields_map = {} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) re_status_code = re.search(r'INSTRUMENTATION_STATUS_CODE: ' 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '(?P<status_code>1|0|-1|-2)', result_block_string) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) re_fields = re.compile(r'INSTRUMENTATION_STATUS: ' 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '(?P<key>[\w.]+)=(?P<value>.*?)(?=\nINSTRUMENTATION_STATUS)', re.DOTALL) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for field in re_fields.finditer(result_block_string): 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key, value = (field.group('key').strip(), field.group('value').strip()) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if key.startswith('performance.'): 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key = key[len('performance.'):] 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._fields_map[key] = value 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._fields_map.setdefault('class') 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._fields_map.setdefault('test') 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._test_name = '%s:%s' % (self._fields_map['class'], 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._fields_map['test']) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._status_code = int(re_status_code.group('status_code')) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if 'stack' in self._fields_map: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._failure_reason = self._fields_map['stack'] 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetTestName(self): 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._test_name 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetStatusCode(self): 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._status_code 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetFailureReason(self): 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._failure_reason 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetResultFields(self): 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._fields_map 170