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

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

Issue 1851143002: Find annotated tests by exposing API in instrumentation_test_instance (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 to_add = [] 180 to_add = []
181 to_remove = [] 181 to_remove = []
182 for a in p.get('arguments', []): 182 for a in p.get('arguments', []):
183 if a['name'] == 'add': 183 if a['name'] == 'add':
184 to_add = ['--%s' % f for f in a['stringArray']] 184 to_add = ['--%s' % f for f in a['stringArray']]
185 elif a['name'] == 'remove': 185 elif a['name'] == 'remove':
186 to_remove = ['--%s' % f for f in a['stringArray']] 186 to_remove = ['--%s' % f for f in a['stringArray']]
187 result.append(ParamsTuple(to_add, to_remove)) 187 result.append(ParamsTuple(to_add, to_remove))
188 return result if result else None 188 return result if result else None
189 189
190 def GetTestsFromPickle(pickle_path, jar_path):
jbudorick 2016/04/06 17:28:33 Can you upload a version of tools/android/find_dis
Yoland Yan(Google) 2016/04/06 19:30:32 Done.
191 """Doc stub"""
192 if not os.path.exists(pickle_path):
193 raise ProguardPickleException('%s does not exist.' % pickle_path)
194 if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path):
195 raise ProguardPickleException(
196 '%s newer than %s.' % (jar_path, pickle_path))
197
198 with open(pickle_path, 'r') as pickle_file:
199 pickle_data = pickle.loads(pickle_file.read())
200 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
201
202 try:
203 if pickle_data['VERSION'] != _PICKLE_FORMAT_VERSION:
204 raise ProguardPickleException('PICKLE_FORMAT_VERSION has changed.')
205 if pickle_data['JAR_MD5SUM'] != jar_md5:
206 raise ProguardPickleException('JAR file MD5 sum differs.')
207 return pickle_data['TEST_METHODS']
208 except TypeError as e:
209 logging.error(pickle_data)
210 raise ProguardPickleException(str(e))
211
212 # pylint: disable=no-self-use
213 def GetTestsFromProguard(jar_path):
214 """Doc stub"""
215 p = proguard.Dump(jar_path)
216
217 def is_test_class(c):
218 return c['class'].endswith('Test')
219
220 def is_test_method(m):
221 return m['method'].startswith('test')
222
223 class_lookup = dict((c['class'], c) for c in p['classes'])
224 def recursive_get_class_annotations(c):
225 s = c['superclass']
226 if s in class_lookup:
227 a = recursive_get_class_annotations(class_lookup[s])
228 else:
229 a = {}
230 a.update(c['annotations'])
231 return a
232
233 def stripped_test_class(c):
234 return {
235 'class': c['class'],
236 'annotations': recursive_get_class_annotations(c),
237 'methods': [m for m in c['methods'] if is_test_method(m)],
238 }
239
240 return [stripped_test_class(c) for c in p['classes']
241 if is_test_class(c)]
242
243 def SaveTestsToPickle(pickle_path, jar_path, tests):
244 """Doc stub"""
245 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
246 pickle_data = {
247 'VERSION': _PICKLE_FORMAT_VERSION,
248 'JAR_MD5SUM': jar_md5,
249 'TEST_METHODS': tests,
250 }
251 with open(pickle_path, 'w') as pickle_file:
252 pickle.dump(pickle_data, pickle_file)
253
254 def GetFilteredTests(test_jar, test_filter, annotations, exclude_annotations):
255 """Doc stub"""
256 pickle_path = '%s-proguard.pickle' % test_jar
257 try:
258 tests = GetTestsFromPickle(pickle_path, test_jar)
259 except ProguardPickleException as e:
260 logging.info('Getting tests from JAR via proguard. (%s)', str(e))
261 tests = GetTestsFromProguard(test_jar)
262 SaveTestsToPickle(pickle_path, test_jar, tests)
263 filtered_tests = FilterTests(tests, test_filter, annotations,
264 exclude_annotations)
265 return filtered_tests
266
267 def FilterTests(tests, test_filter, annotations, excluded_annotations):
268 """Doc stub"""
269
270 def gtest_filter(c, m):
271 t = ['%s.%s' % (c['class'].split('.')[-1], m['method'])]
272 return (not test_filter
273 or unittest_util.FilterTestNames(t, test_filter))
274
275 def annotation_filter(all_annotations):
276 if not annotations:
277 return True
278 return any_annotation_matches(annotations, all_annotations)
279
280 def excluded_annotation_filter(all_annotations):
281 if not excluded_annotations:
282 return True
283 return not any_annotation_matches(excluded_annotations,
284 all_annotations)
285
286 def any_annotation_matches(annotations, all_annotations):
287 return any(
288 ak in all_annotations and (av is None or av == all_annotations[ak])
289 for ak, av in annotations.iteritems())
290
291 filtered_classes = []
292 for c in tests:
293 filtered_methods = []
294 for m in c['methods']:
295 # Gtest filtering
296 if not gtest_filter(c, m):
297 continue
298
299 all_annotations = dict(c['annotations'])
300 all_annotations.update(m['annotations'])
301 if (not annotation_filter(all_annotations)
302 or not excluded_annotation_filter(all_annotations)):
303 continue
304
305 filtered_methods.append(m)
306
307 if filtered_methods:
308 filtered_class = dict(c)
309 filtered_class['methods'] = filtered_methods
310 filtered_classes.append(filtered_class)
311
312 return filtered_classes
313
314 class ProguardPickleException(Exception):
315 pass
190 316
191 class InstrumentationTestInstance(test_instance.TestInstance): 317 class InstrumentationTestInstance(test_instance.TestInstance):
192 318
193 def __init__(self, args, isolate_delegate, error_func): 319 def __init__(self, args, isolate_delegate, error_func):
194 super(InstrumentationTestInstance, self).__init__() 320 super(InstrumentationTestInstance, self).__init__()
195 321
196 self._additional_apks = [] 322 self._additional_apks = []
197 self._apk_under_test = None 323 self._apk_under_test = None
198 self._apk_under_test_incremental_install_script = None 324 self._apk_under_test_incremental_install_script = None
199 self._package_info = None 325 self._package_info = None
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 device_rel_path, host_rel_path = t.split(':') 584 device_rel_path, host_rel_path = t.split(':')
459 host_abs_path = os.path.join(host_paths.DIR_SOURCE_ROOT, host_rel_path) 585 host_abs_path = os.path.join(host_paths.DIR_SOURCE_ROOT, host_rel_path)
460 self._data_deps.extend( 586 self._data_deps.extend(
461 [(host_abs_path, 587 [(host_abs_path,
462 [None, 'chrome', 'test', 'data', device_rel_path])]) 588 [None, 'chrome', 'test', 'data', device_rel_path])])
463 589
464 def GetDataDependencies(self): 590 def GetDataDependencies(self):
465 return self._data_deps 591 return self._data_deps
466 592
467 def GetTests(self): 593 def GetTests(self):
468 pickle_path = '%s-proguard.pickle' % self.test_jar 594 filtered_tests = GetFilteredTests(
469 try: 595 self.test_jar,
470 tests = self._GetTestsFromPickle(pickle_path, self.test_jar) 596 self._test_filter,
471 except self.ProguardPickleException as e: 597 self._annotations,
472 logging.info('Getting tests from JAR via proguard. (%s)', str(e)) 598 self._excluded_annotations)
473 tests = self._GetTestsFromProguard(self.test_jar) 599 return self._ParametrizeTestsWithFlags(self._InflateTests(filtered_tests))
474 self._SaveTestsToPickle(pickle_path, self.test_jar, tests)
475 return self._ParametrizeTestsWithFlags(
476 self._InflateTests(self._FilterTests(tests)))
477
478 class ProguardPickleException(Exception):
479 pass
480
481 def _GetTestsFromPickle(self, pickle_path, jar_path):
482 if not os.path.exists(pickle_path):
483 raise self.ProguardPickleException('%s does not exist.' % pickle_path)
484 if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path):
485 raise self.ProguardPickleException(
486 '%s newer than %s.' % (jar_path, pickle_path))
487
488 with open(pickle_path, 'r') as pickle_file:
489 pickle_data = pickle.loads(pickle_file.read())
490 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
491
492 try:
493 if pickle_data['VERSION'] != _PICKLE_FORMAT_VERSION:
494 raise self.ProguardPickleException('PICKLE_FORMAT_VERSION has changed.')
495 if pickle_data['JAR_MD5SUM'] != jar_md5:
496 raise self.ProguardPickleException('JAR file MD5 sum differs.')
497 return pickle_data['TEST_METHODS']
498 except TypeError as e:
499 logging.error(pickle_data)
500 raise self.ProguardPickleException(str(e))
501
502 # pylint: disable=no-self-use
503 def _GetTestsFromProguard(self, jar_path):
504 p = proguard.Dump(jar_path)
505
506 def is_test_class(c):
507 return c['class'].endswith('Test')
508
509 def is_test_method(m):
510 return m['method'].startswith('test')
511
512 class_lookup = dict((c['class'], c) for c in p['classes'])
513 def recursive_get_class_annotations(c):
514 s = c['superclass']
515 if s in class_lookup:
516 a = recursive_get_class_annotations(class_lookup[s])
517 else:
518 a = {}
519 a.update(c['annotations'])
520 return a
521
522 def stripped_test_class(c):
523 return {
524 'class': c['class'],
525 'annotations': recursive_get_class_annotations(c),
526 'methods': [m for m in c['methods'] if is_test_method(m)],
527 }
528
529 return [stripped_test_class(c) for c in p['classes']
530 if is_test_class(c)]
531
532 def _SaveTestsToPickle(self, pickle_path, jar_path, tests):
533 jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
534 pickle_data = {
535 'VERSION': _PICKLE_FORMAT_VERSION,
536 'JAR_MD5SUM': jar_md5,
537 'TEST_METHODS': tests,
538 }
539 with open(pickle_path, 'w') as pickle_file:
540 pickle.dump(pickle_data, pickle_file)
541
542 def _FilterTests(self, tests):
543
544 def gtest_filter(c, m):
545 t = ['%s.%s' % (c['class'].split('.')[-1], m['method'])]
546 return (not self._test_filter
547 or unittest_util.FilterTestNames(t, self._test_filter))
548
549 def annotation_filter(all_annotations):
550 if not self._annotations:
551 return True
552 return any_annotation_matches(self._annotations, all_annotations)
553
554 def excluded_annotation_filter(all_annotations):
555 if not self._excluded_annotations:
556 return True
557 return not any_annotation_matches(self._excluded_annotations,
558 all_annotations)
559
560 def any_annotation_matches(annotations, all_annotations):
561 return any(
562 ak in all_annotations and (av is None or av == all_annotations[ak])
563 for ak, av in annotations.iteritems())
564
565 filtered_classes = []
566 for c in tests:
567 filtered_methods = []
568 for m in c['methods']:
569 # Gtest filtering
570 if not gtest_filter(c, m):
571 continue
572
573 all_annotations = dict(c['annotations'])
574 all_annotations.update(m['annotations'])
575 if (not annotation_filter(all_annotations)
576 or not excluded_annotation_filter(all_annotations)):
577 continue
578
579 filtered_methods.append(m)
580
581 if filtered_methods:
582 filtered_class = dict(c)
583 filtered_class['methods'] = filtered_methods
584 filtered_classes.append(filtered_class)
585
586 return filtered_classes
587 600
588 def _InflateTests(self, tests): 601 def _InflateTests(self, tests):
589 inflated_tests = [] 602 inflated_tests = []
590 for c in tests: 603 for c in tests:
591 for m in c['methods']: 604 for m in c['methods']:
592 a = dict(c['annotations']) 605 a = dict(c['annotations'])
593 a.update(m['annotations']) 606 a.update(m['annotations'])
594 inflated_tests.append({ 607 inflated_tests.append({
595 'class': c['class'], 608 'class': c['class'],
596 'method': m['method'], 609 'method': m['method'],
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 @staticmethod 647 @staticmethod
635 def GenerateTestResults( 648 def GenerateTestResults(
636 result_code, result_bundle, statuses, start_ms, duration_ms): 649 result_code, result_bundle, statuses, start_ms, duration_ms):
637 return GenerateTestResults(result_code, result_bundle, statuses, 650 return GenerateTestResults(result_code, result_bundle, statuses,
638 start_ms, duration_ms) 651 start_ms, duration_ms)
639 652
640 #override 653 #override
641 def TearDown(self): 654 def TearDown(self):
642 if self._isolate_delegate: 655 if self._isolate_delegate:
643 self._isolate_delegate.Clear() 656 self._isolate_delegate.Clear()
644
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698