OLD | NEW |
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2013 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 """Helper class for instrumenation test jar.""" | 5 """Helper class for instrumenation test jar.""" |
6 | 6 |
7 import collections | 7 import collections |
8 import logging | 8 import logging |
9 import os | 9 import os |
10 import pickle | 10 import pickle |
11 import re | 11 import re |
12 | 12 |
13 from pylib import cmd_helper | 13 from pylib import cmd_helper |
14 from pylib import constants | 14 from pylib import constants |
15 | 15 |
16 | 16 |
17 # If you change the cached output of proguard, increment this number | 17 # If you change the cached output of proguard, increment this number |
18 PICKLE_FORMAT_VERSION = 1 | 18 PICKLE_FORMAT_VERSION = 1 |
19 | 19 |
20 | 20 |
21 class TestJar(object): | 21 class TestJar(object): |
| 22 _ANNOTATIONS = frozenset( |
| 23 ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest', 'EnormousTest', |
| 24 'FlakyTest', 'DisabledTest', 'Manual', 'PerfTest']) |
| 25 _DEFAULT_ANNOTATION = 'SmallTest' |
| 26 _PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$') |
| 27 _PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$') |
| 28 _PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$') |
| 29 _PROGUARD_ANNOTATION_CONST_RE = ( |
| 30 re.compile(r'\s*?- Constant element value.*$')) |
| 31 _PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$') |
| 32 |
22 def __init__(self, jar_path): | 33 def __init__(self, jar_path): |
| 34 if not os.path.exists(jar_path): |
| 35 raise Exception('%s not found, please build it' % jar_path) |
| 36 |
23 sdk_root = os.getenv('ANDROID_SDK_ROOT', constants.ANDROID_SDK_ROOT) | 37 sdk_root = os.getenv('ANDROID_SDK_ROOT', constants.ANDROID_SDK_ROOT) |
24 self._PROGUARD_PATH = os.path.join(sdk_root, | 38 self._PROGUARD_PATH = os.path.join(sdk_root, |
25 'tools/proguard/bin/proguard.sh') | 39 'tools/proguard/bin/proguard.sh') |
26 if not os.path.exists(self._PROGUARD_PATH): | 40 if not os.path.exists(self._PROGUARD_PATH): |
27 self._PROGUARD_PATH = os.path.join(os.environ['ANDROID_BUILD_TOP'], | 41 self._PROGUARD_PATH = os.path.join(os.environ['ANDROID_BUILD_TOP'], |
28 'external/proguard/bin/proguard.sh') | 42 'external/proguard/bin/proguard.sh') |
29 self._PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$') | |
30 self._PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$') | |
31 self._PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$') | |
32 self._PROGUARD_ANNOTATION_CONST_RE = ( | |
33 re.compile(r'\s*?- Constant element value.*$')) | |
34 self._PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$') | |
35 | |
36 if not os.path.exists(jar_path): | |
37 raise Exception('%s not found, please build it' % jar_path) | |
38 self._jar_path = jar_path | 43 self._jar_path = jar_path |
39 self._annotation_map = collections.defaultdict(list) | 44 self._annotation_map = collections.defaultdict(list) |
40 self._pickled_proguard_name = self._jar_path + '-proguard.pickle' | 45 self._pickled_proguard_name = self._jar_path + '-proguard.pickle' |
41 self._test_methods = [] | 46 self._test_methods = [] |
42 if not self._GetCachedProguardData(): | 47 if not self._GetCachedProguardData(): |
43 self._GetProguardData() | 48 self._GetProguardData() |
44 | 49 |
45 def _GetCachedProguardData(self): | 50 def _GetCachedProguardData(self): |
46 if (os.path.exists(self._pickled_proguard_name) and | 51 if (os.path.exists(self._pickled_proguard_name) and |
47 (os.path.getmtime(self._pickled_proguard_name) > | 52 (os.path.getmtime(self._pickled_proguard_name) > |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 def GetAnnotatedTests(self, annotation_filter_list): | 156 def GetAnnotatedTests(self, annotation_filter_list): |
152 """Returns a list of all tests that match the given annotation filters.""" | 157 """Returns a list of all tests that match the given annotation filters.""" |
153 return [test for test, annotations in self._GetAnnotationMap().iteritems() | 158 return [test for test, annotations in self._GetAnnotationMap().iteritems() |
154 if self._IsTestMethod(test) and self._AnnotationsMatchFilters( | 159 if self._IsTestMethod(test) and self._AnnotationsMatchFilters( |
155 annotation_filter_list, annotations)] | 160 annotation_filter_list, annotations)] |
156 | 161 |
157 def GetTestMethods(self): | 162 def GetTestMethods(self): |
158 """Returns a list of all test methods in this apk as Class#testMethod.""" | 163 """Returns a list of all test methods in this apk as Class#testMethod.""" |
159 return self._test_methods | 164 return self._test_methods |
160 | 165 |
| 166 def _GetTestsMissingAnnotation(self): |
| 167 """Get a list of test methods with no known annotations.""" |
| 168 tests_missing_annotations = [] |
| 169 for test_method in self.GetTestMethods(): |
| 170 annotations_ = frozenset(self.GetTestAnnotations(test_method)) |
| 171 if (annotations_.isdisjoint(self._ANNOTATIONS) and |
| 172 not self.IsPythonDrivenTest(test_method)): |
| 173 tests_missing_annotations.append(test_method) |
| 174 return sorted(tests_missing_annotations) |
| 175 |
| 176 def _GetAllMatchingTests(self, annotation_filter_list, test_filter): |
| 177 """Get a list of tests matching any of the annotations and the filter. |
| 178 |
| 179 Args: |
| 180 annotation_filter_list: List of test annotations. A test must have at |
| 181 least one of the these annotations. A test without any annotations |
| 182 is considered to be SmallTest. |
| 183 test_filter: Filter used for partial matching on the test method names. |
| 184 |
| 185 Returns: |
| 186 List of all matching tests. |
| 187 """ |
| 188 if annotation_filter_list: |
| 189 available_tests = self.GetAnnotatedTests(annotation_filter_list) |
| 190 # Include un-annotated tests in SmallTest. |
| 191 if annotation_filter_list.count(self._DEFAULT_ANNOTATION) > 0: |
| 192 for test in self._GetTestsMissingAnnotation(): |
| 193 logging.warning( |
| 194 '%s has no annotations. Assuming "%s".', test, |
| 195 self._DEFAULT_ANNOTATION) |
| 196 available_tests.append(test) |
| 197 else: |
| 198 available_tests = [m for m in self.GetTestMethods() |
| 199 if not self.IsPythonDrivenTest(m)] |
| 200 |
| 201 tests = [] |
| 202 if test_filter: |
| 203 # |available_tests| are in adb instrument format: package.path.class#test. |
| 204 filter_without_hash = test_filter.replace('#', '.') |
| 205 tests = [t for t in available_tests |
| 206 if filter_without_hash in t.replace('#', '.')] |
| 207 else: |
| 208 tests = available_tests |
| 209 |
| 210 return tests |
| 211 |
161 @staticmethod | 212 @staticmethod |
162 def IsPythonDrivenTest(test): | 213 def IsPythonDrivenTest(test): |
163 return 'pythonDrivenTests' in test | 214 return 'pythonDrivenTests' in test |
OLD | NEW |