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 |