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

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

Issue 2935503002: List Java Instru Test Information From JUnit Runner (Closed)
Patch Set: address comments Created 3 years, 5 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 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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698