Index: third_party/android/testrunner/am_instrument_parser.py |
diff --git a/third_party/android/testrunner/am_instrument_parser.py b/third_party/android/testrunner/am_instrument_parser.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4554c4d565f28f63c511614ccca1479df04f2595 |
--- /dev/null |
+++ b/third_party/android/testrunner/am_instrument_parser.py |
@@ -0,0 +1,169 @@ |
+#!/usr/bin/python2.4 |
+# |
+# |
+# Copyright 2008, The Android Open Source Project |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+"""Module that assists in parsing the output of "am instrument" commands run on |
+the device.""" |
+ |
+import re |
+import string |
+ |
+ |
+def ParseAmInstrumentOutput(result): |
+ """Given the raw output of an "am instrument" command that targets and |
+ InstrumentationTestRunner, return structured data. |
+ |
+ Args: |
+ result (string): Raw output of "am instrument" |
+ |
+ Return |
+ (test_results, inst_finished_bundle) |
+ |
+ test_results (list of am_output_parser.TestResult) |
+ inst_finished_bundle (dict): Key/value pairs contained in the bundle that is |
+ passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return |
+ code of the Instrumentation process, any error codes reported by the |
+ activity manager, and any results explicity added by the instrumentation |
+ code. |
+ """ |
+ |
+ re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$') |
+ test_results = [] |
+ inst_finished_bundle = {} |
+ |
+ result_block_string = "" |
+ for line in result.splitlines(): |
+ result_block_string += line + '\n' |
+ |
+ if "INSTRUMENTATION_STATUS_CODE:" in line: |
+ test_result = TestResult(result_block_string) |
+ if test_result.GetStatusCode() == 1: # The test started |
+ pass |
+ elif test_result.GetStatusCode() in [0, -1, -2]: |
+ test_results.append(test_result) |
+ else: |
+ pass |
+ result_block_string = "" |
+ if "INSTRUMENTATION_CODE:" in line: |
+ inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string) |
+ result_block_string = "" |
+ |
+ return (test_results, inst_finished_bundle) |
+ |
+ |
+def _ParseInstrumentationFinishedBundle(result): |
+ """Given the raw output of "am instrument" returns a dictionary of the |
+ key/value pairs from the bundle passed into |
+ ActivityManager.finishInstrumentation(). |
+ |
+ Args: |
+ result (string): Raw output of "am instrument" |
+ |
+ Return: |
+ inst_finished_bundle (dict): Key/value pairs contained in the bundle that is |
+ passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return |
+ code of the Instrumentation process, any error codes reported by the |
+ activity manager, and any results explicity added by the instrumentation |
+ code. |
+ """ |
+ |
+ re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$') |
+ re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$') |
+ result_dict = {} |
+ key = '' |
+ val = '' |
+ last_tag = '' |
+ |
+ for line in result.split('\n'): |
+ line = line.strip(string.whitespace) |
+ if re_result.match(line): |
+ last_tag = 'INSTRUMENTATION_RESULT' |
+ key = re_result.search(line).group(1).strip(string.whitespace) |
+ if key.startswith('performance.'): |
+ key = key[len('performance.'):] |
+ val = re_result.search(line).group(2).strip(string.whitespace) |
+ try: |
+ result_dict[key] = float(val) |
+ except ValueError: |
+ result_dict[key] = val |
+ except TypeError: |
+ result_dict[key] = val |
+ elif re_code.match(line): |
+ last_tag = 'INSTRUMENTATION_CODE' |
+ key = 'code' |
+ val = re_code.search(line).group(1).strip(string.whitespace) |
+ result_dict[key] = val |
+ elif 'INSTRUMENTATION_ABORTED:' in line: |
+ last_tag = 'INSTRUMENTATION_ABORTED' |
+ key = 'INSTRUMENTATION_ABORTED' |
+ val = '' |
+ result_dict[key] = val |
+ elif last_tag == 'INSTRUMENTATION_RESULT': |
+ result_dict[key] += '\n' + line |
+ |
+ if not result_dict.has_key('code'): |
+ result_dict['code'] = '0' |
+ result_dict['shortMsg'] = "No result returned from instrumentation" |
+ |
+ return result_dict |
+ |
+ |
+class TestResult(object): |
+ """A class that contains information about a single test result.""" |
+ |
+ def __init__(self, result_block_string): |
+ """ |
+ Args: |
+ result_block_string (string): Is a single "block" of output. A single |
+ "block" would be either a "test started" status report, or a "test |
+ finished" status report. |
+ """ |
+ |
+ self._test_name = None |
+ self._status_code = None |
+ self._failure_reason = None |
+ self._fields_map = {} |
+ |
+ re_status_code = re.search(r'INSTRUMENTATION_STATUS_CODE: ' |
+ '(?P<status_code>1|0|-1|-2)', result_block_string) |
+ re_fields = re.compile(r'INSTRUMENTATION_STATUS: ' |
+ '(?P<key>[\w.]+)=(?P<value>.*?)(?=\nINSTRUMENTATION_STATUS)', re.DOTALL) |
+ |
+ for field in re_fields.finditer(result_block_string): |
+ key, value = (field.group('key').strip(), field.group('value').strip()) |
+ if key.startswith('performance.'): |
+ key = key[len('performance.'):] |
+ self._fields_map[key] = value |
+ self._fields_map.setdefault('class') |
+ self._fields_map.setdefault('test') |
+ |
+ self._test_name = '%s:%s' % (self._fields_map['class'], |
+ self._fields_map['test']) |
+ self._status_code = int(re_status_code.group('status_code')) |
+ if 'stack' in self._fields_map: |
+ self._failure_reason = self._fields_map['stack'] |
+ |
+ def GetTestName(self): |
+ return self._test_name |
+ |
+ def GetStatusCode(self): |
+ return self._status_code |
+ |
+ def GetFailureReason(self): |
+ return self._failure_reason |
+ |
+ def GetResultFields(self): |
+ return self._fields_map |