Chromium Code Reviews| 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 logging | |
| 5 import datetime | 6 import datetime |
| 6 import functools | 7 import functools |
| 7 | 8 |
| 8 from recipe_engine import recipe_api | 9 from recipe_engine import recipe_api |
| 9 | 10 |
| 10 | 11 |
| 11 # Minimally supported version of swarming.py script (reported by --version). | 12 # Minimally supported version of swarming.py script (reported by --version). |
| 12 MINIMAL_SWARMING_VERSION = (0, 8, 6) | 13 MINIMAL_SWARMING_VERSION = (0, 8, 6) |
| 13 | 14 |
| 14 | 15 |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 400 extra_args.append( | 401 extra_args.append( |
| 401 '--test-launcher-summary-output=${ISOLATED_OUTDIR}/output.json') | 402 '--test-launcher-summary-output=${ISOLATED_OUTDIR}/output.json') |
| 402 | 403 |
| 403 # Make a task, configure it to be collected through shim script. | 404 # Make a task, configure it to be collected through shim script. |
| 404 task = self.task(title, isolated_hash, extra_args=extra_args, | 405 task = self.task(title, isolated_hash, extra_args=extra_args, |
| 405 cipd_packages=cipd_packages, **kwargs) | 406 cipd_packages=cipd_packages, **kwargs) |
| 406 task.collect_step = lambda *args, **kw: ( | 407 task.collect_step = lambda *args, **kw: ( |
| 407 self._gtest_collect_step(test_launcher_summary_output, *args, **kw)) | 408 self._gtest_collect_step(test_launcher_summary_output, *args, **kw)) |
| 408 return task | 409 return task |
| 409 | 410 |
| 411 def _check_and_set_output_flag(self, extra_args, flag, output_file_name): | |
| 412 extra_args = list(extra_args or []) | |
| 413 # Ensure flag is not already passed. We are going to overwrite it. | |
| 414 flag_value = '--%s=' % flag | |
| 415 bad_args = any(x.startswith(flag_value) for x in extra_args) | |
| 416 if bad_args: # pragma: no cover | |
|
Ken Russell (switch to Gerrit)
2016/09/19 23:41:19
It would be better to write a test for this code p
eyaich1
2016/09/20 13:56:59
So this was copy/pasted code so I didn't notice it
| |
| 417 error = '--%s should not be used' % flag | |
| 418 raise ValueError(error) | |
| 419 | |
| 420 # Append it. | |
| 421 output_arg = '--%s=${ISOLATED_OUTDIR}/%s' % (flag, output_file_name) | |
| 422 extra_args.append(output_arg) | |
| 423 return extra_args | |
| 424 | |
| 410 def isolated_script_task(self, title, isolated_hash, extra_args=None, | 425 def isolated_script_task(self, title, isolated_hash, extra_args=None, |
| 411 idempotent=False, **kwargs): | 426 idempotent=False, **kwargs): |
| 412 """Returns a new SwarmingTask to run an isolated script test on Swarming. | 427 """Returns a new SwarmingTask to run an isolated script test on Swarming. |
| 413 | 428 |
| 414 Swarming recipe module knows how collect JSON file with test execution | 429 Swarming recipe module knows how collect JSON file with test execution |
| 415 summary produced by isolated script tests launcher. Since isolated script | 430 summary produced by isolated script tests launcher. Since isolated script |
| 416 tests do not support sharding, no merging of the results is performed. | 431 tests do not support sharding, no merging of the results is performed. |
| 417 Parsed JSON summary is returned from the collect step. | 432 Parsed JSON summary is returned from the collect step. |
| 418 | 433 |
| 419 For meaning of the rest of the arguments see 'task' method. | 434 For meaning of the rest of the arguments see 'task' method. |
| 420 """ | 435 """ |
| 421 extra_args = list(extra_args or []) | |
| 422 | 436 |
| 423 # Ensure --isolated-script-test-output is not already passed. We are going | 437 # Ensure output flags are not already passed. We are going |
| 424 # to overwrite it. | 438 # to overwrite them. |
| 425 bad_args = any( | 439 # output.json name is expected by collect_gtest_task.py. |
| 426 x.startswith('--isolated-script-test-output=') for x in extra_args) | 440 extra_args = self._check_and_set_output_flag( \ |
| 427 if bad_args: # pragma: no cover | 441 extra_args, 'isolated-script-test-output', 'output.json') |
| 428 raise ValueError('--isolated-script-test-output should not be used.') | 442 # chartjson-output.json name is expected by benchmarks generating chartjson |
| 429 | 443 # output |
| 430 # Append it. output.json name is expected by collect_gtest_task.py. | 444 extra_args = self._check_and_set_output_flag( |
| 431 extra_args.append( | 445 extra_args, |
| 432 '--isolated-script-test-output=${ISOLATED_OUTDIR}/output.json') | 446 'isolated-script-test-chartjson-output', |
| 447 'chartjson-output.json') | |
| 433 | 448 |
| 434 task = self.task(title, isolated_hash, extra_args=extra_args, | 449 task = self.task(title, isolated_hash, extra_args=extra_args, |
| 435 idempotent=idempotent, **kwargs) | 450 idempotent=idempotent, **kwargs) |
| 436 task.collect_step = self._isolated_script_collect_step | 451 task.collect_step = self._isolated_script_collect_step |
| 437 return task | 452 return task |
| 438 | 453 |
| 439 def check_client_version(self, step_test_data=None): | 454 def check_client_version(self, step_test_data=None): |
| 440 """Yields steps to verify compatibility with swarming_client version.""" | 455 """Yields steps to verify compatibility with swarming_client version.""" |
| 441 return self.m.swarming_client.ensure_script_version( | 456 return self.m.swarming_client.ensure_script_version( |
| 442 'swarming.py', MINIMAL_SWARMING_VERSION, step_test_data) | 457 'swarming.py', MINIMAL_SWARMING_VERSION, step_test_data) |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 710 # Show any remaining isolated outputs (such as logcats). | 725 # Show any remaining isolated outputs (such as logcats). |
| 711 # Note that collect_gtest_task.py uses the default summary.json, which | 726 # Note that collect_gtest_task.py uses the default summary.json, which |
| 712 # only has 'outputs_ref' instead of the deprecated 'isolated_out'. | 727 # only has 'outputs_ref' instead of the deprecated 'isolated_out'. |
| 713 for index, shard in enumerate(swarming_summary.get('shards', [])): | 728 for index, shard in enumerate(swarming_summary.get('shards', [])): |
| 714 outputs_ref = shard.get('outputs_ref') | 729 outputs_ref = shard.get('outputs_ref') |
| 715 if outputs_ref: | 730 if outputs_ref: |
| 716 link_name = 'shard #%d isolated out' % index | 731 link_name = 'shard #%d isolated out' % index |
| 717 p.links[link_name] = outputs_ref['view_url'] | 732 p.links[link_name] = outputs_ref['view_url'] |
| 718 | 733 |
| 719 | 734 |
| 735 def _merge_isolated_script_chartjson_ouput_shards(self, task, step_result): | |
| 736 # Taken from third_party/catapult/telemetry/telemetry/internal/results/ | |
| 737 # chart_json_output_formatter.py, the json entries are as follows: | |
| 738 # result_dict = { | |
| 739 # 'format_version': '0.1', | |
| 740 # 'next_version': '0.2', | |
| 741 # 'benchmark_name': benchmark_metadata.name, | |
| 742 # 'benchmark_description': benchmark_metadata.description, | |
| 743 # 'trace_rerun_options': benchmark_metadata.rerun_options, | |
| 744 # 'benchmark_metadata': benchmark_metadata.AsDict(), | |
| 745 # 'charts': charts, | |
| 746 # } | |
| 747 # | |
| 748 # Therefore, all entries should be the same and we should only need to merge | |
| 749 # the chart from each shard. | |
| 750 merged_results = {} | |
| 751 seen_first_shard = False | |
| 752 for i in xrange(task.shards): | |
| 753 path = self.m.path.join(str(i), 'chartjson-output.json') | |
| 754 if path not in step_result.raw_io.output_dir: | |
| 755 # chartjson results were not written for this shard, not an error, | |
| 756 # just return | |
| 757 continue | |
| 758 results_raw = step_result.raw_io.output_dir[path] | |
| 759 try: | |
| 760 chartjson_results_json = self.m.json.loads(results_raw) | |
| 761 except Exception as e: | |
| 762 raise Exception('error decoding JSON results from shard #%d' % i) | |
| 763 if not seen_first_shard: | |
| 764 merged_results = chartjson_results_json | |
| 765 seen_first_shard = True | |
| 766 continue | |
| 767 for key in chartjson_results_json: | |
| 768 if key == 'charts': | |
| 769 merged_results[key].extend(chartjson_results_json[key]) | |
| 770 return merged_results | |
| 771 | |
| 772 | |
| 720 def _merge_isolated_script_shards(self, task, step_result): | 773 def _merge_isolated_script_shards(self, task, step_result): |
| 721 # This code is unfortunately specialized to the "simplified" | 774 # This code is unfortunately specialized to the "simplified" |
| 722 # JSON format that used to be the standard for recipes. The | 775 # JSON format that used to be the standard for recipes. The |
| 723 # isolated scripts should be changed to use the now-standard | 776 # isolated scripts should be changed to use the now-standard |
| 724 # Chromium JSON test results format: | 777 # Chromium JSON test results format: |
| 725 # https://www.chromium.org/developers/the-json-test-results-format | 778 # https://www.chromium.org/developers/the-json-test-results-format |
| 726 # . Note that gtests, above, don't seem to conform to this | 779 # . Note that gtests, above, don't seem to conform to this |
| 727 # format yet, so it didn't seem like a good prerequisite to | 780 # format yet, so it didn't seem like a good prerequisite to |
| 728 # switch the isolated tests over when adding sharding support. | 781 # switch the isolated tests over when adding sharding support. |
| 729 # | 782 # |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 792 # in recipe runs.) | 845 # in recipe runs.) |
| 793 links = step_result.presentation.links | 846 links = step_result.presentation.links |
| 794 for index in xrange(task.shards): | 847 for index in xrange(task.shards): |
| 795 url = task.get_shard_view_url(index) | 848 url = task.get_shard_view_url(index) |
| 796 if url: | 849 if url: |
| 797 links['shard #%d' % index] = url | 850 links['shard #%d' % index] = url |
| 798 | 851 |
| 799 step_result.isolated_script_results = \ | 852 step_result.isolated_script_results = \ |
| 800 self._merge_isolated_script_shards(task, step_result) | 853 self._merge_isolated_script_shards(task, step_result) |
| 801 | 854 |
| 855 # Obtain chartjson results if present | |
| 856 step_result.isolated_script_chartjson_results = \ | |
| 857 self._merge_isolated_script_chartjson_ouput_shards(task, step_result) | |
| 858 | |
| 802 self._display_pending(summary, step_result.presentation) | 859 self._display_pending(summary, step_result.presentation) |
| 803 except Exception as e: | 860 except Exception as e: |
| 804 self.m.step.active_result.presentation.logs['no_results_exc'] = [str(e)] | 861 self.m.step.active_result.presentation.logs['no_results_exc'] = [str(e)] |
| 805 self.m.step.active_result.isolated_script_results = None | 862 self.m.step.active_result.isolated_script_results = None |
| 806 | 863 |
| 807 def _get_step_name(self, prefix, task): | 864 def _get_step_name(self, prefix, task): |
| 808 """SwarmingTask -> name of a step of a waterfall. | 865 """SwarmingTask -> name of a step of a waterfall. |
| 809 | 866 |
| 810 Will take a task title (+ step name prefix) and append OS dimension to it. | 867 Will take a task title (+ step name prefix) and append OS dimension to it. |
| 811 | 868 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 989 | 1046 |
| 990 def get_shard_view_url(self, index): | 1047 def get_shard_view_url(self, index): |
| 991 """Returns URL of HTML page with shard details or None if not available. | 1048 """Returns URL of HTML page with shard details or None if not available. |
| 992 | 1049 |
| 993 Works only after the task has been successfully triggered. | 1050 Works only after the task has been successfully triggered. |
| 994 """ | 1051 """ |
| 995 if self._trigger_output and self._trigger_output.get('tasks'): | 1052 if self._trigger_output and self._trigger_output.get('tasks'): |
| 996 for shard_dict in self._trigger_output['tasks'].itervalues(): | 1053 for shard_dict in self._trigger_output['tasks'].itervalues(): |
| 997 if shard_dict['shard_index'] == index: | 1054 if shard_dict['shard_index'] == index: |
| 998 return shard_dict['view_url'] | 1055 return shard_dict['view_url'] |
| OLD | NEW |