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 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 Loading... | |
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 20:33:30
Thanks for putting up with my waffling on this.
L
Yoland Yan(Google)
2016/04/06 22:04:19
dude, ofc
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 TotalTestAmount(test_jar): | |
255 """Doc stub""" | |
256 total_test_amount = 0 | |
257 tests = _GetAllTests(test_jar) | |
258 for c in tests: | |
259 total_test_amount += len(c['methods']) | |
260 return total_test_amount | |
261 | |
262 def GetFilteredTests(test_jar, test_filter, annotations, exclude_annotations): | |
263 """Doc stub""" | |
264 tests = _GetAllTests(test_jar) | |
265 filtered_tests = FilterTests(tests, test_filter, annotations, | |
266 exclude_annotations) | |
267 return filtered_tests | |
268 | |
269 def FilterTests(tests, test_filter, annotations, excluded_annotations): | |
270 """Doc stub""" | |
271 | |
272 def gtest_filter(c, m): | |
273 t = ['%s.%s' % (c['class'].split('.')[-1], m['method'])] | |
274 return (not test_filter | |
275 or unittest_util.FilterTestNames(t, test_filter)) | |
276 | |
277 def annotation_filter(all_annotations): | |
278 if not annotations: | |
279 return True | |
280 return any_annotation_matches(annotations, all_annotations) | |
281 | |
282 def excluded_annotation_filter(all_annotations): | |
283 if not excluded_annotations: | |
284 return True | |
285 return not any_annotation_matches(excluded_annotations, | |
286 all_annotations) | |
287 | |
288 def any_annotation_matches(annotations, all_annotations): | |
289 return any( | |
290 ak in all_annotations and (av is None or av == all_annotations[ak]) | |
291 for ak, av in annotations.iteritems()) | |
292 | |
293 filtered_classes = [] | |
294 for c in tests: | |
295 filtered_methods = [] | |
296 for m in c['methods']: | |
297 # Gtest filtering | |
298 if not gtest_filter(c, m): | |
299 continue | |
300 | |
301 all_annotations = dict(c['annotations']) | |
302 all_annotations.update(m['annotations']) | |
303 if (not annotation_filter(all_annotations) | |
304 or not excluded_annotation_filter(all_annotations)): | |
305 continue | |
306 | |
307 filtered_methods.append(m) | |
308 | |
309 if filtered_methods: | |
310 filtered_class = dict(c) | |
311 filtered_class['methods'] = filtered_methods | |
312 filtered_classes.append(filtered_class) | |
313 | |
314 return filtered_classes | |
315 | |
316 def _GetAllTests(test_jar): | |
317 """Doc stub""" | |
318 pickle_path = '%s-proguard.pickle' % test_jar | |
319 try: | |
320 tests = GetTestsFromPickle(pickle_path, test_jar) | |
321 except ProguardPickleException as e: | |
322 logging.info('Getting tests from JAR via proguard. (%s)', str(e)) | |
323 tests = GetTestsFromProguard(test_jar) | |
324 SaveTestsToPickle(pickle_path, test_jar, tests) | |
325 return tests | |
326 | |
327 class ProguardPickleException(Exception): | |
328 pass | |
190 | 329 |
191 class InstrumentationTestInstance(test_instance.TestInstance): | 330 class InstrumentationTestInstance(test_instance.TestInstance): |
192 | 331 |
193 def __init__(self, args, isolate_delegate, error_func): | 332 def __init__(self, args, isolate_delegate, error_func): |
194 super(InstrumentationTestInstance, self).__init__() | 333 super(InstrumentationTestInstance, self).__init__() |
195 | 334 |
196 self._additional_apks = [] | 335 self._additional_apks = [] |
197 self._apk_under_test = None | 336 self._apk_under_test = None |
198 self._apk_under_test_incremental_install_script = None | 337 self._apk_under_test_incremental_install_script = None |
199 self._package_info = None | 338 self._package_info = None |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
458 device_rel_path, host_rel_path = t.split(':') | 597 device_rel_path, host_rel_path = t.split(':') |
459 host_abs_path = os.path.join(host_paths.DIR_SOURCE_ROOT, host_rel_path) | 598 host_abs_path = os.path.join(host_paths.DIR_SOURCE_ROOT, host_rel_path) |
460 self._data_deps.extend( | 599 self._data_deps.extend( |
461 [(host_abs_path, | 600 [(host_abs_path, |
462 [None, 'chrome', 'test', 'data', device_rel_path])]) | 601 [None, 'chrome', 'test', 'data', device_rel_path])]) |
463 | 602 |
464 def GetDataDependencies(self): | 603 def GetDataDependencies(self): |
465 return self._data_deps | 604 return self._data_deps |
466 | 605 |
467 def GetTests(self): | 606 def GetTests(self): |
468 pickle_path = '%s-proguard.pickle' % self.test_jar | 607 filtered_tests = GetFilteredTests( |
469 try: | 608 self.test_jar, |
470 tests = self._GetTestsFromPickle(pickle_path, self.test_jar) | 609 self._test_filter, |
471 except self.ProguardPickleException as e: | 610 self._annotations, |
472 logging.info('Getting tests from JAR via proguard. (%s)', str(e)) | 611 self._excluded_annotations) |
473 tests = self._GetTestsFromProguard(self.test_jar) | 612 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 | 613 |
588 def _InflateTests(self, tests): | 614 def _InflateTests(self, tests): |
589 inflated_tests = [] | 615 inflated_tests = [] |
590 for c in tests: | 616 for c in tests: |
591 for m in c['methods']: | 617 for m in c['methods']: |
592 a = dict(c['annotations']) | 618 a = dict(c['annotations']) |
593 a.update(m['annotations']) | 619 a.update(m['annotations']) |
594 inflated_tests.append({ | 620 inflated_tests.append({ |
595 'class': c['class'], | 621 'class': c['class'], |
596 'method': m['method'], | 622 'method': m['method'], |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
634 @staticmethod | 660 @staticmethod |
635 def GenerateTestResults( | 661 def GenerateTestResults( |
636 result_code, result_bundle, statuses, start_ms, duration_ms): | 662 result_code, result_bundle, statuses, start_ms, duration_ms): |
637 return GenerateTestResults(result_code, result_bundle, statuses, | 663 return GenerateTestResults(result_code, result_bundle, statuses, |
638 start_ms, duration_ms) | 664 start_ms, duration_ms) |
639 | 665 |
640 #override | 666 #override |
641 def TearDown(self): | 667 def TearDown(self): |
642 if self._isolate_delegate: | 668 if self._isolate_delegate: |
643 self._isolate_delegate.Clear() | 669 self._isolate_delegate.Clear() |
644 | |
OLD | NEW |