Chromium Code Reviews| 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 | 6 |
| 7 from recipe_engine import recipe_api | 7 from recipe_engine import recipe_api |
| 8 | 8 |
| 9 | 9 |
| 10 class iOSApi(recipe_api.RecipeApi): | 10 class iOSApi(recipe_api.RecipeApi): |
| 11 | 11 |
| 12 # Mapping of common names of supported iOS devices to product types | 12 # Mapping of common names of supported iOS devices to product types |
| 13 # exposed by the Swarming server. | 13 # exposed by the Swarming server. |
| 14 PRODUCT_TYPES = { | 14 PRODUCT_TYPES = { |
| 15 'iPad Air': 'iPad4,1', | 15 'iPad Air': 'iPad4,1', |
| 16 'iPhone 5s': 'iPhone6,1', | 16 'iPhone 5s': 'iPhone6,1', |
| 17 'iPhone 6s': 'iPhone8,1', | |
| 17 } | 18 } |
| 18 | 19 |
| 19 def __init__(self, *args, **kwargs): | 20 def __init__(self, *args, **kwargs): |
| 20 super(iOSApi, self).__init__(*args, **kwargs) | 21 super(iOSApi, self).__init__(*args, **kwargs) |
| 21 self.__config = None | 22 self.__config = None |
| 22 | 23 |
| 23 def host_info(self): | 24 def host_info(self): |
| 24 """Emits information about the current host and available tools.""" | 25 """Emits information about the current host and available tools.""" |
| 25 step_result = self.m.step('host and tools info', [ | 26 step_result = self.m.step('host and tools info', [ |
| 26 self.package_repo_resource( | 27 self.package_repo_resource( |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 692 failures = self.trigger(tasks) | 693 failures = self.trigger(tasks) |
| 693 infra_failures.extend(failures) | 694 infra_failures.extend(failures) |
| 694 | 695 |
| 695 for task in tasks: | 696 for task in tasks: |
| 696 if not task.task: | 697 if not task.task: |
| 697 # We failed to isolate or trigger this test. | 698 # We failed to isolate or trigger this test. |
| 698 # Create a dummy step for it and mark it as failed. | 699 # Create a dummy step for it and mark it as failed. |
| 699 step_result = self.m.step(task.step_name, []) | 700 step_result = self.m.step(task.step_name, []) |
| 700 step_result.presentation.status = self.m.step.EXCEPTION | 701 step_result.presentation.status = self.m.step.EXCEPTION |
| 701 step_result.presentation.step_text = 'Failed to trigger the test.' | 702 step_result.presentation.step_text = 'Failed to trigger the test.' |
| 703 infra_failures.append(task.step_name) | |
| 702 continue | 704 continue |
| 703 | 705 |
| 704 try: | 706 try: |
| 705 # TODO(smut): We need our own script here to interpret the results. | 707 step_result = self.m.swarming.collect_task(task.task) |
| 706 self.m.swarming.collect_task(task.task) | |
| 707 except self.m.step.StepFailure as f: | 708 except self.m.step.StepFailure as f: |
| 709 step_result = f.result | |
| 710 | |
| 711 # We only run one shard, so the results we're interested in will | |
| 712 # always be shard 0. | |
| 713 swarming_summary = step_result.json.output['shards'][0] | |
| 714 state = swarming_summary['state'] | |
| 715 exit_code = (swarming_summary.get('exit_codes') or [None])[0] | |
| 716 | |
| 717 # Interpret the result and set the display appropriately. | |
| 718 if state == self.m.swarming.State.COMPLETED and exit_code is not None: | |
| 719 # Task completed and we got an exit code from the iOS test runner. | |
| 720 if exit_code == 1: | |
| 721 step_result.presentation.status = self.m.step.FAILURE | |
| 722 test_failures.append(task.step_name) | |
| 723 elif exit_code == 2: | |
| 724 # The iOS test runner exits 2 to indicate an infrastructure failure. | |
| 725 step_result.presentation.status = self.m.step.EXCEPTION | |
| 726 infra_failures.append(task.step_name) | |
| 727 elif state == self.m.swarming.State.TIMED_OUT: | |
| 728 # The task was killed for taking too long. This is a test failure | |
| 729 # because the test itself hung. | |
| 730 step_result.presentation.status = self.m.step.FAILURE | |
| 731 step_result.presentation.step_text = 'Test timed out.' | |
| 708 test_failures.append(task.step_name) | 732 test_failures.append(task.step_name) |
| 733 elif state == self.m.swarming.State.EXPIRED: | |
| 734 # No Swarming bot accepted the task in time. | |
| 735 step_result.presentation.status = self.m.step.EXCEPTION | |
| 736 step_result.presentation.step_text = ( | |
| 737 'No suitable Swarming bot found in time.' | |
| 738 ) | |
| 739 infra_failures.append(task.step_name) | |
| 740 else: | |
| 741 step_result.presentation.status = self.m.step.EXCEPTION | |
| 742 step_result.presentation.step_text = ( | |
| 743 'Unexpected infrastructure failure.' | |
| 744 ) | |
| 745 infra_failures.append(task.step_name) | |
| 746 | |
| 747 # Add any iOS test runner results to the display. | |
| 748 test_summary = self.m.path.join( | |
| 749 task.task.task_output_dir, '0', 'summary.json') | |
| 750 if self.m.path.exists(test_summary): # pragma: no cover | |
|
Dirk Pranke
2016/08/17 01:53:58
is it too difficult to write a test for this?
smut
2016/08/17 21:51:56
Sort of, because I'm not sure how to mock the open
| |
| 751 with open(test_summary) as f: | |
| 752 test_summary_json = self.m.json.load(f) | |
| 753 step_result.presentation.logs['test_summary.json'] = self.m.json.dumps( | |
| 754 test_summary_json, indent=2).splitlines() | |
| 755 step_result.presentation.logs.update(test_summary_json.get('logs', {})) | |
| 756 step_result.presentation.links.update( | |
| 757 test_summary_json.get('links', {})) | |
| 758 if test_summary_json.get('step_text'): | |
| 759 step_result.presentation.step_text = '%s<br />%s' % ( | |
| 760 step_result.presentation.step_text, test_summary_json['step_text']) | |
|
Dirk Pranke
2016/08/17 01:53:58
The routines in this module are, generally, pretty
smut
2016/08/17 21:51:56
I tried it, but I didn't like the way it looked.
| |
| 709 | 761 |
| 710 if test_failures: | 762 if test_failures: |
| 711 raise self.m.step.StepFailure( | 763 raise self.m.step.StepFailure( |
| 712 'Failed %s.' % ', '.join(test_failures + infra_failures)) | 764 'Failed %s.' % ', '.join(sorted(set(test_failures + infra_failures)))) |
| 713 elif infra_failures: | 765 elif infra_failures: |
| 714 raise self.m.step.InfraFailure('Failed %s.' % ', '.join(infra_failures)) | 766 raise self.m.step.InfraFailure( |
| 767 'Failed %s.' % ', '.join(sorted(set(infra_failures)))) | |
| 715 | 768 |
| 716 @property | 769 @property |
| 717 def most_recent_app_dir(self): | 770 def most_recent_app_dir(self): |
| 718 """Returns the path to the directory of the most recently compiled apps.""" | 771 """Returns the path to the directory of the most recently compiled apps.""" |
| 719 build_dir = { | 772 build_dir = { |
| 720 'xcodebuild': 'xcodebuild', | 773 'xcodebuild': 'xcodebuild', |
| 721 'ninja': 'out', | 774 'ninja': 'out', |
| 722 }[self.compiler] | 775 }[self.compiler] |
| 723 | 776 |
| 724 platform = { | 777 platform = { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 765 self.configuration, | 818 self.configuration, |
| 766 'iossim', | 819 'iossim', |
| 767 ), | 820 ), |
| 768 'ninja': self.m.path.join( | 821 'ninja': self.m.path.join( |
| 769 'src', | 822 'src', |
| 770 build_dir, | 823 build_dir, |
| 771 '%s-%s' % (self.configuration, platform), | 824 '%s-%s' % (self.configuration, platform), |
| 772 'iossim', | 825 'iossim', |
| 773 ), | 826 ), |
| 774 }[self.compiler] | 827 }[self.compiler] |
| OLD | NEW |