12b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project#!/usr/bin/python2.4 22b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# 32b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# 42b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# Copyright 2008, The Android Open Source Project 52b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# 62b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# Licensed under the Apache License, Version 2.0 (the "License"); 72b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# you may not use this file except in compliance with the License. 82b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# You may obtain a copy of the License at 92b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# 102b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# http://www.apache.org/licenses/LICENSE-2.0 112b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# 122b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# Unless required by applicable law or agreed to in writing, software 132b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# distributed under the License is distributed on an "AS IS" BASIS, 142b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 152b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# See the License for the specific language governing permissions and 162b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project# limitations under the License. 172b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 182b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project"""Module that assists in parsing the output of "am instrument" commands run on 192b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Projectthe device.""" 202b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 212b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Projectimport re 222b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Projectimport string 232b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 242b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 252b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Projectdef ParseAmInstrumentOutput(result): 262b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """Given the raw output of an "am instrument" command that targets and 272b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project InstrumentationTestRunner, return structured data. 282b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 292b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project Args: 302b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result (string): Raw output of "am instrument" 312b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 322b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project Return 332b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project (test_results, inst_finished_bundle) 342b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 352b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project test_results (list of am_output_parser.TestResult) 362b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project inst_finished_bundle (dict): Key/value pairs contained in the bundle that is 372b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return 382b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project code of the Instrumentation process, any error codes reported by the 392b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project activity manager, and any results explicity added by the instrumentation 402b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project code. 412b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """ 422b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 432b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$') 442b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project test_results = [] 452b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project inst_finished_bundle = {} 462b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 472b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_block_string = "" 482b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project for line in result.splitlines(): 492b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_block_string += line + '\n' 502b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 512b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project if "INSTRUMENTATION_STATUS_CODE:" in line: 522b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project test_result = TestResult(result_block_string) 532b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project if test_result.GetStatusCode() == 1: # The test started 542b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project pass 552b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project elif test_result.GetStatusCode() in [0, -1, -2]: 562b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project test_results.append(test_result) 572b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project else: 582b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project pass 592b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_block_string = "" 602b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project if "INSTRUMENTATION_CODE:" in line: 612b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string) 622b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_block_string = "" 632b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 642b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project return (test_results, inst_finished_bundle) 652b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 662b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 672b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Projectdef _ParseInstrumentationFinishedBundle(result): 682b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """Given the raw output of "am instrument" returns a dictionary of the 692b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project key/value pairs from the bundle passed into 702b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project ActivityManager.finishInstrumentation(). 712b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 722b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project Args: 732b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result (string): Raw output of "am instrument" 742b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 752b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project Return: 762b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project inst_finished_bundle (dict): Key/value pairs contained in the bundle that is 772b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return 782b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project code of the Instrumentation process, any error codes reported by the 792b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project activity manager, and any results explicity added by the instrumentation 802b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project code. 812b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """ 822b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 8316eac2a6dcba235179003e399d0df14acb50fea6Jack Wang re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$') 842b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$') 852b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict = {} 862b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project key = '' 872b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project val = '' 882b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project last_tag = '' 892b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 902b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project for line in result.split('\n'): 912b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project line = line.strip(string.whitespace) 922b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project if re_result.match(line): 932b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project last_tag = 'INSTRUMENTATION_RESULT' 942b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project key = re_result.search(line).group(1).strip(string.whitespace) 952b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project if key.startswith('performance.'): 962b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project key = key[len('performance.'):] 972b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project val = re_result.search(line).group(2).strip(string.whitespace) 982b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project try: 992b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict[key] = float(val) 1002b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project except ValueError: 1012b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict[key] = val 1022b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project except TypeError: 1032b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict[key] = val 1042b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project elif re_code.match(line): 1052b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project last_tag = 'INSTRUMENTATION_CODE' 1062b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project key = 'code' 1072b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project val = re_code.search(line).group(1).strip(string.whitespace) 1082b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict[key] = val 1092b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project elif 'INSTRUMENTATION_ABORTED:' in line: 1102b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project last_tag = 'INSTRUMENTATION_ABORTED' 1112b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project key = 'INSTRUMENTATION_ABORTED' 1122b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project val = '' 1132b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict[key] = val 1142b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project elif last_tag == 'INSTRUMENTATION_RESULT': 1152b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict[key] += '\n' + line 1162b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1172b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project if not result_dict.has_key('code'): 1182b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict['code'] = '0' 1192b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_dict['shortMsg'] = "No result returned from instrumentation" 1202b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1212b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project return result_dict 1222b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1232b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1242b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Projectclass TestResult(object): 1252b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """A class that contains information about a single test result.""" 1262b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1272b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project def __init__(self, result_block_string): 1282b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """ 1292b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project Args: 1302b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project result_block_string (string): Is a single "block" of output. A single 1312b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project "block" would be either a "test started" status report, or a "test 1322b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project finished" status report. 1332b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project """ 1342b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1352b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project self._test_name = None 1362b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project self._status_code = None 1372b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project self._failure_reason = None 13816eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._fields_map = {} 1392b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 14016eac2a6dcba235179003e399d0df14acb50fea6Jack Wang re_status_code = re.search(r'INSTRUMENTATION_STATUS_CODE: ' 14116eac2a6dcba235179003e399d0df14acb50fea6Jack Wang '(?P<status_code>1|0|-1|-2)', result_block_string) 14216eac2a6dcba235179003e399d0df14acb50fea6Jack Wang re_fields = re.compile(r'INSTRUMENTATION_STATUS: ' 14316eac2a6dcba235179003e399d0df14acb50fea6Jack Wang '(?P<key>[\w.]+)=(?P<value>.*?)(?=\nINSTRUMENTATION_STATUS)', re.DOTALL) 14416eac2a6dcba235179003e399d0df14acb50fea6Jack Wang 14516eac2a6dcba235179003e399d0df14acb50fea6Jack Wang for field in re_fields.finditer(result_block_string): 14616eac2a6dcba235179003e399d0df14acb50fea6Jack Wang key, value = (field.group('key').strip(), field.group('value').strip()) 14716eac2a6dcba235179003e399d0df14acb50fea6Jack Wang if key.startswith('performance.'): 14816eac2a6dcba235179003e399d0df14acb50fea6Jack Wang key = key[len('performance.'):] 14916eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._fields_map[key] = value 15016eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._fields_map.setdefault('class') 15116eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._fields_map.setdefault('test') 15216eac2a6dcba235179003e399d0df14acb50fea6Jack Wang 15316eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._test_name = '%s:%s' % (self._fields_map['class'], 15416eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._fields_map['test']) 15516eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._status_code = int(re_status_code.group('status_code')) 15616eac2a6dcba235179003e399d0df14acb50fea6Jack Wang if 'stack' in self._fields_map: 15716eac2a6dcba235179003e399d0df14acb50fea6Jack Wang self._failure_reason = self._fields_map['stack'] 1582b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1592b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project def GetTestName(self): 1602b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project return self._test_name 1612b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1622b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project def GetStatusCode(self): 1632b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project return self._status_code 1642b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project 1652b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project def GetFailureReason(self): 1662b83cbdb14fcf0307e87b67d46ba17aab4c22a28The Android Open Source Project return self._failure_reason 16716eac2a6dcba235179003e399d0df14acb50fea6Jack Wang 16816eac2a6dcba235179003e399d0df14acb50fea6Jack Wang def GetResultFields(self): 16916eac2a6dcba235179003e399d0df14acb50fea6Jack Wang return self._fields_map 170