Chromium Code Reviews| 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 from collections import namedtuple | |
| 10 | 11 |
| 11 from devil.android import apk_helper | 12 from devil.android import apk_helper |
| 12 from devil.android import md5sum | 13 from devil.android import md5sum |
| 13 from pylib import constants | 14 from pylib import constants |
| 14 from pylib.base import base_test_result | 15 from pylib.base import base_test_result |
| 15 from pylib.base import test_instance | 16 from pylib.base import test_instance |
| 16 from pylib.instrumentation import test_result | 17 from pylib.instrumentation import test_result |
| 17 from pylib.instrumentation import instrumentation_parser | 18 from pylib.instrumentation import instrumentation_parser |
| 18 from pylib.utils import proguard | 19 from pylib.utils import proguard |
| 19 | 20 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 34 'org.chromium.chrome.test.ChromeInstrumentationTestRunner.' | 35 'org.chromium.chrome.test.ChromeInstrumentationTestRunner.' |
| 35 + 'EnableTestHttpServer') | 36 + 'EnableTestHttpServer') |
| 36 _EXTRA_DRIVER_TEST_LIST = ( | 37 _EXTRA_DRIVER_TEST_LIST = ( |
| 37 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList') | 38 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList') |
| 38 _EXTRA_DRIVER_TEST_LIST_FILE = ( | 39 _EXTRA_DRIVER_TEST_LIST_FILE = ( |
| 39 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile') | 40 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile') |
| 40 _EXTRA_DRIVER_TARGET_PACKAGE = ( | 41 _EXTRA_DRIVER_TARGET_PACKAGE = ( |
| 41 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage') | 42 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage') |
| 42 _EXTRA_DRIVER_TARGET_CLASS = ( | 43 _EXTRA_DRIVER_TARGET_CLASS = ( |
| 43 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass') | 44 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass') |
| 45 _PARAMETERIZED_TEST_ANNOTATION = 'ParameterizedTest' | |
| 46 _PARAMETERIZED_TEST_SET_ANNOTATION = 'ParameterizedTest$Set' | |
| 47 _COMMAND_LINE_PARAMETER = 'cmdlinearg-parameter' | |
| 44 _NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE) | 48 _NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE) |
| 45 _PICKLE_FORMAT_VERSION = 10 | 49 _PICKLE_FORMAT_VERSION = 10 |
| 46 | 50 |
| 47 | 51 |
| 48 # TODO(jbudorick): Make these private class methods of | 52 # TODO(jbudorick): Make these private class methods of |
| 49 # InstrumentationTestInstance once the instrumentation test_runner is | 53 # InstrumentationTestInstance once the instrumentation test_runner is |
| 50 # deprecated. | 54 # deprecated. |
| 51 def ParseAmInstrumentRawOutput(raw_output): | 55 def ParseAmInstrumentRawOutput(raw_output): |
| 52 """Parses the output of an |am instrument -r| call. | 56 """Parses the output of an |am instrument -r| call. |
| 53 | 57 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 and any(_NATIVE_CRASH_RE.search(l) | 131 and any(_NATIVE_CRASH_RE.search(l) |
| 128 for l in result_bundle.itervalues())) | 132 for l in result_bundle.itervalues())) |
| 129 if crashed: | 133 if crashed: |
| 130 current_result.SetType(base_test_result.ResultType.CRASH) | 134 current_result.SetType(base_test_result.ResultType.CRASH) |
| 131 | 135 |
| 132 results.append(current_result) | 136 results.append(current_result) |
| 133 | 137 |
| 134 return results | 138 return results |
| 135 | 139 |
| 136 | 140 |
| 141 def ParseCommandLineFlagParameters(annotations): | |
| 142 """Determines whether the test is parameterized to be run with different | |
| 143 command-line flags. | |
| 144 | |
| 145 Args: | |
| 146 annotations: The annotations of the test. | |
| 147 | |
| 148 Returns: | |
| 149 If the test is parameterized, returns a list of named tuples | |
| 150 with lists of flags, e.g.: | |
| 151 | |
| 152 [(add=['--flag-to-add']), (remove=['--flag-to-remove']), ()] | |
| 153 | |
| 154 That means, the test must be run three times, the first time with | |
| 155 "--flag-to-add" added to command-line, the second time with | |
| 156 "--flag-to-remove" to be removed from command-line, and the third time | |
| 157 with default command-line args. If the same flag is listed both for adding | |
| 158 and for removing, it is left unchanged. | |
| 159 | |
| 160 If the test is not parametrized, returns None. | |
| 161 | |
| 162 """ | |
| 163 ParamsTuple = namedtuple('ParamsTuple', ['add', 'remove']) | |
| 164 parameterized_tests = [] | |
| 165 if _PARAMETERIZED_TEST_ANNOTATION in annotations: | |
| 166 parameterized_tests = [annotations[_PARAMETERIZED_TEST_ANNOTATION]] | |
| 167 elif _PARAMETERIZED_TEST_SET_ANNOTATION in annotations: | |
| 168 if annotations[_PARAMETERIZED_TEST_SET_ANNOTATION]: | |
| 169 parameterized_tests = annotations[ | |
| 170 _PARAMETERIZED_TEST_SET_ANNOTATION].get('tests', []) | |
| 171 else: | |
| 172 return None | |
| 173 | |
| 174 result = [] | |
| 175 for pt in parameterized_tests: | |
| 176 if not pt: | |
| 177 continue | |
| 178 for p in pt['parameters']: | |
| 179 if p['tag'] == _COMMAND_LINE_PARAMETER: | |
| 180 to_add = [] | |
| 181 to_remove = [] | |
| 182 if 'arguments' in p: | |
|
jbudorick
2015/11/02 14:49:46
nit: combine these two lines into
for a in p.ge
mnaganov (inactive)
2015/11/02 19:03:54
Done.
| |
| 183 for a in p['arguments']: | |
| 184 if a['name'] == 'add': | |
| 185 to_add = [('--' + f) for f in a['stringArray']] | |
|
jbudorick
2015/11/02 14:49:46
nit: ['--%s' % f for f in a['stringArray']]
mnaganov (inactive)
2015/11/02 19:03:53
Done.
| |
| 186 elif a['name'] == 'remove': | |
| 187 to_remove = [('--' + f) for f in a['stringArray']] | |
|
jbudorick
2015/11/02 14:49:46
nit: same
mnaganov (inactive)
2015/11/02 19:03:53
Done.
| |
| 188 result.append(ParamsTuple(to_add, to_remove)) | |
| 189 return result if result else None | |
| 190 | |
| 191 | |
| 137 class InstrumentationTestInstance(test_instance.TestInstance): | 192 class InstrumentationTestInstance(test_instance.TestInstance): |
| 138 | 193 |
| 139 def __init__(self, args, isolate_delegate, error_func): | 194 def __init__(self, args, isolate_delegate, error_func): |
| 140 super(InstrumentationTestInstance, self).__init__() | 195 super(InstrumentationTestInstance, self).__init__() |
| 141 | 196 |
| 142 self._additional_apks = [] | 197 self._additional_apks = [] |
| 143 self._apk_under_test = None | 198 self._apk_under_test = None |
| 144 self._apk_under_test_permissions = None | 199 self._apk_under_test_permissions = None |
| 145 self._package_info = None | 200 self._package_info = None |
| 146 self._suite = None | 201 self._suite = None |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 return self._data_deps | 440 return self._data_deps |
| 386 | 441 |
| 387 def GetTests(self): | 442 def GetTests(self): |
| 388 pickle_path = '%s-proguard.pickle' % self.test_jar | 443 pickle_path = '%s-proguard.pickle' % self.test_jar |
| 389 try: | 444 try: |
| 390 tests = self._GetTestsFromPickle(pickle_path, self.test_jar) | 445 tests = self._GetTestsFromPickle(pickle_path, self.test_jar) |
| 391 except self.ProguardPickleException as e: | 446 except self.ProguardPickleException as e: |
| 392 logging.info('Getting tests from JAR via proguard. (%s)', str(e)) | 447 logging.info('Getting tests from JAR via proguard. (%s)', str(e)) |
| 393 tests = self._GetTestsFromProguard(self.test_jar) | 448 tests = self._GetTestsFromProguard(self.test_jar) |
| 394 self._SaveTestsToPickle(pickle_path, self.test_jar, tests) | 449 self._SaveTestsToPickle(pickle_path, self.test_jar, tests) |
| 395 return self._InflateTests(self._FilterTests(tests)) | 450 return self._InflateTests(self._FilterTests(tests)) |
|
jbudorick
2015/11/02 14:49:45
re below: add the separate function call here.
mnaganov (inactive)
2015/11/02 19:03:54
Done.
| |
| 396 | 451 |
| 397 class ProguardPickleException(Exception): | 452 class ProguardPickleException(Exception): |
| 398 pass | 453 pass |
| 399 | 454 |
| 400 def _GetTestsFromPickle(self, pickle_path, jar_path): | 455 def _GetTestsFromPickle(self, pickle_path, jar_path): |
| 401 if not os.path.exists(pickle_path): | 456 if not os.path.exists(pickle_path): |
| 402 raise self.ProguardPickleException('%s does not exist.' % pickle_path) | 457 raise self.ProguardPickleException('%s does not exist.' % pickle_path) |
| 403 if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path): | 458 if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path): |
| 404 raise self.ProguardPickleException( | 459 raise self.ProguardPickleException( |
| 405 '%s newer than %s.' % (jar_path, pickle_path)) | 460 '%s newer than %s.' % (jar_path, pickle_path)) |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 filtered_classes.append(filtered_class) | 558 filtered_classes.append(filtered_class) |
| 504 | 559 |
| 505 return filtered_classes | 560 return filtered_classes |
| 506 | 561 |
| 507 def _InflateTests(self, tests): | 562 def _InflateTests(self, tests): |
| 508 inflated_tests = [] | 563 inflated_tests = [] |
| 509 for c in tests: | 564 for c in tests: |
| 510 for m in c['methods']: | 565 for m in c['methods']: |
| 511 a = dict(c['annotations']) | 566 a = dict(c['annotations']) |
| 512 a.update(m['annotations']) | 567 a.update(m['annotations']) |
| 513 inflated_tests.append({ | 568 parameters = ParseCommandLineFlagParameters(a) |
|
jbudorick
2015/11/02 14:49:46
Do this in a separate function.
mnaganov (inactive)
2015/11/02 19:03:53
Done.
| |
| 569 if parameters: | |
| 570 for p in parameters: | |
| 571 inflated_tests.append({ | |
| 572 'class': c['class'], | |
| 573 'method': m['method'], | |
| 574 'annotations': a, | |
| 575 'flags': p, | |
| 576 }) | |
| 577 else: | |
| 578 inflated_tests.append({ | |
| 514 'class': c['class'], | 579 'class': c['class'], |
| 515 'method': m['method'], | 580 'method': m['method'], |
| 516 'annotations': a, | 581 'annotations': a, |
| 517 }) | 582 }) |
| 518 return inflated_tests | 583 return inflated_tests |
| 519 | 584 |
| 520 @staticmethod | 585 @staticmethod |
| 521 def GetHttpServerEnvironmentVars(): | 586 def GetHttpServerEnvironmentVars(): |
| 522 return { | 587 return { |
| 523 _EXTRA_ENABLE_HTTP_SERVER: None, | 588 _EXTRA_ENABLE_HTTP_SERVER: None, |
| 524 } | 589 } |
| 525 | 590 |
| 526 def GetDriverEnvironmentVars( | 591 def GetDriverEnvironmentVars( |
| 527 self, test_list=None, test_list_file_path=None): | 592 self, test_list=None, test_list_file_path=None): |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 547 def GenerateTestResults( | 612 def GenerateTestResults( |
| 548 result_code, result_bundle, statuses, start_ms, duration_ms): | 613 result_code, result_bundle, statuses, start_ms, duration_ms): |
| 549 return GenerateTestResults(result_code, result_bundle, statuses, | 614 return GenerateTestResults(result_code, result_bundle, statuses, |
| 550 start_ms, duration_ms) | 615 start_ms, duration_ms) |
| 551 | 616 |
| 552 #override | 617 #override |
| 553 def TearDown(self): | 618 def TearDown(self): |
| 554 if self._isolate_delegate: | 619 if self._isolate_delegate: |
| 555 self._isolate_delegate.Clear() | 620 self._isolate_delegate.Clear() |
| 556 | 621 |
| OLD | NEW |