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 |
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_exception | 16 from pylib.base import test_exception |
16 from pylib.base import test_instance | 17 from pylib.base import test_instance |
17 from pylib.constants import host_paths | 18 from pylib.constants import host_paths |
18 from pylib.instrumentation import test_result | 19 from pylib.instrumentation import test_result |
19 from pylib.instrumentation import instrumentation_parser | 20 from pylib.instrumentation import instrumentation_parser |
20 from pylib.utils import dexdump | 21 from pylib.utils import dexdump |
21 from pylib.utils import proguard | 22 from pylib.utils import proguard |
22 from pylib.utils import shared_preference_utils | 23 from pylib.utils import shared_preference_utils |
24 from py_utils import tempfile_ext | |
23 | 25 |
24 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): | 26 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH): |
25 import unittest_util # pylint: disable=import-error | 27 import unittest_util # pylint: disable=import-error |
26 | 28 |
27 # Ref: http://developer.android.com/reference/android/app/Activity.html | 29 # Ref: http://developer.android.com/reference/android/app/Activity.html |
28 _ACTIVITY_RESULT_CANCELED = 0 | 30 _ACTIVITY_RESULT_CANCELED = 0 |
29 _ACTIVITY_RESULT_OK = -1 | 31 _ACTIVITY_RESULT_OK = -1 |
30 | 32 |
31 _COMMAND_LINE_PARAMETER = 'cmdlinearg-parameter' | 33 _COMMAND_LINE_PARAMETER = 'cmdlinearg-parameter' |
32 _DEFAULT_ANNOTATIONS = [ | 34 _DEFAULT_ANNOTATIONS = [ |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 unqualified_class_test = { | 180 unqualified_class_test = { |
179 'class': t['class'].split('.')[-1], | 181 'class': t['class'].split('.')[-1], |
180 'method': t['method'] | 182 'method': t['method'] |
181 } | 183 } |
182 names = [ | 184 names = [ |
183 GetTestName(t, sep='.'), | 185 GetTestName(t, sep='.'), |
184 GetTestName(unqualified_class_test, sep='.'), | 186 GetTestName(unqualified_class_test, sep='.'), |
185 GetUniqueTestName(t, sep='.') | 187 GetUniqueTestName(t, sep='.') |
186 ] | 188 ] |
187 | 189 |
190 if t['is_junit4']: | |
191 names += [ | |
192 GetTestNameWithoutParameterPostfix(t, sep='.'), | |
jbudorick
2017/07/14 18:43:55
These make it so that, if someone passes the test
the real yoland
2017/07/18 04:20:21
I think this just makes that if someone pass in te
| |
193 GetTestNameWithoutParameterPostfix(unqualified_class_test, sep='.') | |
194 ] | |
195 | |
188 pattern_groups = test_filter.split('-') | 196 pattern_groups = test_filter.split('-') |
189 if len(pattern_groups) > 1: | 197 if len(pattern_groups) > 1: |
190 negative_filter = pattern_groups[1] | 198 negative_filter = pattern_groups[1] |
191 if unittest_util.FilterTestNames(names, negative_filter): | 199 if unittest_util.FilterTestNames(names, negative_filter): |
192 return [] | 200 return [] |
193 | 201 |
194 positive_filter = pattern_groups[0] | 202 positive_filter = pattern_groups[0] |
195 return unittest_util.FilterTestNames(names, positive_filter) | 203 return unittest_util.FilterTestNames(names, positive_filter) |
196 | 204 |
197 def annotation_filter(all_annotations): | 205 def annotation_filter(all_annotations): |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
232 | 240 |
233 if (not annotation_filter(t['annotations']) | 241 if (not annotation_filter(t['annotations']) |
234 or not excluded_annotation_filter(t['annotations'])): | 242 or not excluded_annotation_filter(t['annotations'])): |
235 continue | 243 continue |
236 | 244 |
237 filtered_tests.append(t) | 245 filtered_tests.append(t) |
238 | 246 |
239 return filtered_tests | 247 return filtered_tests |
240 | 248 |
241 | 249 |
250 def GetAllTestsFromRunner(device, test_apk_path, test_package, filename, | |
251 test_runner=None, test_runner_junit4=None): | |
252 pickle_path = '%s-runner.pickle' % test_apk_path | |
253 try: | |
254 tests = _GetAllTestsFromRunner(device, test_package, filename, | |
jbudorick
2017/07/14 18:43:55
What's going on here? Why does it get the tests fr
the real yoland
2017/07/18 04:20:21
oops, my bad
Done
| |
255 test_runner, test_runner_junit4) | |
256 tests = _GetTestsFromPickle(pickle_path, test_apk_path) | |
257 except TestListPickleException as e: | |
258 logging.info('Could not get tests from pickle: %s', e) | |
259 logging.info('Getting tests by print tests in instrumentation runner') | |
260 tests = _GetAllTestsFromRunner(device, test_package, filename, | |
261 test_runner, test_runner_junit4) | |
262 _SaveTestsToPickle(pickle_path, test_apk_path, tests) | |
263 return tests | |
264 | |
265 | |
266 # TODO(yolandyan): remove this once the tests are converted to junit4 | |
242 def GetAllTestsFromJar(test_jar): | 267 def GetAllTestsFromJar(test_jar): |
243 pickle_path = '%s-proguard.pickle' % test_jar | 268 pickle_path = '%s-proguard.pickle' % test_jar |
244 try: | 269 try: |
245 tests = _GetTestsFromPickle(pickle_path, test_jar) | 270 tests = _GetTestsFromPickle(pickle_path, test_jar) |
246 except TestListPickleException as e: | 271 except TestListPickleException as e: |
247 logging.info('Could not get tests from pickle: %s', e) | 272 logging.info('Could not get tests from pickle: %s', e) |
248 logging.info('Getting tests from JAR via proguard.') | 273 logging.info('Getting tests from JAR via proguard.') |
249 tests = _GetTestsFromProguard(test_jar) | 274 tests = _GetTestsFromProguard(test_jar) |
250 _SaveTestsToPickle(pickle_path, test_jar, tests) | 275 _SaveTestsToPickle(pickle_path, test_jar, tests) |
251 return tests | 276 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(): | 354 for class_name, class_info in package_info['classes'].iteritems(): |
330 if class_name.endswith('Test'): | 355 if class_name.endswith('Test'): |
331 tests.append({ | 356 tests.append({ |
332 'class': '%s.%s' % (package_name, class_name), | 357 'class': '%s.%s' % (package_name, class_name), |
333 'annotations': {}, | 358 'annotations': {}, |
334 'methods': get_test_methods(class_info['methods']), | 359 'methods': get_test_methods(class_info['methods']), |
335 'superclass': class_info['superclass'], | 360 'superclass': class_info['superclass'], |
336 }) | 361 }) |
337 return tests | 362 return tests |
338 | 363 |
364 def _GetAllTestsFromRunner(device, test_package, filename, | |
365 test_runner=None, test_runner_junit4=None): | |
366 device_path = os.path.join(device.GetExternalStoragePath(), | |
jbudorick
2017/07/14 18:43:55
just use a device temp file: https://codesearch.ch
the real yoland
2017/07/18 04:20:22
Done
| |
367 'chromium_tests_root', filename) | |
368 device.RunShellCommand(['rm', device_path], check_return=False) | |
369 if test_runner is None and test_runner_junit4 is None: | |
370 raise Exception('Test runner does NOT exist for this test apk') | |
371 if test_runner_junit4: | |
jbudorick
2017/07/14 18:43:56
If there is no test_runner_junit4, it looks like w
the real yoland
2017/07/18 04:20:21
Done
| |
372 extras = {} | |
373 extras['listAllTests'] = filename | |
374 extras['log'] = 'true' | |
375 extras['package'] = 'org.chromium' | |
376 target = '%s/%s' % (test_package, test_runner_junit4) | |
377 output_string = ''.join(device.StartInstrumentation( | |
378 target, extras=extras, timeout=30, retries=0)) | |
jbudorick
2017/07/14 18:43:55
No retries?
the real yoland
2017/07/18 04:20:22
Set retries to 2?
Done
| |
379 if output_string: | |
380 raise Exception('Test listing through %s failed on device:\n%s' % ( | |
381 test_runner_junit4, output_string)) | |
382 with tempfile_ext.NamedTemporaryDirectory() as host_dir: | |
383 host_file = os.path.join(host_dir, filename) | |
384 device.PullFile(device_path, host_dir) | |
385 with open(host_file, 'r') as f: | |
386 json_string = f.read() | |
387 return json.loads(json_string) | |
388 | |
339 | 389 |
340 def _SaveTestsToPickle(pickle_path, jar_path, tests): | 390 def _SaveTestsToPickle(pickle_path, jar_path, tests): |
341 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path] | 391 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path] |
342 pickle_data = { | 392 pickle_data = { |
343 'VERSION': _PICKLE_FORMAT_VERSION, | 393 'VERSION': _PICKLE_FORMAT_VERSION, |
344 'JAR_MD5SUM': jar_md5, | 394 'JAR_MD5SUM': jar_md5, |
345 'TEST_METHODS': tests, | 395 'TEST_METHODS': tests, |
346 } | 396 } |
347 with open(pickle_path, 'w') as pickle_file: | 397 with open(pickle_path, 'w') as pickle_file: |
348 pickle.dump(pickle_data, pickle_file) | 398 pickle.dump(pickle_data, pickle_file) |
(...skipping 23 matching lines...) Expand all Loading... | |
372 | 422 |
373 Args: | 423 Args: |
374 test: the instrumentation test dict. | 424 test: the instrumentation test dict. |
375 sep: the character(s) that should join the class name and the method name. | 425 sep: the character(s) that should join the class name and the method name. |
376 Returns: | 426 Returns: |
377 The test name as a string. | 427 The test name as a string. |
378 """ | 428 """ |
379 return '%s%s%s' % (test['class'], sep, test['method']) | 429 return '%s%s%s' % (test['class'], sep, test['method']) |
380 | 430 |
381 | 431 |
432 def GetTestNameWithoutParameterPostfix( | |
433 test, sep='#', parameter_postfix='__'): | |
434 """Gets the name of the given JUnit4 test withouth parameter postfix. | |
435 | |
436 For most WebView JUnit4 javatests, each test is parameterizatized with | |
437 "__sandboxed_mode" to run in both non-sandboxed mode and sandboxed mode. | |
438 | |
439 This function returns the name of the test without parameterization | |
440 so test filters can match both parameterized and non-parameterized tests. | |
441 | |
442 Args: | |
443 test: the instrumentation test dict. | |
444 sep: the character(s) that should join the class name and the method name. | |
445 parameterization_sep: the character(s) that seperate method name and method | |
446 parameterization postfix. | |
447 Returns: | |
448 The test name without parameter postfix as a string. | |
449 """ | |
450 name = GetTestName(test, sep=sep) | |
451 return name.split(parameter_postfix)[0] | |
452 | |
453 | |
382 def GetUniqueTestName(test, sep='#'): | 454 def GetUniqueTestName(test, sep='#'): |
383 """Gets the unique name of the given test. | 455 """Gets the unique name of the given test. |
384 | 456 |
385 This will include text to disambiguate between tests for which GetTestName | 457 This will include text to disambiguate between tests for which GetTestName |
386 would return the same name. | 458 would return the same name. |
387 | 459 |
388 Args: | 460 Args: |
389 test: the instrumentation test dict. | 461 test: the instrumentation test dict. |
390 sep: the character(s) that should join the class name and the method name. | 462 sep: the character(s) that should join the class name and the method name. |
391 Returns: | 463 Returns: |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
761 return 'instrumentation' | 833 return 'instrumentation' |
762 | 834 |
763 #override | 835 #override |
764 def SetUp(self): | 836 def SetUp(self): |
765 self._data_deps.extend( | 837 self._data_deps.extend( |
766 self._data_deps_delegate(self._runtime_deps_path)) | 838 self._data_deps_delegate(self._runtime_deps_path)) |
767 | 839 |
768 def GetDataDependencies(self): | 840 def GetDataDependencies(self): |
769 return self._data_deps | 841 return self._data_deps |
770 | 842 |
771 def GetTests(self): | 843 def GetTests(self, device=None): |
772 if self.test_jar: | 844 filename = 'list_all_tests.json' |
845 if self._test_runner_junit4 and device: | |
846 tests = GetAllTestsFromRunner( | |
847 device, self.test_apk.path, self.test_package, filename, | |
848 test_runner=self._test_runner, | |
849 test_runner_junit4=self.test_runner_junit4) | |
850 elif self.test_jar: | |
773 tests = GetAllTestsFromJar(self.test_jar) | 851 tests = GetAllTestsFromJar(self.test_jar) |
774 else: | 852 else: |
775 tests = GetAllTestsFromApk(self.test_apk.path) | 853 tests = GetAllTestsFromApk(self.test_apk.path) |
776 inflated_tests = self._ParameterizeTestsWithFlags(self._InflateTests(tests)) | 854 inflated_tests = self._ParameterizeTestsWithFlags(self._InflateTests(tests)) |
777 if self._test_runner_junit4 is None and any( | 855 if self._test_runner_junit4 is None and any( |
778 t['is_junit4'] for t in inflated_tests): | 856 t['is_junit4'] for t in inflated_tests): |
779 raise MissingJUnit4RunnerException() | 857 raise MissingJUnit4RunnerException() |
780 filtered_tests = FilterTests( | 858 filtered_tests = FilterTests( |
781 inflated_tests, self._test_filter, self._annotations, | 859 inflated_tests, self._test_filter, self._annotations, |
782 self._excluded_annotations) | 860 self._excluded_annotations) |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
840 | 918 |
841 @staticmethod | 919 @staticmethod |
842 def GenerateTestResults( | 920 def GenerateTestResults( |
843 result_code, result_bundle, statuses, start_ms, duration_ms): | 921 result_code, result_bundle, statuses, start_ms, duration_ms): |
844 return GenerateTestResults(result_code, result_bundle, statuses, | 922 return GenerateTestResults(result_code, result_bundle, statuses, |
845 start_ms, duration_ms) | 923 start_ms, duration_ms) |
846 | 924 |
847 #override | 925 #override |
848 def TearDown(self): | 926 def TearDown(self): |
849 pass | 927 pass |
OLD | NEW |