Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / build / android / pylib / instrumentation / instrumentation_parser.py
blob1859f1423ef66eba12e978f5aaff6b2f51ddb6f9
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import logging
6 import re
8 # http://developer.android.com/reference/android/test/InstrumentationTestRunner.html
9 STATUS_CODE_START = 1
10 STATUS_CODE_OK = 0
11 STATUS_CODE_ERROR = -1
12 STATUS_CODE_FAILURE = -2
14 # http://developer.android.com/reference/android/app/Activity.html
15 RESULT_CODE_OK = -1
16 RESULT_CODE_CANCELED = 0
18 _INSTR_LINE_RE = re.compile('^\s*INSTRUMENTATION_([A-Z_]+): (.*)$')
21 class InstrumentationParser(object):
23 def __init__(self, stream):
24 """An incremental parser for the output of Android instrumentation tests.
26 Example:
28 stream = adb.IterShell('am instrument -r ...')
29 parser = InstrumentationParser(stream)
31 for code, bundle in parser.IterStatus():
32 # do something with each instrumentation status
33 print 'status:', code, bundle
35 # do something with the final instrumentation result
36 code, bundle = parser.GetResult()
37 print 'result:', code, bundle
39 Args:
40 stream: a sequence of lines as produced by the raw output of an
41 instrumentation test (e.g. by |am instrument -r| or |uiautomator|).
42 """
43 self._stream = stream
44 self._code = None
45 self._bundle = None
47 def IterStatus(self):
48 """Iterate over statuses as they are produced by the instrumentation test.
50 Yields:
51 A tuple (code, bundle) for each instrumentation status found in the
52 output.
53 """
54 def join_bundle_values(bundle):
55 for key in bundle:
56 bundle[key] = '\n'.join(bundle[key])
57 return bundle
59 bundle = {'STATUS': {}, 'RESULT': {}}
60 header = None
61 key = None
62 for line in self._stream:
63 m = _INSTR_LINE_RE.match(line)
64 if m:
65 header, value = m.groups()
66 key = None
67 if header in ['STATUS', 'RESULT'] and '=' in value:
68 key, value = value.split('=', 1)
69 bundle[header][key] = [value]
70 elif header == 'STATUS_CODE':
71 yield int(value), join_bundle_values(bundle['STATUS'])
72 bundle['STATUS'] = {}
73 elif header == 'CODE':
74 self._code = int(value)
75 else:
76 logging.warning('Unknown INSTRUMENTATION_%s line: %s', header, value)
77 elif key is not None:
78 bundle[header][key].append(line)
80 self._bundle = join_bundle_values(bundle['RESULT'])
82 def GetResult(self):
83 """Return the final instrumentation result.
85 Returns:
86 A pair (code, bundle) with the final instrumentation result. The |code|
87 may be None if no instrumentation result was found in the output.
89 Raises:
90 AssertionError if attempting to get the instrumentation result before
91 exhausting |IterStatus| first.
92 """
93 assert self._bundle is not None, (
94 'The IterStatus generator must be exhausted before reading the final'
95 ' instrumentation result.')
96 return self._code, self._bundle