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 logging |
| 6 import datetime | 6 import datetime |
| 7 import functools | 7 import functools |
| 8 | 8 |
| 9 from recipe_engine import recipe_api | 9 from recipe_engine import recipe_api |
| 10 | 10 |
| (...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 763 merged_results = chartjson_results_json | 763 merged_results = chartjson_results_json |
| 764 seen_first_shard = True | 764 seen_first_shard = True |
| 765 continue | 765 continue |
| 766 for key in chartjson_results_json: | 766 for key in chartjson_results_json: |
| 767 if key == 'charts': | 767 if key == 'charts': |
| 768 # Append each additional chart to our merged results | 768 # Append each additional chart to our merged results |
| 769 for add_key in chartjson_results_json[key]: | 769 for add_key in chartjson_results_json[key]: |
| 770 merged_results[key][add_key] = chartjson_results_json[key][add_key] | 770 merged_results[key][add_key] = chartjson_results_json[key][add_key] |
| 771 return merged_results | 771 return merged_results |
| 772 | 772 |
| 773 def _merge_simplified_test_result_format(self, shard_results_list): | |
| 774 merged_results = { | |
| 775 'successes': [], | |
| 776 'failures': [], | |
| 777 'valid': True, | |
| 778 } | |
| 779 for results_json in shard_results_list: | |
| 780 for key in merged_results: | |
| 781 if key in results_json: | |
| 782 if isinstance(merged_results[key], list): | |
| 783 merged_results[key].extend(results_json[key]) | |
| 784 elif isinstance(merged_results[key], bool): | |
| 785 merged_results[key] = merged_results[key] and results_json[key] | |
| 786 else: | |
| 787 raise recipe_api.InfraFailure( | |
| 788 'Unknown key type ' + type(merged_results[key]) + | |
| 789 ' when handling key ' + key + '.') # pragma: no cover | |
| 790 return merged_results | |
| 791 | |
| 792 def _merge_json_test_result_format(self, shard_results_list): | |
| 793 merged_results = { | |
| 794 'tests': {}, | |
| 795 'interrupted': false, | |
| 796 'path_delimiter': '', | |
| 797 'version': 3, | |
| 798 'seconds_since_epoch': float('inf'), | |
| 799 'num_failures_by_type': { | |
| 800 } | |
| 801 } | |
| 802 for result_json in shard_results_list: | |
| 803 if not ('tests' in result_json and | |
| 804 'interrupted' in result_json and | |
| 805 'path_delimiter' in result_json and | |
| 806 'version' in result_json and | |
| 807 'seconds_since_epoch' in result_json and | |
| 808 'num_failures_by_type' in result_json): | |
| 809 raise recipe_api.InfraFailure('Invalid json test results') | |
|
Sergiy Byelozyorov
2016/09/29 21:36:22
I would double-check if everybody implements the f
nednguyen
2016/10/04 00:10:11
Hmhh, the spec say these fields are required?
htt
Sergiy Byelozyorov
2016/10/04 08:54:52
Sure. I just meant that you should make sure it do
Dirk Pranke
2016/10/04 20:04:02
We should try to follow the spec and update the sp
| |
| 810 | |
| 811 # Traverse the results_json's test trie & merged_results's test tries in | |
| 812 # DFS order & add the n to merged['tests']. | |
| 813 curr_result_nodes_queue = [results_json['tests']] | |
| 814 merged_results_nodes_queue = [merged_results['tests']] | |
| 815 while nodes_queue: | |
|
Sergiy Byelozyorov
2016/09/29 21:36:22
I don't see nodes_queue defined anywhere... does t
nednguyen
2016/10/04 00:10:11
Yeah, I wasn't sure how to test these. Done.
| |
| 816 curr_node = curr_result_nodes_queue.pop() | |
| 817 merged_node = merged_results_nodes_queue.pop() | |
| 818 for k, v in curr_node.iteritems(): | |
| 819 if k in merged_node: | |
| 820 curr_result_nodes_queue.push(v) | |
| 821 merged_results_nodes_queue.push(merged_node[k]) | |
| 822 else: | |
| 823 merged_node[k] = v | |
| 824 | |
| 825 # Update the rest of the fields for merged_results. | |
| 826 merged_results['interrupted'] |= results_json['interrupted'] | |
| 827 if not merged_results['path_delimiter']: | |
| 828 merged_results['path_delimiter'] = results_json['path_delimiter'] | |
| 829 elif merged_results['path_delimiter'] != results_json['path_delimiter']: | |
| 830 raise Exception( | |
| 831 'Incosistent path delimiter: %s %s' % | |
| 832 (merged_results['path_delimiter'], | |
| 833 results_json['path_delimiter'])) | |
| 834 if results_json['version'] != 3: | |
| 835 raise recipe_api.InfraFailure( | |
| 836 'Only version 3 of json test result format is supported') | |
| 837 merged_results['seconds_since_epoch'] = min( | |
| 838 merged_results['seconds_since_epoch'], | |
| 839 results_json['seconds_since_epoch']) | |
|
Sergiy Byelozyorov
2016/09/29 21:36:22
Any particular reason to pick the smaller of the t
nednguyen
2016/10/04 00:10:11
I honestly not sure what is the reason for this fi
Sergiy Byelozyorov
2016/10/04 08:54:52
AFAIK, this is when the tests were run... probably
nednguyen
2016/10/04 13:30:29
Ah, I just think that the earliest seconds_since_e
| |
| 840 for result_type, count in results_json['num_failures_by_type']: | |
| 841 if not result_type in merged_results['num_failures_by_type']: | |
|
Sergiy Byelozyorov
2016/09/29 21:36:22
IMHO this is more Pythonic:
merged_results['num_f
nednguyen
2016/10/04 00:10:11
Done.
| |
| 842 merged_results['num_failures_by_type'][result_type] = 0 | |
| 843 merged_results['num_failures_by_type'][result_type] += count | |
| 773 | 844 |
| 774 def _merge_isolated_script_shards(self, task, step_result): | 845 def _merge_isolated_script_shards(self, task, step_result): |
| 775 # This code is unfortunately specialized to the "simplified" | 846 # This code is unfortunately specialized to the "simplified" |
| 776 # JSON format that used to be the standard for recipes. The | 847 # JSON format that used to be the standard for recipes. The |
| 777 # isolated scripts should be changed to use the now-standard | 848 # isolated scripts should be changed to use the now-standard |
| 778 # Chromium JSON test results format: | 849 # Chromium JSON test results format: |
| 779 # https://www.chromium.org/developers/the-json-test-results-format | 850 # https://www.chromium.org/developers/the-json-test-results-format |
| 780 # . Note that gtests, above, don't seem to conform to this | 851 # . Note that gtests, above, don't seem to conform to this |
| 781 # format yet, so it didn't seem like a good prerequisite to | 852 # format yet, so it didn't seem like a good prerequisite to |
| 782 # switch the isolated tests over when adding sharding support. | 853 # switch the isolated tests over when adding sharding support. |
| 783 # | 854 # |
| 784 # These are the only keys we pay attention to in the output JSON. | 855 # These are the only keys we pay attention to in the output JSON. |
|
Ken Russell (switch to Gerrit)
2016/09/30 23:37:53
Please move this comment to the top of _merge_simp
nednguyen
2016/10/04 00:10:11
Done.
| |
| 785 merged_results = { | 856 shard_results_list = [] |
| 786 'successes': [], | |
| 787 'failures': [], | |
| 788 'valid': True, | |
| 789 } | |
| 790 for i in xrange(task.shards): | 857 for i in xrange(task.shards): |
| 791 path = self.m.path.join(str(i), 'output.json') | 858 path = self.m.path.join(str(i), 'output.json') |
| 792 if path not in step_result.raw_io.output_dir: | 859 if path not in step_result.raw_io.output_dir: |
| 793 raise Exception('no results from shard #%d' % i) | 860 raise Exception('no results from shard #%d' % i) |
| 794 results_raw = step_result.raw_io.output_dir[path] | 861 results_raw = step_result.raw_io.output_dir[path] |
| 795 try: | 862 try: |
| 796 results_json = self.m.json.loads(results_raw) | 863 results_json = self.m.json.loads(results_raw) |
| 864 shard_results_list.append(results_json) | |
| 797 except Exception as e: | 865 except Exception as e: |
| 798 raise Exception('error decoding JSON results from shard #%d' % i) | 866 raise Exception('error decoding JSON results from shard #%d' % i) |
| 799 for key in merged_results: | 867 if not shard_results_list: |
|
eyaich1
2016/09/29 14:55:23
no need for this check you create it above
Sergiy Byelozyorov
2016/09/29 21:36:22
But it can be empty, can't it?
| |
| 800 if key in results_json: | 868 raise Exception('No shard results is created') |
|
Ken Russell (switch to Gerrit)
2016/09/30 23:37:53
Grammar: remove "is".
nednguyen
2016/10/04 00:10:11
Done.
| |
| 801 if isinstance(merged_results[key], list): | 869 elif 'seconds_since_epoch' in shard_results_list[0]: |
|
eyaich1
2016/09/29 14:55:23
is this the distinguishing factor between the resu
nednguyen
2016/10/04 00:10:11
This is the distinguished factor between the simpl
| |
| 802 merged_results[key].extend(results_json[key]) | 870 return self._merge_json_test_result_format[shard_results_list] |
| 803 elif isinstance(merged_results[key], bool): | 871 else: |
| 804 merged_results[key] = merged_results[key] and results_json[key] | 872 return self._merge_simplified_json_format(shard_results_list) |
| 805 else: | |
| 806 raise recipe_api.InfraFailure( | |
| 807 'Unknown key type ' + type(merged_results[key]) + | |
| 808 ' when handling key ' + key + '.') # pragma: no cover | |
| 809 return merged_results | |
| 810 | 873 |
| 811 def _isolated_script_collect_step(self, task, **kwargs): | 874 def _isolated_script_collect_step(self, task, **kwargs): |
| 812 step_test_data = kwargs.pop('step_test_data', None) | 875 step_test_data = kwargs.pop('step_test_data', None) |
| 813 if not step_test_data: | 876 if not step_test_data: |
| 814 step_test_data = self.m.test_utils.test_api.canned_isolated_script_output( | 877 step_test_data = self.m.test_utils.test_api.canned_isolated_script_output( |
| 815 passing=True, is_win=self.m.platform.is_win, swarming=True) | 878 passing=True, is_win=self.m.platform.is_win, swarming=True) |
| 816 | 879 |
| 817 args=self.get_collect_cmd_args(task) | 880 args=self.get_collect_cmd_args(task) |
| 818 args.extend(['--task-output-dir', self.m.raw_io.output_dir()]) | 881 args.extend(['--task-output-dir', self.m.raw_io.output_dir()]) |
| 819 | 882 |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1052 | 1115 |
| 1053 def get_shard_view_url(self, index): | 1116 def get_shard_view_url(self, index): |
| 1054 """Returns URL of HTML page with shard details or None if not available. | 1117 """Returns URL of HTML page with shard details or None if not available. |
| 1055 | 1118 |
| 1056 Works only after the task has been successfully triggered. | 1119 Works only after the task has been successfully triggered. |
| 1057 """ | 1120 """ |
| 1058 if self._trigger_output and self._trigger_output.get('tasks'): | 1121 if self._trigger_output and self._trigger_output.get('tasks'): |
| 1059 for shard_dict in self._trigger_output['tasks'].itervalues(): | 1122 for shard_dict in self._trigger_output['tasks'].itervalues(): |
| 1060 if shard_dict['shard_index'] == index: | 1123 if shard_dict['shard_index'] == index: |
| 1061 return shard_dict['view_url'] | 1124 return shard_dict['view_url'] |
| OLD | NEW |