4 # Copyright 2008, The Android Open Source Project
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 """Module that assists in parsing the output of "am instrument" commands run on
25 def ParseAmInstrumentOutput(result
):
26 """Given the raw output of an "am instrument" command that targets and
27 InstrumentationTestRunner, return structured data.
30 result (string): Raw output of "am instrument"
33 (test_results, inst_finished_bundle)
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
43 re_status_code
= re
.compile(r
'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$')
45 inst_finished_bundle
= {}
47 result_block_string
= ""
48 for line
in result
.splitlines():
49 result_block_string
+= line
+ '\n'
51 if "INSTRUMENTATION_STATUS_CODE:" in line
:
52 test_result
= TestResult(result_block_string
)
53 if test_result
.GetStatusCode() == 1: # The test started
55 elif test_result
.GetStatusCode() in [0, -1, -2]:
56 test_results
.append(test_result
)
59 result_block_string
= ""
60 if "INSTRUMENTATION_CODE:" in line
:
61 inst_finished_bundle
= _ParseInstrumentationFinishedBundle(result_block_string
)
62 result_block_string
= ""
64 return (test_results
, inst_finished_bundle
)
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().
73 result (string): Raw output of "am instrument"
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
83 re_result
= re
.compile(r
'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$')
84 re_code
= re
.compile(r
'INSTRUMENTATION_CODE: (\-?\d)$')
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
)
99 result_dict
[key
] = float(val
)
101 result_dict
[key
] = val
103 result_dict
[key
] = val
104 elif re_code
.match(line
):
105 last_tag
= 'INSTRUMENTATION_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'
113 result_dict
[key
] = val
114 elif last_tag
== 'INSTRUMENTATION_RESULT':
115 result_dict
[key
] += '\n' + line
117 if not result_dict
.has_key('code'):
118 result_dict
['code'] = '0'
119 result_dict
['shortMsg'] = "No result returned from instrumentation"
124 class TestResult(object):
125 """A class that contains information about a single test result."""
127 def __init__(self
, result_block_string
):
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.
135 self
._test
_name
= None
136 self
._status
_code
= None
137 self
._failure
_reason
= None
138 self
._fields
_map
= {}
140 re_status_code
= re
.search(r
'INSTRUMENTATION_STATUS_CODE: '
141 '(?P<status_code>1|0|-1|-2)', result_block_string
)
142 re_fields
= re
.compile(r
'INSTRUMENTATION_STATUS: '
143 '(?P<key>[\w.]+)=(?P<value>.*?)(?=\nINSTRUMENTATION_STATUS)', re
.DOTALL
)
145 for field
in re_fields
.finditer(result_block_string
):
146 key
, value
= (field
.group('key').strip(), field
.group('value').strip())
147 if key
.startswith('performance.'):
148 key
= key
[len('performance.'):]
149 self
._fields
_map
[key
] = value
150 self
._fields
_map
.setdefault('class')
151 self
._fields
_map
.setdefault('test')
153 self
._test
_name
= '%s:%s' % (self
._fields
_map
['class'],
154 self
._fields
_map
['test'])
155 self
._status
_code
= int(re_status_code
.group('status_code'))
156 if 'stack' in self
._fields
_map
:
157 self
._failure
_reason
= self
._fields
_map
['stack']
159 def GetTestName(self
):
160 return self
._test
_name
162 def GetStatusCode(self
):
163 return self
._status
_code
165 def GetFailureReason(self
):
166 return self
._failure
_reason
168 def GetResultFields(self
):
169 return self
._fields
_map