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 copy | 5 import copy |
| 6 import json | |
| 6 import logging | 7 import logging |
| 7 import os | 8 import os |
| 8 import pickle | 9 import pickle |
| 9 import re | 10 import re |
| 10 | 11 |
| 11 from devil.android import apk_helper | 12 from devil.android import apk_helper |
| 13 from devil.android import device_temp_file | |
| 12 from devil.android import md5sum | 14 from devil.android import md5sum |
| 13 from pylib import constants | 15 from pylib import constants |
| 14 from pylib.base import base_test_result | 16 from pylib.base import base_test_result |
| 15 from pylib.base import test_exception | 17 from pylib.base import test_exception |
| 16 from pylib.base import test_instance | 18 from pylib.base import test_instance |
| 17 from pylib.constants import host_paths | 19 from pylib.constants import host_paths |
| 18 from pylib.instrumentation import test_result | 20 from pylib.instrumentation import test_result |
| 19 from pylib.instrumentation import instrumentation_parser | 21 from pylib.instrumentation import instrumentation_parser |
| 20 from pylib.utils import dexdump | 22 from pylib.utils import dexdump |
| 21 from pylib.utils import proguard | 23 from pylib.utils import proguard |
| 22 from pylib.utils import shared_preference_utils | 24 from pylib.utils import shared_preference_utils |
| 25 from py_utils import tempfile_ext | |
| 23 | 26 |
| 24 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): | 27 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): |
| 25 import unittest_util # pylint: disable=import-error | 28 import unittest_util # pylint: disable=import-error |
| 26 | 29 |
| 27 # Ref: http://developer.android.com/reference/android/app/Activity.html | 30 # Ref: http://developer.android.com/reference/android/app/Activity.html |
| 28 _ACTIVITY_RESULT_CANCELED = 0 | 31 _ACTIVITY_RESULT_CANCELED = 0 |
| 29 _ACTIVITY_RESULT_OK = -1 | 32 _ACTIVITY_RESULT_OK = -1 |
| 30 | 33 |
| 31 _COMMAND_LINE_PARAMETER = 'cmdlinearg-parameter' | 34 _COMMAND_LINE_PARAMETER = 'cmdlinearg-parameter' |
| 32 _DEFAULT_ANNOTATIONS = [ | 35 _DEFAULT_ANNOTATIONS = [ |
| 33 'SmallTest', 'MediumTest', 'LargeTest', 'EnormousTest', 'IntegrationTest'] | 36 'SmallTest', 'MediumTest', 'LargeTest', 'EnormousTest', 'IntegrationTest'] |
| 34 _EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS = [ | 37 _EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS = [ |
| 35 'DisabledTest', 'FlakyTest'] | 38 'DisabledTest', 'FlakyTest'] |
| 36 _VALID_ANNOTATIONS = set(['Manual'] + _DEFAULT_ANNOTATIONS + | 39 _VALID_ANNOTATIONS = set(['Manual'] + _DEFAULT_ANNOTATIONS + |
| 37 _EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS) | 40 _EXCLUDE_UNLESS_REQUESTED_ANNOTATIONS) |
| 38 _EXTRA_DRIVER_TEST_LIST = ( | 41 _EXTRA_DRIVER_TEST_LIST = ( |
| 39 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList') | 42 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestList') |
| 40 _EXTRA_DRIVER_TEST_LIST_FILE = ( | 43 _EXTRA_DRIVER_TEST_LIST_FILE = ( |
| 41 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile') | 44 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TestListFile') |
| 42 _EXTRA_DRIVER_TARGET_PACKAGE = ( | 45 _EXTRA_DRIVER_TARGET_PACKAGE = ( |
| 43 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage') | 46 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetPackage') |
| 44 _EXTRA_DRIVER_TARGET_CLASS = ( | 47 _EXTRA_DRIVER_TARGET_CLASS = ( |
| 45 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass') | 48 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass') |
| 46 _EXTRA_TIMEOUT_SCALE = ( | 49 _EXTRA_TIMEOUT_SCALE = ( |
| 47 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TimeoutScale') | 50 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TimeoutScale') |
| 51 _EXTRA_TEST_LIST = ( | |
| 52 'org.chromium.base.test.BaseChromiumAndroidJUnitRunner.TestList') | |
| 48 | 53 |
| 49 _SKIP_PARAMETERIZATION = 'SkipCommandLineParameterization' | 54 _SKIP_PARAMETERIZATION = 'SkipCommandLineParameterization' |
| 50 _COMMANDLINE_PARAMETERIZATION = 'CommandLineParameter' | 55 _COMMANDLINE_PARAMETERIZATION = 'CommandLineParameter' |
| 51 _NATIVE_CRASH_RE = re.compile('(process|native) crash', re.IGNORECASE) | 56 _NATIVE_CRASH_RE = re.compile('(process|native) crash', re.IGNORECASE) |
| 52 _CMDLINE_NAME_SEGMENT_RE = re.compile( | 57 _CMDLINE_NAME_SEGMENT_RE = re.compile( |
| 53 r' with(?:out)? \{[^\}]*\}') | 58 r' with(?:out)? \{[^\}]*\}') |
| 54 _PICKLE_FORMAT_VERSION = 12 | 59 _PICKLE_FORMAT_VERSION = 12 |
| 55 | 60 |
| 56 | 61 |
| 57 class MissingSizeAnnotationError(test_exception.TestException): | 62 class MissingSizeAnnotationError(test_exception.TestException): |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 155 | 160 |
| 156 return results | 161 return results |
| 157 | 162 |
| 158 | 163 |
| 159 def FilterTests(tests, test_filter=None, annotations=None, | 164 def FilterTests(tests, test_filter=None, annotations=None, |
| 160 excluded_annotations=None): | 165 excluded_annotations=None): |
| 161 """Filter a list of tests | 166 """Filter a list of tests |
| 162 | 167 |
| 163 Args: | 168 Args: |
| 164 tests: a list of tests. e.g. [ | 169 tests: a list of tests. e.g. [ |
| 165 {'annotations": {}, 'class': 'com.example.TestA', 'methods':[]}, | 170 {'annotations": {}, 'class': 'com.example.TestA', 'method':'test1'}, |
| 166 {'annotations": {}, 'class': 'com.example.TestB', 'methods':[]}] | 171 {'annotations": {}, 'class': 'com.example.TestB', 'method':'test2'}] |
| 167 test_filter: googletest-style filter string. | 172 test_filter: googletest-style filter string. |
| 168 annotations: a dict of wanted annotations for test methods. | 173 annotations: a dict of wanted annotations for test methods. |
| 169 exclude_annotations: a dict of annotations to exclude. | 174 exclude_annotations: a dict of annotations to exclude. |
| 170 | 175 |
| 171 Return: | 176 Return: |
| 172 A list of filtered tests | 177 A list of filtered tests |
| 173 """ | 178 """ |
| 174 def gtest_filter(t): | 179 def gtest_filter(t): |
| 175 if not test_filter: | 180 if not test_filter: |
| 176 return True | 181 return True |
| 177 # Allow fully-qualified name as well as an omitted package. | 182 # Allow fully-qualified name as well as an omitted package. |
| 178 unqualified_class_test = { | 183 unqualified_class_test = { |
| 179 'class': t['class'].split('.')[-1], | 184 'class': t['class'].split('.')[-1], |
| 180 'method': t['method'] | 185 'method': t['method'] |
| 181 } | 186 } |
| 182 names = [ | 187 names = [ |
| 183 GetTestName(t, sep='.'), | 188 GetTestName(t, sep='.'), |
| 184 GetTestName(unqualified_class_test, sep='.'), | 189 GetTestName(unqualified_class_test, sep='.'), |
| 185 GetUniqueTestName(t, sep='.') | 190 GetUniqueTestName(t, sep='.') |
| 186 ] | 191 ] |
| 187 | 192 |
| 193 if t['is_junit4']: | |
| 194 names += [ | |
| 195 GetTestNameWithoutParameterPostfix(t, sep='.'), | |
| 196 GetTestNameWithoutParameterPostfix(unqualified_class_test, sep='.') | |
| 197 ] | |
| 198 | |
| 188 pattern_groups = test_filter.split('-') | 199 pattern_groups = test_filter.split('-') |
| 189 if len(pattern_groups) > 1: | 200 if len(pattern_groups) > 1: |
| 190 negative_filter = pattern_groups[1] | 201 negative_filter = pattern_groups[1] |
| 191 if unittest_util.FilterTestNames(names, negative_filter): | 202 if unittest_util.FilterTestNames(names, negative_filter): |
| 192 return [] | 203 return [] |
| 193 | 204 |
| 194 positive_filter = pattern_groups[0] | 205 positive_filter = pattern_groups[0] |
| 195 return unittest_util.FilterTestNames(names, positive_filter) | 206 return unittest_util.FilterTestNames(names, positive_filter) |
| 196 | 207 |
| 197 def annotation_filter(all_annotations): | 208 def annotation_filter(all_annotations): |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 232 | 243 |
| 233 if (not annotation_filter(t['annotations']) | 244 if (not annotation_filter(t['annotations']) |
| 234 or not excluded_annotation_filter(t['annotations'])): | 245 or not excluded_annotation_filter(t['annotations'])): |
| 235 continue | 246 continue |
| 236 | 247 |
| 237 filtered_tests.append(t) | 248 filtered_tests.append(t) |
| 238 | 249 |
| 239 return filtered_tests | 250 return filtered_tests |
| 240 | 251 |
| 241 | 252 |
| 253 def GetAllTestsFromRunner(device, test_apk, test_package, | |
| 254 test_runner=None, test_runner_junit4=None): | |
| 255 pickle_path = '%s-runner.pickle' % test_apk.path | |
| 256 try: | |
| 257 tests = _GetTestsFromPickle(pickle_path, test_apk.path) | |
| 258 except TestListPickleException as e: | |
| 259 logging.info('Could not get tests from pickle: %s', e) | |
| 260 logging.info('Getting tests by print tests in instrumentation runner') | |
| 261 tests = _GetAllTestsFromRunner(device, test_package, test_runner, | |
| 262 test_runner_junit4) | |
| 263 _SaveTestsToPickle(pickle_path, test_apk.path, tests) | |
| 264 return tests | |
| 265 | |
| 266 | |
| 267 # TODO(yolandyan): remove this once the tests are converted to junit4 | |
| 242 def GetAllTestsFromJar(test_jar): | 268 def GetAllTestsFromJar(test_jar): |
| 243 pickle_path = '%s-proguard.pickle' % test_jar | 269 pickle_path = '%s-proguard.pickle' % test_jar |
| 244 try: | 270 try: |
| 245 tests = _GetTestsFromPickle(pickle_path, test_jar) | 271 tests = _GetTestsFromPickle(pickle_path, test_jar) |
| 246 except TestListPickleException as e: | 272 except TestListPickleException as e: |
| 247 logging.info('Could not get tests from pickle: %s', e) | 273 logging.info('Could not get tests from pickle: %s', e) |
| 248 logging.info('Getting tests from JAR via proguard.') | 274 logging.info('Getting tests from JAR via proguard.') |
| 249 tests = _GetTestsFromProguard(test_jar) | 275 tests = _GetTestsFromProguard(test_jar) |
| 250 _SaveTestsToPickle(pickle_path, test_jar, tests) | 276 _SaveTestsToPickle(pickle_path, test_jar, tests) |
| 251 return tests | 277 return tests |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 329 for class_name, class_info in package_info['classes'].iteritems(): | 355 for class_name, class_info in package_info['classes'].iteritems(): |
| 330 if class_name.endswith('Test'): | 356 if class_name.endswith('Test'): |
| 331 tests.append({ | 357 tests.append({ |
| 332 'class': '%s.%s' % (package_name, class_name), | 358 'class': '%s.%s' % (package_name, class_name), |
| 333 'annotations': {}, | 359 'annotations': {}, |
| 334 'methods': get_test_methods(class_info['methods']), | 360 'methods': get_test_methods(class_info['methods']), |
| 335 'superclass': class_info['superclass'], | 361 'superclass': class_info['superclass'], |
| 336 }) | 362 }) |
| 337 return tests | 363 return tests |
| 338 | 364 |
| 365 def _GetAllTestsFromRunner(device, test_package, test_runner=None, | |
| 366 test_runner_junit4=None): | |
| 367 with device_temp_file.DeviceTempFile( | |
| 368 device.adb, suffix='.json', dir=device.GetExternalStoragePath()) as f: | |
| 369 if test_runner is None and test_runner_junit4 is None: | |
|
mikecase (-- gone --)
2017/07/18 23:59:12
test_runner basically unused here.
the real yoland
2017/07/19 00:12:49
Removed
| |
| 370 raise Exception('Test runner does NOT exist for this test apk') | |
| 371 if test_runner_junit4: | |
| 372 extras = {} | |
| 373 extras[_EXTRA_TEST_LIST] = f.name | |
| 374 extras['log'] = 'true' | |
| 375 extras['package'] = 'org.chromium' | |
|
mikecase (-- gone --)
2017/07/18 23:59:12
so this won't work downstream right? I think some
the real yoland
2017/07/19 00:12:49
Changed
This is just for the sake of speed up java
| |
| 376 target = '%s/%s' % (test_package, test_runner_junit4) | |
| 377 output_string = ''.join(device.StartInstrumentation( | |
| 378 target, extras=extras, timeout=30, retries=2)) | |
| 379 if output_string: | |
| 380 raise Exception('Test listing through %s failed on device:\n%s' % ( | |
| 381 test_runner_junit4, output_string)) | |
| 382 else: | |
| 383 raise Exception('JUnit4 Runner is not present in this apk') | |
| 384 with tempfile_ext.NamedTemporaryDirectory() as host_dir: | |
| 385 host_file = os.path.join(host_dir, 'list_tests.json') | |
| 386 device.PullFile(f.name, host_file) | |
| 387 with open(host_file, 'r') as host_file: | |
| 388 json_string = host_file.read() | |
| 389 return json.loads(json_string) | |
| 390 | |
| 339 | 391 |
| 340 def _SaveTestsToPickle(pickle_path, jar_path, tests): | 392 def _SaveTestsToPickle(pickle_path, jar_path, tests): |
| 341 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path] | 393 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path] |
| 342 pickle_data = { | 394 pickle_data = { |
| 343 'VERSION': _PICKLE_FORMAT_VERSION, | 395 'VERSION': _PICKLE_FORMAT_VERSION, |
| 344 'JAR_MD5SUM': jar_md5, | 396 'JAR_MD5SUM': jar_md5, |
| 345 'TEST_METHODS': tests, | 397 'TEST_METHODS': tests, |
| 346 } | 398 } |
| 347 with open(pickle_path, 'w') as pickle_file: | 399 with open(pickle_path, 'w') as pickle_file: |
| 348 pickle.dump(pickle_data, pickle_file) | 400 pickle.dump(pickle_data, pickle_file) |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 372 | 424 |
| 373 Args: | 425 Args: |
| 374 test: the instrumentation test dict. | 426 test: the instrumentation test dict. |
| 375 sep: the character(s) that should join the class name and the method name. | 427 sep: the character(s) that should join the class name and the method name. |
| 376 Returns: | 428 Returns: |
| 377 The test name as a string. | 429 The test name as a string. |
| 378 """ | 430 """ |
| 379 return '%s%s%s' % (test['class'], sep, test['method']) | 431 return '%s%s%s' % (test['class'], sep, test['method']) |
| 380 | 432 |
| 381 | 433 |
| 434 def GetTestNameWithoutParameterPostfix( | |
| 435 test, sep='#', parameter_postfix='__'): | |
|
mikecase (-- gone --)
2017/07/18 23:59:12
prefix? Or is it more of a parameter_postfix_prefi
the real yoland
2017/07/19 00:12:49
woah troll
| |
| 436 """Gets the name of the given JUnit4 test withouth parameter postfix. | |
|
mikecase (-- gone --)
2017/07/18 23:59:12
withouth
the real yoland
2017/07/19 00:12:49
Done
| |
| 437 | |
| 438 For most WebView JUnit4 javatests, each test is parameterizatized with | |
| 439 "__sandboxed_mode" to run in both non-sandboxed mode and sandboxed mode. | |
| 440 | |
| 441 This function returns the name of the test without parameterization | |
| 442 so test filters can match both parameterized and non-parameterized tests. | |
| 443 | |
| 444 Args: | |
| 445 test: the instrumentation test dict. | |
| 446 sep: the character(s) that should join the class name and the method name. | |
| 447 parameterization_sep: the character(s) that seperate method name and method | |
|
mikecase (-- gone --)
2017/07/18 23:59:11
Update this variable name to what is actually is.
the real yoland
2017/07/19 00:12:49
Done
| |
| 448 parameterization postfix. | |
| 449 Returns: | |
| 450 The test name without parameter postfix as a string. | |
| 451 """ | |
| 452 name = GetTestName(test, sep=sep) | |
| 453 return name.split(parameter_postfix)[0] | |
| 454 | |
| 455 | |
| 382 def GetUniqueTestName(test, sep='#'): | 456 def GetUniqueTestName(test, sep='#'): |
| 383 """Gets the unique name of the given test. | 457 """Gets the unique name of the given test. |
| 384 | 458 |
| 385 This will include text to disambiguate between tests for which GetTestName | 459 This will include text to disambiguate between tests for which GetTestName |
| 386 would return the same name. | 460 would return the same name. |
| 387 | 461 |
| 388 Args: | 462 Args: |
| 389 test: the instrumentation test dict. | 463 test: the instrumentation test dict. |
| 390 sep: the character(s) that should join the class name and the method name. | 464 sep: the character(s) that should join the class name and the method name. |
| 391 Returns: | 465 Returns: |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 761 return 'instrumentation' | 835 return 'instrumentation' |
| 762 | 836 |
| 763 #override | 837 #override |
| 764 def SetUp(self): | 838 def SetUp(self): |
| 765 self._data_deps.extend( | 839 self._data_deps.extend( |
| 766 self._data_deps_delegate(self._runtime_deps_path)) | 840 self._data_deps_delegate(self._runtime_deps_path)) |
| 767 | 841 |
| 768 def GetDataDependencies(self): | 842 def GetDataDependencies(self): |
| 769 return self._data_deps | 843 return self._data_deps |
| 770 | 844 |
| 771 def GetTests(self): | 845 def GetTests(self, device=None): |
| 772 if self.test_jar: | 846 if self._test_runner_junit4: |
| 847 tests = GetAllTestsFromRunner( | |
| 848 device, self.test_apk, self.test_package, | |
| 849 test_runner=self._test_runner, | |
| 850 test_runner_junit4=self.test_runner_junit4) | |
| 851 elif self.test_jar: | |
| 773 tests = GetAllTestsFromJar(self.test_jar) | 852 tests = GetAllTestsFromJar(self.test_jar) |
| 774 else: | 853 else: |
| 775 tests = GetAllTestsFromApk(self.test_apk.path) | 854 tests = GetAllTestsFromApk(self.test_apk.path) |
| 776 inflated_tests = self._ParameterizeTestsWithFlags(self._InflateTests(tests)) | 855 inflated_tests = self._ParameterizeTestsWithFlags(self._InflateTests(tests)) |
| 777 if self._test_runner_junit4 is None and any( | 856 if self._test_runner_junit4 is None and any( |
| 778 t['is_junit4'] for t in inflated_tests): | 857 t['is_junit4'] for t in inflated_tests): |
| 779 raise MissingJUnit4RunnerException() | 858 raise MissingJUnit4RunnerException() |
| 780 filtered_tests = FilterTests( | 859 filtered_tests = FilterTests( |
| 781 inflated_tests, self._test_filter, self._annotations, | 860 inflated_tests, self._test_filter, self._annotations, |
| 782 self._excluded_annotations) | 861 self._excluded_annotations) |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 840 | 919 |
| 841 @staticmethod | 920 @staticmethod |
| 842 def GenerateTestResults( | 921 def GenerateTestResults( |
| 843 result_code, result_bundle, statuses, start_ms, duration_ms): | 922 result_code, result_bundle, statuses, start_ms, duration_ms): |
| 844 return GenerateTestResults(result_code, result_bundle, statuses, | 923 return GenerateTestResults(result_code, result_bundle, statuses, |
| 845 start_ms, duration_ms) | 924 start_ms, duration_ms) |
| 846 | 925 |
| 847 #override | 926 #override |
| 848 def TearDown(self): | 927 def TearDown(self): |
| 849 pass | 928 pass |
| OLD | NEW |