| 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 |