OLD | NEW |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import logging | 5 import logging |
6 import os | 6 import os |
7 import pickle | 7 import pickle |
8 import re | 8 import re |
9 import sys | 9 import sys |
10 | 10 |
11 from pylib import cmd_helper | 11 from pylib import cmd_helper |
12 from pylib import constants | 12 from pylib import constants |
13 from pylib import flag_changer | 13 from pylib import flag_changer |
14 from pylib.base import base_test_result | 14 from pylib.base import base_test_result |
15 from pylib.base import test_instance | 15 from pylib.base import test_instance |
16 from pylib.instrumentation import test_result | 16 from pylib.instrumentation import test_result |
| 17 from pylib.instrumentation import instrumentation_parser |
17 from pylib.utils import apk_helper | 18 from pylib.utils import apk_helper |
18 from pylib.utils import md5sum | 19 from pylib.utils import md5sum |
19 from pylib.utils import proguard | 20 from pylib.utils import proguard |
20 | 21 |
21 sys.path.append( | 22 sys.path.append( |
22 os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', 'common')) | 23 os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', 'common')) |
23 import unittest_util | 24 import unittest_util |
24 | 25 |
25 _DEFAULT_ANNOTATIONS = [ | 26 _DEFAULT_ANNOTATIONS = [ |
26 'Smoke', 'SmallTest', 'MediumTest', 'LargeTest', | 27 'Smoke', 'SmallTest', 'MediumTest', 'LargeTest', |
(...skipping 13 matching lines...) Expand all Loading... |
40 Returns: | 41 Returns: |
41 A 3-tuple containing: | 42 A 3-tuple containing: |
42 - the instrumentation code as an integer | 43 - the instrumentation code as an integer |
43 - the instrumentation result as a list of lines | 44 - the instrumentation result as a list of lines |
44 - the instrumentation statuses received as a list of 2-tuples | 45 - the instrumentation statuses received as a list of 2-tuples |
45 containing: | 46 containing: |
46 - the status code as an integer | 47 - the status code as an integer |
47 - the bundle dump as a dict mapping string keys to a list of | 48 - the bundle dump as a dict mapping string keys to a list of |
48 strings, one for each line. | 49 strings, one for each line. |
49 """ | 50 """ |
50 INSTR_STATUS = 'INSTRUMENTATION_STATUS: ' | 51 parser = instrumentation_parser.InstrumentationParser(raw_output) |
51 INSTR_STATUS_CODE = 'INSTRUMENTATION_STATUS_CODE: ' | 52 statuses = list(parser.IterStatus()) |
52 INSTR_RESULT = 'INSTRUMENTATION_RESULT: ' | 53 code, bundle = parser.GetResult() |
53 INSTR_CODE = 'INSTRUMENTATION_CODE: ' | 54 return (code, bundle, statuses) |
54 | |
55 last = None | |
56 instr_code = None | |
57 instr_result = [] | |
58 instr_statuses = [] | |
59 bundle = {} | |
60 for line in raw_output: | |
61 if line.startswith(INSTR_STATUS): | |
62 instr_var = line[len(INSTR_STATUS):] | |
63 if '=' in instr_var: | |
64 k, v = instr_var.split('=', 1) | |
65 bundle[k] = [v] | |
66 last = INSTR_STATUS | |
67 last_key = k | |
68 else: | |
69 logging.debug('Unknown "%s" line: %s' % (INSTR_STATUS, line)) | |
70 | |
71 elif line.startswith(INSTR_STATUS_CODE): | |
72 instr_status = line[len(INSTR_STATUS_CODE):] | |
73 instr_statuses.append((int(instr_status), bundle)) | |
74 bundle = {} | |
75 last = INSTR_STATUS_CODE | |
76 | |
77 elif line.startswith(INSTR_RESULT): | |
78 instr_result.append(line[len(INSTR_RESULT):]) | |
79 last = INSTR_RESULT | |
80 | |
81 elif line.startswith(INSTR_CODE): | |
82 instr_code = int(line[len(INSTR_CODE):]) | |
83 last = INSTR_CODE | |
84 | |
85 elif last == INSTR_STATUS: | |
86 bundle[last_key].append(line) | |
87 | |
88 elif last == INSTR_RESULT: | |
89 instr_result.append(line) | |
90 | |
91 return (instr_code, instr_result, instr_statuses) | |
92 | 55 |
93 | 56 |
94 def GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms): | 57 def GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms): |
95 """Generate the result of |test| from |instr_statuses|. | 58 """Generate the result of |test| from |instr_statuses|. |
96 | 59 |
97 Args: | 60 Args: |
98 test_name: The name of the test as "class#method" | 61 test_name: The name of the test as "class#method" |
99 instr_statuses: A list of 2-tuples containing: | 62 instr_statuses: A list of 2-tuples containing: |
100 - the status code as an integer | 63 - the status code as an integer |
101 - the bundle dump as a dict mapping string keys to string values | 64 - the bundle dump as a dict mapping string keys to string values |
102 Note that this is the same as the third item in the 3-tuple returned by | 65 Note that this is the same as the third item in the 3-tuple returned by |
103 |_ParseAmInstrumentRawOutput|. | 66 |_ParseAmInstrumentRawOutput|. |
104 start_ms: The start time of the test in milliseconds. | 67 start_ms: The start time of the test in milliseconds. |
105 duration_ms: The duration of the test in milliseconds. | 68 duration_ms: The duration of the test in milliseconds. |
106 Returns: | 69 Returns: |
107 An InstrumentationTestResult object. | 70 An InstrumentationTestResult object. |
108 """ | 71 """ |
109 INSTR_STATUS_CODE_START = 1 | |
110 INSTR_STATUS_CODE_OK = 0 | |
111 INSTR_STATUS_CODE_ERROR = -1 | |
112 INSTR_STATUS_CODE_FAIL = -2 | |
113 | |
114 log = '' | 72 log = '' |
115 result_type = base_test_result.ResultType.UNKNOWN | 73 result_type = base_test_result.ResultType.UNKNOWN |
116 | 74 |
117 for status_code, bundle in instr_statuses: | 75 for status_code, bundle in instr_statuses: |
118 if status_code == INSTR_STATUS_CODE_START: | 76 if status_code == instrumentation_parser.STATUS_CODE_START: |
119 pass | 77 pass |
120 elif status_code == INSTR_STATUS_CODE_OK: | 78 elif status_code == instrumentation_parser.STATUS_CODE_OK: |
121 bundle_test = '%s#%s' % ( | 79 bundle_test = '%s#%s' % (bundle.get('class', ''), bundle.get('test', '')) |
122 ''.join(bundle.get('class', [''])), | 80 skipped = bundle.get('test_skipped', '') |
123 ''.join(bundle.get('test', ['']))) | |
124 skipped = ''.join(bundle.get('test_skipped', [''])) | |
125 | 81 |
126 if (test_name == bundle_test and | 82 if (test_name == bundle_test and |
127 result_type == base_test_result.ResultType.UNKNOWN): | 83 result_type == base_test_result.ResultType.UNKNOWN): |
128 result_type = base_test_result.ResultType.PASS | 84 result_type = base_test_result.ResultType.PASS |
129 elif skipped.lower() in ('true', '1', 'yes'): | 85 elif skipped.lower() in ('true', '1', 'yes'): |
130 result_type = base_test_result.ResultType.SKIP | 86 result_type = base_test_result.ResultType.SKIP |
131 logging.info('Skipped ' + test_name) | 87 logging.info('Skipped ' + test_name) |
132 else: | 88 else: |
133 if status_code not in (INSTR_STATUS_CODE_ERROR, | 89 if status_code not in (instrumentation_parser.STATUS_CODE_ERROR, |
134 INSTR_STATUS_CODE_FAIL): | 90 instrumentation_parser.STATUS_CODE_FAILURE): |
135 logging.error('Unrecognized status code %d. Handling as an error.', | 91 logging.error('Unrecognized status code %d. Handling as an error.', |
136 status_code) | 92 status_code) |
137 result_type = base_test_result.ResultType.FAIL | 93 result_type = base_test_result.ResultType.FAIL |
138 if 'stack' in bundle: | 94 if 'stack' in bundle: |
139 log = '\n'.join(bundle['stack']) | 95 log = bundle['stack'] |
140 | 96 |
141 return test_result.InstrumentationTestResult( | 97 return test_result.InstrumentationTestResult( |
142 test_name, result_type, start_ms, duration_ms, log=log) | 98 test_name, result_type, start_ms, duration_ms, log=log) |
143 | 99 |
144 | 100 |
145 class InstrumentationTestInstance(test_instance.TestInstance): | 101 class InstrumentationTestInstance(test_instance.TestInstance): |
146 | 102 |
147 def __init__(self, args, isolate_delegate, error_func): | 103 def __init__(self, args, isolate_delegate, error_func): |
148 super(InstrumentationTestInstance, self).__init__() | 104 super(InstrumentationTestInstance, self).__init__() |
149 | 105 |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 a.update(m['annotations']) | 415 a.update(m['annotations']) |
460 inflated_tests.append({ | 416 inflated_tests.append({ |
461 'class': c['class'], | 417 'class': c['class'], |
462 'method': m['method'], | 418 'method': m['method'], |
463 'annotations': a, | 419 'annotations': a, |
464 }) | 420 }) |
465 return inflated_tests | 421 return inflated_tests |
466 | 422 |
467 @staticmethod | 423 @staticmethod |
468 def GenerateMultiTestResult(errors, statuses): | 424 def GenerateMultiTestResult(errors, statuses): |
469 INSTR_STATUS_CODE_START = 1 | |
470 results = [] | 425 results = [] |
471 skip_counter = 1 | 426 skip_counter = 1 |
472 for status_code, bundle in statuses: | 427 for status_code, bundle in statuses: |
473 if status_code != INSTR_STATUS_CODE_START: | 428 if status_code != instrumentation_parser.STATUS_CODE_START: |
474 # TODO(rnephew): Make skipped tests still output test name. This is only | 429 # TODO(rnephew): Make skipped tests still output test name. This is only |
475 # there to give skipped tests a unique name so they are counted | 430 # there to give skipped tests a unique name so they are counted |
476 if 'test_skipped' in bundle: | 431 if 'test_skipped' in bundle: |
477 test_name = str(skip_counter) | 432 test_name = str(skip_counter) |
478 skip_counter += 1 | 433 skip_counter += 1 |
479 else: | 434 else: |
480 test_name = '%s#%s' % ( | 435 test_name = '%s#%s' % (bundle.get('class', ''), |
481 ''.join(bundle.get('class', [''])), | 436 bundle.get('test', '')) |
482 ''.join(bundle.get('test', ['']))) | |
483 | 437 |
484 results.append( | 438 results.append( |
485 GenerateTestResult(test_name, [(status_code, bundle)], 0, 0)) | 439 GenerateTestResult(test_name, [(status_code, bundle)], 0, 0)) |
486 for error in errors: | 440 for error in errors.itervalues(): |
487 if _NATIVE_CRASH_RE.search(error): | 441 if _NATIVE_CRASH_RE.search(error): |
488 results.append( | 442 results.append( |
489 base_test_result.BaseTestResult( | 443 base_test_result.BaseTestResult( |
490 'Crash detected', base_test_result.ResultType.CRASH)) | 444 'Crash detected', base_test_result.ResultType.CRASH)) |
491 | 445 |
492 return results | 446 return results |
493 | 447 |
494 @staticmethod | 448 @staticmethod |
495 def ParseAmInstrumentRawOutput(raw_output): | 449 def ParseAmInstrumentRawOutput(raw_output): |
496 return ParseAmInstrumentRawOutput(raw_output) | 450 return ParseAmInstrumentRawOutput(raw_output) |
497 | 451 |
498 @staticmethod | 452 @staticmethod |
499 def GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms): | 453 def GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms): |
500 return GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms) | 454 return GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms) |
501 | 455 |
502 #override | 456 #override |
503 def TearDown(self): | 457 def TearDown(self): |
504 if self._isolate_delegate: | 458 if self._isolate_delegate: |
505 self._isolate_delegate.Clear() | 459 self._isolate_delegate.Clear() |
506 | 460 |
OLD | NEW |