Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: build/android/pylib/instrumentation/instrumentation_test_instance.py

Issue 2668203005: Reland allow JUnit3/4 tests within the same apk to be run by test_runner (Closed)
Patch Set: Change pickle version Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 collections 5 import collections
6 import copy 6 import copy
7 import logging 7 import logging
8 import os 8 import os
9 import pickle 9 import pickle
10 import re 10 import re
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 _EXTRA_DRIVER_TARGET_CLASS = ( 44 _EXTRA_DRIVER_TARGET_CLASS = (
45 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass') 45 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TargetClass')
46 _EXTRA_TIMEOUT_SCALE = ( 46 _EXTRA_TIMEOUT_SCALE = (
47 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TimeoutScale') 47 'org.chromium.test.driver.OnDeviceInstrumentationDriver.TimeoutScale')
48 48
49 _PARAMETERIZED_TEST_ANNOTATION = 'ParameterizedTest' 49 _PARAMETERIZED_TEST_ANNOTATION = 'ParameterizedTest'
50 _PARAMETERIZED_TEST_SET_ANNOTATION = 'ParameterizedTest$Set' 50 _PARAMETERIZED_TEST_SET_ANNOTATION = 'ParameterizedTest$Set'
51 _NATIVE_CRASH_RE = re.compile('(process|native) crash', re.IGNORECASE) 51 _NATIVE_CRASH_RE = re.compile('(process|native) crash', re.IGNORECASE)
52 _CMDLINE_NAME_SEGMENT_RE = re.compile( 52 _CMDLINE_NAME_SEGMENT_RE = re.compile(
53 r' with(?:out)? \{[^\}]*\}') 53 r' with(?:out)? \{[^\}]*\}')
54 _PICKLE_FORMAT_VERSION = 10 54 _PICKLE_FORMAT_VERSION = 11
55 55
56 56
57 class MissingSizeAnnotationError(test_exception.TestException): 57 class MissingSizeAnnotationError(test_exception.TestException):
58 def __init__(self, class_name): 58 def __init__(self, class_name):
59 super(MissingSizeAnnotationError, self).__init__(class_name + 59 super(MissingSizeAnnotationError, self).__init__(class_name +
60 ': Test method is missing required size annotation. Add one of: ' + 60 ': Test method is missing required size annotation. Add one of: ' +
61 ', '.join('@' + a for a in _VALID_ANNOTATIONS)) 61 ', '.join('@' + a for a in _VALID_ANNOTATIONS))
62 62
63 63
64 class TestListPickleException(test_exception.TestException): 64 class TestListPickleException(test_exception.TestException):
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 else: 348 else:
349 a = {} 349 a = {}
350 a.update(c['annotations']) 350 a.update(c['annotations'])
351 return a 351 return a
352 352
353 def stripped_test_class(c): 353 def stripped_test_class(c):
354 return { 354 return {
355 'class': c['class'], 355 'class': c['class'],
356 'annotations': recursive_class_annotations(c), 356 'annotations': recursive_class_annotations(c),
357 'methods': [m for m in c['methods'] if is_test_method(m)], 357 'methods': [m for m in c['methods'] if is_test_method(m)],
358 'superclass': c['superclass'],
358 } 359 }
359 360
360 return [stripped_test_class(c) for c in p['classes'] 361 return [stripped_test_class(c) for c in p['classes']
361 if is_test_class(c)] 362 if is_test_class(c)]
362 363
363 364
364 def _GetTestsFromDexdump(test_apk): 365 def _GetTestsFromDexdump(test_apk):
365 d = dexdump.Dump(test_apk) 366 dump = dexdump.Dump(test_apk)
366 tests = [] 367 tests = []
367 368
368 def get_test_methods(methods): 369 def get_test_methods(methods):
369 return [ 370 return [
370 { 371 {
371 'method': m, 372 'method': m,
372 # No annotation info is available from dexdump. 373 # No annotation info is available from dexdump.
373 # Set MediumTest annotation for default. 374 # Set MediumTest annotation for default.
374 'annotations': {'MediumTest': None}, 375 'annotations': {'MediumTest': None},
375 } for m in methods if m.startswith('test')] 376 } for m in methods if m.startswith('test')]
376 377
377 for package_name, package_info in d.iteritems(): 378 for package_name, package_info in dump.iteritems():
378 for class_name, class_info in package_info['classes'].iteritems(): 379 for class_name, class_info in package_info['classes'].iteritems():
379 if class_name.endswith('Test'): 380 if class_name.endswith('Test'):
380 tests.append({ 381 tests.append({
381 'class': '%s.%s' % (package_name, class_name), 382 'class': '%s.%s' % (package_name, class_name),
382 'annotations': {}, 383 'annotations': {},
383 'methods': get_test_methods(class_info['methods']), 384 'methods': get_test_methods(class_info['methods']),
385 'superclass': class_info['superclass'],
384 }) 386 })
385 return tests 387 return tests
386 388
387 389
388 def _SaveTestsToPickle(pickle_path, jar_path, tests): 390 def _SaveTestsToPickle(pickle_path, jar_path, tests):
389 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path] 391 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
390 pickle_data = { 392 pickle_data = {
391 'VERSION': _PICKLE_FORMAT_VERSION, 393 'VERSION': _PICKLE_FORMAT_VERSION,
392 'JAR_MD5SUM': jar_md5, 394 'JAR_MD5SUM': jar_md5,
393 'TEST_METHODS': tests, 395 'TEST_METHODS': tests,
394 } 396 }
395 with open(pickle_path, 'w') as pickle_file: 397 with open(pickle_path, 'w') as pickle_file:
396 pickle.dump(pickle_data, pickle_file) 398 pickle.dump(pickle_data, pickle_file)
397 399
398 400
401 class MissingJUnit4RunnerException(test_exception.TestException):
402 """Raised when JUnit4 runner is not provided or specified in apk manifest"""
403
404 def __init__(self):
405 super(MissingJUnit4RunnerException, self).__init__(
406 'JUnit4 runner is not provided or specified in test apk manifest.')
407
408
399 class UnmatchedFilterException(test_exception.TestException): 409 class UnmatchedFilterException(test_exception.TestException):
400 """Raised when a user specifies a filter that doesn't match any tests.""" 410 """Raised when a user specifies a filter that doesn't match any tests."""
401 411
402 def __init__(self, test_filter): 412 def __init__(self, test_filter):
403 super(UnmatchedFilterException, self).__init__( 413 super(UnmatchedFilterException, self).__init__(
404 'Test filter "%s" matched no tests.' % test_filter) 414 'Test filter "%s" matched no tests.' % test_filter)
405 415
406 416
407 def GetTestName(test, sep='#'): 417 def GetTestName(test, sep='#'):
408 """Gets the name of the given test. 418 """Gets the name of the given test.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 self._additional_apks = [] 459 self._additional_apks = []
450 self._apk_under_test = None 460 self._apk_under_test = None
451 self._apk_under_test_incremental_install_script = None 461 self._apk_under_test_incremental_install_script = None
452 self._package_info = None 462 self._package_info = None
453 self._suite = None 463 self._suite = None
454 self._test_apk = None 464 self._test_apk = None
455 self._test_apk_incremental_install_script = None 465 self._test_apk_incremental_install_script = None
456 self._test_jar = None 466 self._test_jar = None
457 self._test_package = None 467 self._test_package = None
458 self._test_runner = None 468 self._test_runner = None
469 self._test_runner_junit4 = None
459 self._test_support_apk = None 470 self._test_support_apk = None
460 self._initializeApkAttributes(args, error_func) 471 self._initializeApkAttributes(args, error_func)
461 472
462 self._data_deps = None 473 self._data_deps = None
463 self._data_deps_delegate = None 474 self._data_deps_delegate = None
464 self._runtime_deps_path = None 475 self._runtime_deps_path = None
465 self._initializeDataDependencyAttributes(args, data_deps_delegate) 476 self._initializeDataDependencyAttributes(args, data_deps_delegate)
466 477
467 self._annotations = None 478 self._annotations = None
468 self._excluded_annotations = None 479 self._excluded_annotations = None
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 if not os.path.exists(self._test_apk.path): 553 if not os.path.exists(self._test_apk.path):
543 error_func('Unable to find test APK: %s' % self._test_apk.path) 554 error_func('Unable to find test APK: %s' % self._test_apk.path)
544 if not self._test_jar: 555 if not self._test_jar:
545 logging.warning('Test jar not specified. Test runner will not have ' 556 logging.warning('Test jar not specified. Test runner will not have '
546 'Java annotation info available. May not handle test ' 557 'Java annotation info available. May not handle test '
547 'timeouts correctly.') 558 'timeouts correctly.')
548 elif not os.path.exists(self._test_jar): 559 elif not os.path.exists(self._test_jar):
549 error_func('Unable to find test JAR: %s' % self._test_jar) 560 error_func('Unable to find test JAR: %s' % self._test_jar)
550 561
551 self._test_package = self._test_apk.GetPackageName() 562 self._test_package = self._test_apk.GetPackageName()
552 self._test_runner = self._test_apk.GetInstrumentationName() 563 all_instrumentations = self._test_apk.GetAllInstrumentations()
564 junit3_runners = [
565 x for x in all_instrumentations if ('true' not in x.get(
566 'chromium-junit4', ''))]
567 junit4_runners = [
568 x for x in all_instrumentations if ('true' in x.get(
569 'chromium-junit4', ''))]
570
571 if len(junit3_runners) > 1:
572 logging.warning('This test apk has more than one JUnit3 instrumentation')
573 if len(junit4_runners) > 1:
574 logging.warning('This test apk has more than one JUnit4 instrumentation')
575
576 self._test_runner = (
577 junit3_runners[0]['android:name'] if junit3_runners else
578 self.test_apk.GetInstrumentationName())
579 self._test_runner_junit4 = (
580 junit4_runners[0]['android:name'] if junit4_runners else None)
553 581
554 self._package_info = None 582 self._package_info = None
555 if self._apk_under_test: 583 if self._apk_under_test:
556 package_under_test = self._apk_under_test.GetPackageName() 584 package_under_test = self._apk_under_test.GetPackageName()
557 for package_info in constants.PACKAGE_INFO.itervalues(): 585 for package_info in constants.PACKAGE_INFO.itervalues():
558 if package_under_test == package_info.package: 586 if package_under_test == package_info.package:
559 self._package_info = package_info 587 self._package_info = package_info
560 break 588 break
561 if not self._package_info: 589 if not self._package_info:
562 logging.warning('Unable to find package info for %s', self._test_package) 590 logging.warning('Unable to find package info for %s', self._test_package)
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
717 745
718 @property 746 @property
719 def test_package(self): 747 def test_package(self):
720 return self._test_package 748 return self._test_package
721 749
722 @property 750 @property
723 def test_runner(self): 751 def test_runner(self):
724 return self._test_runner 752 return self._test_runner
725 753
726 @property 754 @property
755 def test_runner_junit4(self):
756 return self._test_runner_junit4
757
758 @property
727 def timeout_scale(self): 759 def timeout_scale(self):
728 return self._timeout_scale 760 return self._timeout_scale
729 761
730 #override 762 #override
731 def TestType(self): 763 def TestType(self):
732 return 'instrumentation' 764 return 'instrumentation'
733 765
734 #override 766 #override
735 def SetUp(self): 767 def SetUp(self):
736 self._data_deps.extend( 768 self._data_deps.extend(
737 self._data_deps_delegate(self._runtime_deps_path)) 769 self._data_deps_delegate(self._runtime_deps_path))
738 770
739 def GetDataDependencies(self): 771 def GetDataDependencies(self):
740 return self._data_deps 772 return self._data_deps
741 773
742 def GetTests(self): 774 def GetTests(self):
743 if self.test_jar: 775 if self.test_jar:
744 tests = GetAllTestsFromJar(self.test_jar) 776 tests = GetAllTestsFromJar(self.test_jar)
745 else: 777 else:
746 tests = GetAllTestsFromApk(self.test_apk.path) 778 tests = GetAllTestsFromApk(self.test_apk.path)
747 inflated_tests = self._ParametrizeTestsWithFlags(self._InflateTests(tests)) 779 inflated_tests = self._ParametrizeTestsWithFlags(self._InflateTests(tests))
780 if self._test_runner_junit4 is None and any(
781 t['is_junit4'] for t in inflated_tests):
782 raise MissingJUnit4RunnerException()
748 filtered_tests = FilterTests( 783 filtered_tests = FilterTests(
749 inflated_tests, self._test_filter, self._annotations, 784 inflated_tests, self._test_filter, self._annotations,
750 self._excluded_annotations) 785 self._excluded_annotations)
751 if self._test_filter and not filtered_tests: 786 if self._test_filter and not filtered_tests:
752 for t in inflated_tests: 787 for t in inflated_tests:
753 logging.debug(' %s', GetUniqueTestName(t)) 788 logging.debug(' %s', GetUniqueTestName(t))
754 raise UnmatchedFilterException(self._test_filter) 789 raise UnmatchedFilterException(self._test_filter)
755 return filtered_tests 790 return filtered_tests
756 791
757 # pylint: disable=no-self-use 792 # pylint: disable=no-self-use
758 def _InflateTests(self, tests): 793 def _InflateTests(self, tests):
759 inflated_tests = [] 794 inflated_tests = []
760 for c in tests: 795 for c in tests:
761 for m in c['methods']: 796 for m in c['methods']:
762 a = dict(c['annotations']) 797 a = dict(c['annotations'])
763 a.update(m['annotations']) 798 a.update(m['annotations'])
764 inflated_tests.append({ 799 inflated_tests.append({
765 'class': c['class'], 800 'class': c['class'],
766 'method': m['method'], 801 'method': m['method'],
767 'annotations': a, 802 'annotations': a,
803 'is_junit4': c['superclass'] == 'java.lang.Object'
768 }) 804 })
769 return inflated_tests 805 return inflated_tests
770 806
771 def _ParametrizeTestsWithFlags(self, tests): 807 def _ParametrizeTestsWithFlags(self, tests):
772 new_tests = [] 808 new_tests = []
773 for t in tests: 809 for t in tests:
774 parameters = ParseCommandLineFlagParameters(t['annotations']) 810 parameters = ParseCommandLineFlagParameters(t['annotations'])
775 if parameters: 811 if parameters:
776 t['flags'] = parameters[0] 812 t['flags'] = parameters[0]
777 for p in parameters[1:]: 813 for p in parameters[1:]:
(...skipping 25 matching lines...) Expand all
803 839
804 @staticmethod 840 @staticmethod
805 def GenerateTestResults( 841 def GenerateTestResults(
806 result_code, result_bundle, statuses, start_ms, duration_ms): 842 result_code, result_bundle, statuses, start_ms, duration_ms):
807 return GenerateTestResults(result_code, result_bundle, statuses, 843 return GenerateTestResults(result_code, result_bundle, statuses,
808 start_ms, duration_ms) 844 start_ms, duration_ms)
809 845
810 #override 846 #override
811 def TearDown(self): 847 def TearDown(self):
812 pass 848 pass
OLDNEW
« no previous file with comments | « build/android/lint/suppressions.xml ('k') | build/android/pylib/instrumentation/instrumentation_test_instance_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698