"""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:
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