Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(142)

Side by Side Diff: appengine/findit/waterfall/flake/recursive_flake_pipeline.py

Issue 2369333002: [Findit] Capture versionized metadata for master_flake_analysis (Closed)
Patch Set: Fixing nits Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 common import appengine_util 7 from common import appengine_util
6 from common import constants 8 from common import constants
9 from common import time_util
7 from common.pipeline_wrapper import BasePipeline 10 from common.pipeline_wrapper import BasePipeline
8 11
9 from model import analysis_status 12 from model import analysis_status
10 from model.flake.flake_swarming_task import FlakeSwarmingTask 13 from model.flake.flake_swarming_task import FlakeSwarmingTask
11 from model.flake.master_flake_analysis import MasterFlakeAnalysis 14 from model.flake.master_flake_analysis import MasterFlakeAnalysis
12 from waterfall import waterfall_config 15 from waterfall import waterfall_config
13 from waterfall.process_flake_swarming_task_result_pipeline import ( 16 from waterfall.process_flake_swarming_task_result_pipeline import (
14 ProcessFlakeSwarmingTaskResultPipeline) 17 ProcessFlakeSwarmingTaskResultPipeline)
15 from waterfall.trigger_flake_swarming_task_pipeline import ( 18 from waterfall.trigger_flake_swarming_task_pipeline import (
16 TriggerFlakeSwarmingTaskPipeline) 19 TriggerFlakeSwarmingTaskPipeline)
17 20
18 21
22 def _UpdateAnalysisStatusUponCompletion(master_flake_analysis, status, error):
23 master_flake_analysis.completed_time = time_util.GetUTCNow()
24 master_flake_analysis.status = status
25
26 if error:
27 master_flake_analysis.error = error
28
29 master_flake_analysis.put()
30
31
19 class RecursiveFlakePipeline(BasePipeline): 32 class RecursiveFlakePipeline(BasePipeline):
20 33
21 # Arguments number differs from overridden method - pylint: disable=W0221 34 # Arguments number differs from overridden method - pylint: disable=W0221
22 def run(self, master_name, builder_name, run_build_number, step_name, 35 def run(self, master_name, builder_name, run_build_number, step_name,
23 test_name, master_build_number, flakiness_algorithm_results_dict, 36 test_name, version_number, master_build_number,
24 queue_name=constants.DEFAULT_QUEUE): 37 flakiness_algorithm_results_dict, queue_name=constants.DEFAULT_QUEUE):
25 """Pipeline to determine the regression range of a flaky test. 38 """Pipeline to determine the regression range of a flaky test.
26 39
27 Args: 40 Args:
28 master_name (str): The master name. 41 master_name (str): The master name.
29 builder_name (str): The builder name. 42 builder_name (str): The builder name.
30 run_build_number (int): The build number of the current swarming rerun. 43 run_build_number (int): The build number of the current swarming rerun.
31 step_name (str): The step name. 44 step_name (str): The step name.
32 test_name (str): The test name. 45 test_name (str): The test name.
46 version_number (int): The version to save analysis results and data to.
33 master_build_number (int): The build number of the Master_Flake_analysis. 47 master_build_number (int): The build number of the Master_Flake_analysis.
34 flakiness_algorithm_results_dict (dict): A dictionary used by 48 flakiness_algorithm_results_dict (dict): A dictionary used by
35 NextBuildNumberPipeline 49 NextBuildNumberPipeline
36 queue_name (str): Which queue to run on. 50 queue_name (str): Which queue to run on.
37 51
38 Returns: 52 Returns:
39 A dict of lists for reliable/flaky tests. 53 A dict of lists for reliable/flaky tests.
40 """ 54 """
41 master = MasterFlakeAnalysis.Get(master_name, builder_name, 55 flake_analysis = MasterFlakeAnalysis.GetVersion(
42 master_build_number, step_name, test_name) 56 master_name, builder_name, master_build_number, step_name, test_name,
43 if master.status != analysis_status.RUNNING: # pragma: no branch 57 version=version_number)
44 master.status = analysis_status.RUNNING 58 logging.info(
45 master.put() 59 'Running RecursiveFlakePipeline on MasterFlakeAnalysis %s/%s/%s/%s/%s',
60 master_name, builder_name, master_build_number, step_name, test_name)
61 logging.info(
62 'MasterFlakeAnalysis %s version %s', flake_analysis, version_number)
63
64 if flake_analysis.status != analysis_status.RUNNING: # pragma: no branch
65 flake_analysis.status = analysis_status.RUNNING
66 flake_analysis.put()
46 67
47 # Call trigger pipeline (flake style). 68 # Call trigger pipeline (flake style).
48 task_id = yield TriggerFlakeSwarmingTaskPipeline( 69 task_id = yield TriggerFlakeSwarmingTaskPipeline(
49 master_name, builder_name, run_build_number, step_name, [test_name]) 70 master_name, builder_name, run_build_number, step_name, [test_name])
50 # Pass the trigger pipeline into a process pipeline. 71 # Pass the trigger pipeline into a process pipeline.
51 test_result_future = yield ProcessFlakeSwarmingTaskResultPipeline( 72 test_result_future = yield ProcessFlakeSwarmingTaskResultPipeline(
52 master_name, builder_name, run_build_number, 73 master_name, builder_name, run_build_number,
53 step_name, task_id, master_build_number, test_name) 74 step_name, task_id, master_build_number, test_name, version_number)
54 yield NextBuildNumberPipeline( 75 yield NextBuildNumberPipeline(
55 master_name, builder_name, master_build_number, run_build_number, 76 master_name, builder_name, master_build_number, run_build_number,
56 step_name, test_name, test_result_future, queue_name, 77 step_name, test_name, version_number, test_result_future, queue_name,
57 flakiness_algorithm_results_dict) 78 flakiness_algorithm_results_dict)
58 79
59 80
60 def get_next_run(master, flakiness_algorithm_results_dict): 81 def get_next_run(master_flake_analysis, flakiness_algorithm_results_dict):
61 # A description of this algorithm can be found at: 82 # A description of this algorithm can be found at:
62 # https://docs.google.com/document/d/1wPYFZ5OT998Yn7O8wGDOhgfcQ98mknoX13AesJaS 6ig/edit 83 # https://docs.google.com/document/d/1wPYFZ5OT998Yn7O8wGDOhgfcQ98mknoX13AesJaS 6ig/edit
63 # Get the last result. 84 # Get the last result.
64 last_result = master.success_rates[-1] 85 last_result = master_flake_analysis.data_points[-1].pass_rate
65 cur_run = min(master.build_numbers) 86 cur_run = min([d.build_number for d in master_flake_analysis.data_points])
66 flake_settings = waterfall_config.GetCheckFlakeSettings() 87 flake_settings = waterfall_config.GetCheckFlakeSettings()
67 lower_flake_threshold = flake_settings.get('lower_flake_threshold') 88 lower_flake_threshold = flake_settings.get('lower_flake_threshold')
68 upper_flake_threshold = flake_settings.get('upper_flake_threshold') 89 upper_flake_threshold = flake_settings.get('upper_flake_threshold')
69 max_stable_in_a_row = flake_settings.get('max_stable_in_a_row') 90 max_stable_in_a_row = flake_settings.get('max_stable_in_a_row')
70 max_flake_in_a_row = flake_settings.get('max_flake_in_a_row') 91 max_flake_in_a_row = flake_settings.get('max_flake_in_a_row')
71 92
72 if last_result < 0: # Test doesn't exist in the current build number. 93 if last_result < 0: # Test doesn't exist in the current build number.
73 flakiness_algorithm_results_dict['stable_in_a_row'] += 1 94 flakiness_algorithm_results_dict['stable_in_a_row'] += 1
74 flakiness_algorithm_results_dict['stabled_out'] = True 95 flakiness_algorithm_results_dict['stabled_out'] = True
75 flakiness_algorithm_results_dict['flaked_out'] = True 96 flakiness_algorithm_results_dict['flaked_out'] = True
76 flakiness_algorithm_results_dict['lower_boundary_result'] = 'STABLE' 97 flakiness_algorithm_results_dict['lower_boundary_result'] = 'STABLE'
77 98
78 lower_boundary = master.build_numbers[ 99 lower_boundary = master_flake_analysis.data_points[
79 -flakiness_algorithm_results_dict['stable_in_a_row']] 100 -flakiness_algorithm_results_dict['stable_in_a_row']].build_number
80 101
81 flakiness_algorithm_results_dict['lower_boundary'] = lower_boundary 102 flakiness_algorithm_results_dict['lower_boundary'] = lower_boundary
82 flakiness_algorithm_results_dict['sequential_run_index'] += 1 103 flakiness_algorithm_results_dict['sequential_run_index'] += 1
83 return lower_boundary + 1 104 return lower_boundary + 1
84 elif (last_result < lower_flake_threshold or 105 elif (last_result < lower_flake_threshold or
85 last_result > upper_flake_threshold): # Stable result. 106 last_result > upper_flake_threshold): # Stable result.
86 flakiness_algorithm_results_dict['stable_in_a_row'] += 1 107 flakiness_algorithm_results_dict['stable_in_a_row'] += 1
87 if (flakiness_algorithm_results_dict['stable_in_a_row'] > 108 if (flakiness_algorithm_results_dict['stable_in_a_row'] >
88 max_stable_in_a_row): # Identified a stable region. 109 max_stable_in_a_row): # Identified a stable region.
89 flakiness_algorithm_results_dict['stabled_out'] = True 110 flakiness_algorithm_results_dict['stabled_out'] = True
90 if (flakiness_algorithm_results_dict['stabled_out'] and 111 if (flakiness_algorithm_results_dict['stabled_out'] and
91 not flakiness_algorithm_results_dict['flaked_out']): 112 not flakiness_algorithm_results_dict['flaked_out']):
92 # Identified a candidate for the upper boundary. 113 # Identified a candidate for the upper boundary.
93 # Earliest stable point to the right of a flaky region. 114 # Earliest stable point to the right of a flaky region.
94 flakiness_algorithm_results_dict['upper_boundary'] = cur_run 115 flakiness_algorithm_results_dict['upper_boundary'] = cur_run
95 flakiness_algorithm_results_dict['lower_boundary'] = None 116 flakiness_algorithm_results_dict['lower_boundary'] = None
(...skipping 24 matching lines...) Expand all
120 not flakiness_algorithm_results_dict['lower_boundary']): 141 not flakiness_algorithm_results_dict['lower_boundary']):
121 # Identified a candidate for the lower boundary. 142 # Identified a candidate for the lower boundary.
122 # Latest flaky point to the left of a stable region. 143 # Latest flaky point to the left of a stable region.
123 flakiness_algorithm_results_dict['lower_boundary'] = cur_run 144 flakiness_algorithm_results_dict['lower_boundary'] = cur_run
124 flakiness_algorithm_results_dict['lower_boundary_result'] = 'FLAKE' 145 flakiness_algorithm_results_dict['lower_boundary_result'] = 'FLAKE'
125 flakiness_algorithm_results_dict['stable_in_a_row'] = 0 146 flakiness_algorithm_results_dict['stable_in_a_row'] = 0
126 step_size = flakiness_algorithm_results_dict['flakes_in_a_row'] + 1 147 step_size = flakiness_algorithm_results_dict['flakes_in_a_row'] + 1
127 return cur_run - step_size 148 return cur_run - step_size
128 149
129 150
130 def sequential_next_run(master, flakiness_algorithm_results_dict): 151 def sequential_next_run(
131 last_result = master.success_rates[-1] 152 master_flake_analysis, flakiness_algorithm_results_dict):
153 last_result = master_flake_analysis.data_points[-1].pass_rate
132 last_result_status = 'FLAKE' 154 last_result_status = 'FLAKE'
133 flake_settings = waterfall_config.GetCheckFlakeSettings() 155 flake_settings = waterfall_config.GetCheckFlakeSettings()
134 lower_flake_threshold = flake_settings.get('lower_flake_threshold') 156 lower_flake_threshold = flake_settings.get('lower_flake_threshold')
135 upper_flake_threshold = flake_settings.get('upper_flake_threshold') 157 upper_flake_threshold = flake_settings.get('upper_flake_threshold')
136 158
137 if (last_result < lower_flake_threshold or 159 if (last_result < lower_flake_threshold or
138 last_result > upper_flake_threshold): 160 last_result > upper_flake_threshold):
139 last_result_status = 'STABLE' 161 last_result_status = 'STABLE'
140 if flakiness_algorithm_results_dict['sequential_run_index'] > 0: 162 if flakiness_algorithm_results_dict['sequential_run_index'] > 0:
141 if (last_result_status != 163 if (last_result_status !=
142 flakiness_algorithm_results_dict['lower_boundary_result']): 164 flakiness_algorithm_results_dict['lower_boundary_result']):
143 master.suspected_flake_build_number = ( 165 master_flake_analysis.suspected_flake_build_number = (
144 flakiness_algorithm_results_dict['lower_boundary'] + 166 flakiness_algorithm_results_dict['lower_boundary'] +
145 flakiness_algorithm_results_dict['sequential_run_index']) 167 flakiness_algorithm_results_dict['sequential_run_index'])
146 master.put() 168 master_flake_analysis.put()
147 return 0 169 return 0
148 flakiness_algorithm_results_dict['sequential_run_index'] += 1 170 flakiness_algorithm_results_dict['sequential_run_index'] += 1
149 return (flakiness_algorithm_results_dict['lower_boundary'] + 171 return (flakiness_algorithm_results_dict['lower_boundary'] +
150 flakiness_algorithm_results_dict['sequential_run_index']) 172 flakiness_algorithm_results_dict['sequential_run_index'])
151 173
152 174
153 class NextBuildNumberPipeline(BasePipeline): 175 class NextBuildNumberPipeline(BasePipeline):
154 176
155 # Arguments number differs from overridden method - pylint: disable=W0221 177 # Arguments number differs from overridden method - pylint: disable=W0221
156 # Unused argument - pylint: disable=W0613 178 # Unused argument - pylint: disable=W0613
157 def run(self, master_name, builder_name, master_build_number, 179 def run(self, master_name, builder_name, master_build_number,
158 run_build_number, step_name, test_name, test_result_future, 180 run_build_number, step_name, test_name, version_number,
159 queue_name, flakiness_algorithm_results_dict): 181 test_result_future, queue_name, flakiness_algorithm_results_dict):
160 182
161 # Get MasterFlakeAnalysis success list corresponding to parameters. 183 # Get MasterFlakeAnalysis success list corresponding to parameters.
162 master = MasterFlakeAnalysis.Get(master_name, builder_name, 184 master_flake_analysis = MasterFlakeAnalysis.GetVersion(
163 master_build_number, step_name, test_name) 185 master_name, builder_name, master_build_number, step_name, test_name,
186 version=version_number)
164 # Don't call another pipeline if we fail. 187 # Don't call another pipeline if we fail.
165 flake_swarming_task = FlakeSwarmingTask.Get( 188 flake_swarming_task = FlakeSwarmingTask.Get(
166 master_name, builder_name, run_build_number, step_name, test_name) 189 master_name, builder_name, run_build_number, step_name, test_name)
167 190
168 if flake_swarming_task.status == analysis_status.ERROR: 191 if flake_swarming_task.status == analysis_status.ERROR:
169 master.status = analysis_status.ERROR 192 # TODO(lijeffrey): Implement more detailed error detection and reporting,
170 master.put() 193 # such as timeouts, dead bots, etc.
194 error = {
195 'error': 'Swarming task failed',
196 'message': 'Swarming task failed'
197 }
198 _UpdateAnalysisStatusUponCompletion(
199 master_flake_analysis, analysis_status.ERROR, error)
171 return 200 return
172 201
173 # Figure out what build_number we should call, if any 202 # Figure out what build_number we should call, if any
174 if (flakiness_algorithm_results_dict['stabled_out'] and 203 if (flakiness_algorithm_results_dict['stabled_out'] and
175 flakiness_algorithm_results_dict['flaked_out']): 204 flakiness_algorithm_results_dict['flaked_out']):
176 next_run = sequential_next_run(master, flakiness_algorithm_results_dict) 205 next_run = sequential_next_run(
206 master_flake_analysis, flakiness_algorithm_results_dict)
177 else: 207 else:
178 next_run = get_next_run(master, flakiness_algorithm_results_dict) 208 next_run = get_next_run(
209 master_flake_analysis, flakiness_algorithm_results_dict)
179 210
180 if next_run < flakiness_algorithm_results_dict['last_build_number']: 211 if next_run < flakiness_algorithm_results_dict['last_build_number']:
181 next_run = 0 212 next_run = 0
182 elif next_run >= master_build_number: 213 elif next_run >= master_build_number:
183 next_run = 0 214 next_run = 0
184 215
185 if next_run: 216 if next_run:
186 pipeline_job = RecursiveFlakePipeline( 217 pipeline_job = RecursiveFlakePipeline(
187 master_name, builder_name, next_run, step_name, test_name, 218 master_name, builder_name, next_run, step_name, test_name,
188 master_build_number, 219 version_number, master_build_number,
189 flakiness_algorithm_results_dict=flakiness_algorithm_results_dict) 220 flakiness_algorithm_results_dict=flakiness_algorithm_results_dict)
190 # pylint: disable=W0201 221 # pylint: disable=W0201
191 pipeline_job.target = appengine_util.GetTargetNameForModule( 222 pipeline_job.target = appengine_util.GetTargetNameForModule(
192 constants.WATERFALL_BACKEND) 223 constants.WATERFALL_BACKEND)
193 pipeline_job.start(queue_name=queue_name) 224 pipeline_job.start(queue_name=queue_name)
194 else: 225 else:
195 master.status = analysis_status.COMPLETED 226 _UpdateAnalysisStatusUponCompletion(
196 master.put() 227 master_flake_analysis, analysis_status.COMPLETED, None)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698