| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 |
| 6 |
| 5 from collections import defaultdict | 7 from collections import defaultdict |
| 6 | 8 |
| 7 from common.pipeline_wrapper import BasePipeline | 9 from model.flake.flake_swarming_task import FlakeSwarmingTask |
| 8 | 10 from model.flake.master_flake_analysis import DataPoint |
| 9 from model.flake.master_flake_analysis import MasterFlakeAnalysis | 11 from model.flake.master_flake_analysis import MasterFlakeAnalysis |
| 10 from model.flake.flake_swarming_task import FlakeSwarmingTask | |
| 11 from waterfall.process_base_swarming_task_result_pipeline import ( | 12 from waterfall.process_base_swarming_task_result_pipeline import ( |
| 12 ProcessBaseSwarmingTaskResultPipeline) | 13 ProcessBaseSwarmingTaskResultPipeline) |
| 13 | 14 |
| 14 | 15 |
| 15 class ProcessFlakeSwarmingTaskResultPipeline( | 16 class ProcessFlakeSwarmingTaskResultPipeline( |
| 16 ProcessBaseSwarmingTaskResultPipeline): | 17 ProcessBaseSwarmingTaskResultPipeline): |
| 17 """A pipeline for monitoring swarming task and processing task result. | 18 """A pipeline for monitoring swarming task and processing task result. |
| 18 | 19 |
| 19 This pipeline waits for result for a swarming task and processes the result to | 20 This pipeline waits for result for a swarming task and processes the result to |
| 20 generate a dict for statuses for each test run. | 21 generate a dict for statuses for each test run. |
| 21 """ | 22 """ |
| 22 | 23 |
| 23 # Arguments number differs from overridden method - pylint: disable=W0221 | 24 # Arguments number differs from overridden method - pylint: disable=W0221 |
| 24 def _CheckTestsRunStatuses(self, output_json, master_name, | 25 def _CheckTestsRunStatuses(self, output_json, master_name, |
| 25 builder_name, build_number, step_name, | 26 builder_name, build_number, step_name, |
| 26 master_build_number, test_name): | 27 master_build_number, test_name, version_number): |
| 27 """Checks result status for each test run and saves the numbers accordingly. | 28 """Checks result status for each test run and saves the numbers accordingly. |
| 28 | 29 |
| 29 Args: | 30 Args: |
| 30 output_json (dict): A dict of all test results in the swarming task. | 31 output_json (dict): A dict of all test results in the swarming task. |
| 31 master_name (string): Name of master of swarming rerun. | 32 master_name (string): Name of master of swarming rerun. |
| 32 builder_name (dict): Name of builder of swarming rerun. | 33 builder_name (dict): Name of builder of swarming rerun. |
| 33 build_number (int): Build Number of swarming rerun. | 34 build_number (int): Build Number of swarming rerun. |
| 34 step_name (dict): Name of step of swarming rerun. | 35 step_name (dict): Name of step of swarming rerun. |
| 35 master_build_number (int): Build number of corresponding mfa | 36 master_build_number (int): Build number of corresponding mfa. |
| 36 test_name (string): Name of test of swarming rerun | 37 test_name (string): Name of test of swarming rerun. |
| 38 version_number (int): The version to save analysis results and ` to. |
| 37 | 39 |
| 38 Returns: | 40 Returns: |
| 39 tests_statuses (dict): A dict of different statuses for each test. | 41 tests_statuses (dict): A dict of different statuses for each test. |
| 40 | 42 |
| 41 Currently for each test, we are saving number of total runs, | 43 Currently for each test, we are saving number of total runs, |
| 42 number of succeeded runs and number of failed runs. | 44 number of succeeded runs and number of failed runs. |
| 43 """ | 45 """ |
| 44 | 46 |
| 45 tests_statuses = defaultdict(lambda: defaultdict(int)) | 47 tests_statuses = defaultdict(lambda: defaultdict(int)) |
| 46 | 48 |
| 47 if not output_json: | 49 if not output_json: |
| 48 return tests_statuses | 50 return tests_statuses |
| 49 | 51 |
| 50 for iteration in output_json.get('per_iteration_data'): | 52 for iteration in output_json.get('per_iteration_data'): |
| 51 for name, test_runs in iteration.iteritems(): | 53 for name, test_runs in iteration.iteritems(): |
| 52 tests_statuses[name]['total_run'] += len(test_runs) | 54 tests_statuses[name]['total_run'] += len(test_runs) |
| 53 for test_run in test_runs: | 55 for test_run in test_runs: |
| 54 tests_statuses[name][test_run['status']] += 1 | 56 tests_statuses[name][test_run['status']] += 1 |
| 55 | 57 |
| 56 # Should query by test name, because some test has dependencies which | 58 # Should query by test name, because some test has dependencies which |
| 57 # are also run, like TEST and PRE_TEST in browser_tests. | 59 # are also run, like TEST and PRE_TEST in browser_tests. |
| 58 tries = tests_statuses.get(test_name, {}).get('total_run', 0) | 60 tries = tests_statuses.get(test_name, {}).get('total_run', 0) |
| 59 successes = tests_statuses.get(test_name, {}).get('SUCCESS', 0) | 61 successes = tests_statuses.get(test_name, {}).get('SUCCESS', 0) |
| 60 | 62 |
| 61 if tries > 0: | 63 if tries > 0: |
| 62 success_rate = successes * 1.0 / tries | 64 pass_rate = successes * 1.0 / tries |
| 63 else: | 65 else: |
| 64 success_rate = -1 # Special value to indicate test is not existing. | 66 pass_rate = -1 # Special value to indicate test is not existing. |
| 65 | 67 |
| 66 master_flake_analysis = MasterFlakeAnalysis.Get(master_name, builder_name, | 68 master_flake_analysis = MasterFlakeAnalysis.GetVersion( |
| 67 master_build_number, | 69 master_name, builder_name, master_build_number, step_name, test_name, |
| 68 step_name, test_name) | 70 version=version_number) |
| 71 logging.info( |
| 72 'Updating MasterFlakeAnalysis data %s/%s/%s/%s/%s', |
| 73 master_name, builder_name, build_number, step_name, test_name) |
| 74 logging.info('MasterFlakeAnalysis %s version %s', |
| 75 master_flake_analysis, master_flake_analysis.version_number) |
| 76 |
| 77 data_point = DataPoint() |
| 78 data_point.build_number = build_number |
| 79 data_point.pass_rate = pass_rate |
| 80 master_flake_analysis.data_points.append(data_point) |
| 81 |
| 69 flake_swarming_task = FlakeSwarmingTask.Get( | 82 flake_swarming_task = FlakeSwarmingTask.Get( |
| 70 master_name, builder_name, build_number, step_name, test_name) | 83 master_name, builder_name, build_number, step_name, test_name) |
| 71 | |
| 72 master_flake_analysis.build_numbers.append(build_number) | |
| 73 master_flake_analysis.success_rates.append(success_rate) | |
| 74 flake_swarming_task.tries = tries | 84 flake_swarming_task.tries = tries |
| 75 flake_swarming_task.successes = successes | 85 flake_swarming_task.successes = successes |
| 76 flake_swarming_task.put() | 86 flake_swarming_task.put() |
| 87 |
| 88 results = flake_swarming_task.GetFlakeSwarmingTaskData() |
| 89 # TODO(lijeffrey): Determine whether or not this flake swarming task |
| 90 # was a cache hit (already ran results for more iterations than were |
| 91 # requested) and update results['cache_hit'] accordingly. |
| 92 master_flake_analysis.swarming_rerun_results.append(results) |
| 77 master_flake_analysis.put() | 93 master_flake_analysis.put() |
| 78 return tests_statuses | 94 return tests_statuses |
| 79 | 95 |
| 80 def _GetArgs(self, master_name, builder_name, build_number, | 96 def _GetArgs(self, master_name, builder_name, build_number, |
| 81 step_name, *args): | 97 step_name, *args): |
| 82 master_build_number = args[0] | 98 master_build_number = args[0] |
| 83 test_name = args[1] | 99 test_name = args[1] |
| 100 version_number = args[2] |
| 84 return (master_name, builder_name, build_number, step_name, | 101 return (master_name, builder_name, build_number, step_name, |
| 85 master_build_number, test_name) | 102 master_build_number, test_name, version_number) |
| 86 | 103 |
| 87 # Unused Argument - pylint: disable=W0612,W0613 | 104 # Unused Argument - pylint: disable=W0612,W0613 |
| 88 def _GetSwarmingTask(self, master_name, builder_name, build_number, | 105 def _GetSwarmingTask(self, master_name, builder_name, build_number, |
| 89 step_name, master_build_number, test_name): | 106 step_name, master_build_number, test_name, _): |
| 90 # Get the appropriate kind of Swarming Task (Flake). | 107 # Get the appropriate kind of Swarming Task (Flake). |
| 91 return FlakeSwarmingTask.Get(master_name, builder_name, | 108 return FlakeSwarmingTask.Get(master_name, builder_name, |
| 92 build_number, step_name, test_name) | 109 build_number, step_name, test_name) |
| OLD | NEW |