| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 datetime | 5 import datetime |
| 6 import functools | 6 import functools |
| 7 | 7 |
| 8 from recipe_engine.types import freeze | 8 from recipe_engine.types import freeze |
| 9 from recipe_engine import recipe_api | 9 from recipe_engine import recipe_api |
| 10 | 10 |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 # idempotent. As of this writing, Telemetry itself downloads some | 339 # idempotent. As of this writing, Telemetry itself downloads some |
| 340 # data from remote servers; additionally, some tests like the | 340 # data from remote servers; additionally, some tests like the |
| 341 # pixel_tests download reference images from cloud storage. It's | 341 # pixel_tests download reference images from cloud storage. It's |
| 342 # safest to assume that these tests aren't idempotent, though we | 342 # safest to assume that these tests aren't idempotent, though we |
| 343 # should work toward making them so. | 343 # should work toward making them so. |
| 344 task = self.task(title, isolated_hash, extra_args=extra_args, | 344 task = self.task(title, isolated_hash, extra_args=extra_args, |
| 345 idempotent=False, **kwargs) | 345 idempotent=False, **kwargs) |
| 346 task.collect_step = self._telemetry_gpu_collect_step | 346 task.collect_step = self._telemetry_gpu_collect_step |
| 347 return task | 347 return task |
| 348 | 348 |
| 349 def isolated_script_task(self, title, isolated_hash, extra_args=None, |
| 350 idempotent=False, **kwargs): |
| 351 """Returns a new SwarmingTask to run an isolated script test on Swarming. |
| 352 |
| 353 Swarming recipe module knows how collect JSON file with test execution |
| 354 summary produced by isolated script tests launcher. Since isolated script |
| 355 tests do not support sharding, no merging of the results is performed. |
| 356 Parsed JSON summary is returned from the collect step. |
| 357 |
| 358 For meaning of the rest of the arguments see 'task' method. |
| 359 """ |
| 360 extra_args = list(extra_args or []) |
| 361 |
| 362 # Ensure --isolated-script-test-output is not already passed. We are going |
| 363 # to overwrite it. |
| 364 bad_args = any( |
| 365 x.startswith('--isolated-script-test-output=') for x in extra_args) |
| 366 if bad_args: # pragma: no cover |
| 367 raise ValueError('--isolated-script-test-output should not be used.') |
| 368 |
| 369 # Append it. output.json name is expected by collect_gtest_task.py. |
| 370 extra_args.append( |
| 371 '--isolated-script-test-output=${ISOLATED_OUTDIR}/output.json') |
| 372 |
| 373 task = self.task(title, isolated_hash, extra_args=extra_args, |
| 374 idempotent=idempotent, **kwargs) |
| 375 task.collect_step = self._isolated_script_collect_step |
| 376 return task |
| 377 |
| 349 def check_client_version(self, step_test_data=None): | 378 def check_client_version(self, step_test_data=None): |
| 350 """Yields steps to verify compatibility with swarming_client version.""" | 379 """Yields steps to verify compatibility with swarming_client version.""" |
| 351 return self.m.swarming_client.ensure_script_version( | 380 return self.m.swarming_client.ensure_script_version( |
| 352 'swarming.py', MINIMAL_SWARMING_VERSION, step_test_data) | 381 'swarming.py', MINIMAL_SWARMING_VERSION, step_test_data) |
| 353 | 382 |
| 354 def trigger_task(self, task, **kwargs): | 383 def trigger_task(self, task, **kwargs): |
| 355 """Triggers one task. | 384 """Triggers one task. |
| 356 | 385 |
| 357 It the task is sharded, will trigger all shards. This steps justs posts | 386 It the task is sharded, will trigger all shards. This steps justs posts |
| 358 the task and immediately returns. Use 'collect_task' to wait for a task to | 387 the task and immediately returns. Use 'collect_task' to wait for a task to |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 647 if step_result.retcode == 0 and results_raw == '': | 676 if step_result.retcode == 0 and results_raw == '': |
| 648 step_result.telemetry_results = {'per_page_values': [], 'pages': []} | 677 step_result.telemetry_results = {'per_page_values': [], 'pages': []} |
| 649 else: | 678 else: |
| 650 step_result.telemetry_results = self.m.json.loads(results_raw) | 679 step_result.telemetry_results = self.m.json.loads(results_raw) |
| 651 | 680 |
| 652 self._display_pending(summary, step_result.presentation) | 681 self._display_pending(summary, step_result.presentation) |
| 653 except Exception as e: | 682 except Exception as e: |
| 654 self.m.step.active_result.presentation.logs['no_results_exc'] = [str(e)] | 683 self.m.step.active_result.presentation.logs['no_results_exc'] = [str(e)] |
| 655 self.m.step.active_result.telemetry_results = None | 684 self.m.step.active_result.telemetry_results = None |
| 656 | 685 |
| 686 def _isolated_script_collect_step(self, task, **kwargs): |
| 687 step_test_data = kwargs.pop('step_test_data', None) |
| 688 if not step_test_data: |
| 689 step_test_data = self.m.test_utils.test_api.canned_isolated_script_output( |
| 690 passing=True, is_win=self.m.platform.is_win, swarming=True) |
| 691 |
| 692 args=self.get_collect_cmd_args(task) |
| 693 args.extend(['--task-output-dir', self.m.raw_io.output_dir()]) |
| 694 |
| 695 try: |
| 696 self.m.python( |
| 697 name=self._get_step_name('', task), |
| 698 script=self.m.swarming_client.path.join('swarming.py'), |
| 699 args=args, step_test_data=lambda: step_test_data, |
| 700 **kwargs) |
| 701 finally: |
| 702 # Regardless of the outcome of the test (pass or fail), we try to parse |
| 703 # the results. If any error occurs while parsing results, then we set them |
| 704 # to None, which caller should treat as invalid results. |
| 705 # Note that try-except block below will not mask the |
| 706 # recipe_api.StepFailure exception from the collect step above. Instead |
| 707 # it is being allowed to propagate after the results have been parsed. |
| 708 try: |
| 709 step_result = self.m.step.active_result |
| 710 outdir_json = self.m.json.dumps(step_result.raw_io.output_dir, indent=2) |
| 711 step_result.presentation.logs['outdir_json'] = outdir_json.splitlines() |
| 712 |
| 713 # Check if it's an internal failure. |
| 714 summary = self.m.json.loads( |
| 715 step_result.raw_io.output_dir['summary.json']) |
| 716 if any(shard['internal_failure'] for shard in summary['shards']): |
| 717 raise recipe_api.InfraFailure('Internal swarming failure.') |
| 718 |
| 719 # TODO(nednguyen, kbr): Combine isolated script results from multiple |
| 720 # shards rather than assuming that there is always just one shard. |
| 721 assert len(summary['shards']) == 1 |
| 722 results_raw = step_result.raw_io.output_dir[ |
| 723 self.m.path.join('0', 'output.json')] |
| 724 step_result.isolated_script_results = self.m.json.loads(results_raw) |
| 725 |
| 726 self._display_pending(summary, step_result.presentation) |
| 727 except Exception as e: |
| 728 self.m.step.active_result.presentation.logs['no_results_exc'] = [str(e)] |
| 729 self.m.step.active_result.isolated_script_results = None |
| 657 | 730 |
| 658 def _get_step_name(self, prefix, task): | 731 def _get_step_name(self, prefix, task): |
| 659 """SwarmingTask -> name of a step of a waterfall. | 732 """SwarmingTask -> name of a step of a waterfall. |
| 660 | 733 |
| 661 Will take a task title (+ step name prefix) and optionally append | 734 Will take a task title (+ step name prefix) and optionally append |
| 662 OS dimension to it in case the task is triggered on OS that is different | 735 OS dimension to it in case the task is triggered on OS that is different |
| 663 from OS this recipe is running on. It shortens step names for the most | 736 from OS this recipe is running on. It shortens step names for the most |
| 664 common case of triggering a task on the same OS as one that recipe | 737 common case of triggering a task on the same OS as one that recipe |
| 665 is running on. | 738 is running on. |
| 666 | 739 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 836 | 909 |
| 837 def get_shard_view_url(self, index): | 910 def get_shard_view_url(self, index): |
| 838 """Returns URL of HTML page with shard details or None if not available. | 911 """Returns URL of HTML page with shard details or None if not available. |
| 839 | 912 |
| 840 Works only after the task has been successfully triggered. | 913 Works only after the task has been successfully triggered. |
| 841 """ | 914 """ |
| 842 if self._trigger_output and self._trigger_output.get('tasks'): | 915 if self._trigger_output and self._trigger_output.get('tasks'): |
| 843 for shard_dict in self._trigger_output['tasks'].itervalues(): | 916 for shard_dict in self._trigger_output['tasks'].itervalues(): |
| 844 if shard_dict['shard_index'] == index: | 917 if shard_dict['shard_index'] == index: |
| 845 return shard_dict['view_url'] | 918 return shard_dict['view_url'] |
| OLD | NEW |