blob: cad87c047ce118d2ce53221a72160288647ce5fb [file] [log] [blame]
The Android Open Source Project2b83cbd2009-03-05 17:04:45 -08001#!/usr/bin/python2.4
2#
3#
4# Copyright 2008, The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18"""Module that assists in parsing the output of "am instrument" commands run on
19the device."""
20
21import re
22import string
23
24
25def ParseAmInstrumentOutput(result):
26 """Given the raw output of an "am instrument" command that targets and
27 InstrumentationTestRunner, return structured data.
28
29 Args:
30 result (string): Raw output of "am instrument"
31
32 Return
33 (test_results, inst_finished_bundle)
34
35 test_results (list of am_output_parser.TestResult)
36 inst_finished_bundle (dict): Key/value pairs contained in the bundle that is
37 passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return
38 code of the Instrumentation process, any error codes reported by the
39 activity manager, and any results explicity added by the instrumentation
40 code.
41 """
42
43 re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$')
44 test_results = []
45 inst_finished_bundle = {}
46
47 result_block_string = ""
48 for line in result.splitlines():
49 result_block_string += line + '\n'
50
51 if "INSTRUMENTATION_STATUS_CODE:" in line:
52 test_result = TestResult(result_block_string)
53 if test_result.GetStatusCode() == 1: # The test started
54 pass
55 elif test_result.GetStatusCode() in [0, -1, -2]:
56 test_results.append(test_result)
57 else:
58 pass
59 result_block_string = ""
60 if "INSTRUMENTATION_CODE:" in line:
61 inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string)
62 result_block_string = ""
63
64 return (test_results, inst_finished_bundle)
65
66
67def _ParseInstrumentationFinishedBundle(result):
68 """Given the raw output of "am instrument" returns a dictionary of the
69 key/value pairs from the bundle passed into
70 ActivityManager.finishInstrumentation().
71
72 Args:
73 result (string): Raw output of "am instrument"
74
75 Return:
76 inst_finished_bundle (dict): Key/value pairs contained in the bundle that is
77 passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return
78 code of the Instrumentation process, any error codes reported by the
79 activity manager, and any results explicity added by the instrumentation
80 code.
81 """
82
83 re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.+)$')
84 re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$')
85 result_dict = {}
86 key = ''
87 val = ''
88 last_tag = ''
89
90 for line in result.split('\n'):
91 line = line.strip(string.whitespace)
92 if re_result.match(line):
93 last_tag = 'INSTRUMENTATION_RESULT'
94 key = re_result.search(line).group(1).strip(string.whitespace)
95 if key.startswith('performance.'):
96 key = key[len('performance.'):]
97 val = re_result.search(line).group(2).strip(string.whitespace)
98 try:
99 result_dict[key] = float(val)
100 except ValueError:
101 result_dict[key] = val
102 except TypeError:
103 result_dict[key] = val
104 elif re_code.match(line):
105 last_tag = 'INSTRUMENTATION_CODE'
106 key = 'code'
107 val = re_code.search(line).group(1).strip(string.whitespace)
108 result_dict[key] = val
109 elif 'INSTRUMENTATION_ABORTED:' in line:
110 last_tag = 'INSTRUMENTATION_ABORTED'
111 key = 'INSTRUMENTATION_ABORTED'
112 val = ''
113 result_dict[key] = val
114 elif last_tag == 'INSTRUMENTATION_RESULT':
115 result_dict[key] += '\n' + line
116
117 if not result_dict.has_key('code'):
118 result_dict['code'] = '0'
119 result_dict['shortMsg'] = "No result returned from instrumentation"
120
121 return result_dict
122
123
124class TestResult(object):
125 """A class that contains information about a single test result."""
126
127 def __init__(self, result_block_string):
128 """
129 Args:
130 result_block_string (string): Is a single "block" of output. A single
131 "block" would be either a "test started" status report, or a "test
132 finished" status report.
133 """
134
135 self._test_name = None
136 self._status_code = None
137 self._failure_reason = None
138
139 re_start_block = re.compile(
140 r'\s*INSTRUMENTATION_STATUS: stream=(?P<stream>.*)'
141 'INSTRUMENTATION_STATUS: test=(?P<test>\w+)\s+'
142 'INSTRUMENTATION_STATUS: class=(?P<class>[\w\.]+)\s+'
143 'INSTRUMENTATION_STATUS: current=(?P<current>\d+)\s+'
144 'INSTRUMENTATION_STATUS: numtests=(?P<numtests>\d+)\s+'
145 'INSTRUMENTATION_STATUS: id=.*\s+'
146 'INSTRUMENTATION_STATUS_CODE: 1\s*', re.DOTALL)
147
148 re_end_block = re.compile(
149 r'\s*INSTRUMENTATION_STATUS: stream=(?P<stream>.*)'
150 'INSTRUMENTATION_STATUS: test=(?P<test>\w+)\s+'
151 '(INSTRUMENTATION_STATUS: stack=(?P<stack>.*))?'
152 'INSTRUMENTATION_STATUS: class=(?P<class>[\w\.]+)\s+'
153 'INSTRUMENTATION_STATUS: current=(?P<current>\d+)\s+'
154 'INSTRUMENTATION_STATUS: numtests=(?P<numtests>\d+)\s+'
155 'INSTRUMENTATION_STATUS: id=.*\s+'
156 'INSTRUMENTATION_STATUS_CODE: (?P<status_code>0|-1|-2)\s*', re.DOTALL)
157
158 start_block_match = re_start_block.match(result_block_string)
159 end_block_match = re_end_block.match(result_block_string)
160
161 if start_block_match:
162 self._test_name = "%s:%s" % (start_block_match.group('class'),
163 start_block_match.group('test'))
164 self._status_code = 1
165 elif end_block_match:
166 self._test_name = "%s:%s" % (end_block_match.group('class'),
167 end_block_match.group('test'))
168 self._status_code = int(end_block_match.group('status_code'))
169 self._failure_reason = end_block_match.group('stack')
170
171 def GetTestName(self):
172 return self._test_name
173
174 def GetStatusCode(self):
175 return self._status_code
176
177 def GetFailureReason(self):
178 return self._failure_reason