OSDN Git Service

Merge change 22346 into donut
[android-x86/development.git] / testrunner / am_instrument_parser.py
1 #!/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
19 the device."""
20
21 import re
22 import string
23
24
25 def 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
67 def _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
124 class 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