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

Side by Side Diff: appengine/findit/handlers/flake/check_flake.py

Issue 2456033002: [Findit] Using flake_analysis_service and add bug number to check flake UI (Closed)
Patch Set: Addressing Comments Created 4 years, 1 month 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
« no previous file with comments | « no previous file | appengine/findit/handlers/flake/test/check_flake_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 from google.appengine.api import users 5 from google.appengine.api import users
6 6
7 from common import auth_util 7 from common import auth_util
8 from common import constants
9 from common import time_util 8 from common import time_util
10 from common.base_handler import BaseHandler 9 from common.base_handler import BaseHandler
11 from common.base_handler import Permission 10 from common.base_handler import Permission
12 from model import analysis_status 11 from model import analysis_status
13 from model import triage_status 12 from model import triage_status
14 from waterfall.flake import initialize_flake_pipeline 13 from model.flake.flake_analysis_request import FlakeAnalysisRequest
14 from model.flake.master_flake_analysis import MasterFlakeAnalysis
15 from waterfall.flake import flake_analysis_service
15 from waterfall.flake import triggering_sources 16 from waterfall.flake import triggering_sources
16 17
17 18
18 def _GetSuspectedFlakeAnalysisAndTriageResult(analysis): 19 def _GetSuspectedFlakeAnalysisAndTriageResult(analysis):
19 if analysis.suspected_flake_build_number is not None: 20 if analysis.suspected_flake_build_number is not None:
20 return { 21 return {
21 'build_number': analysis.suspected_flake_build_number, 22 'build_number': analysis.suspected_flake_build_number,
22 'triage_result': ( 23 'triage_result': (
23 analysis.triage_history[-1].triage_result if analysis.triage_history 24 analysis.triage_history[-1].triage_result if analysis.triage_history
24 else triage_status.UNTRIAGED) 25 else triage_status.UNTRIAGED)
25 } 26 }
26 27
27 return {} 28 return {}
28 29
29 30
30 class CheckFlake(BaseHandler): 31 class CheckFlake(BaseHandler):
31 PERMISSION_LEVEL = Permission.ANYONE 32 PERMISSION_LEVEL = Permission.ANYONE
32 33
34 def _ValidateInput(self, master_name, builder_name, build_number, step_name,
35 test_name, bug_id):
36 """Ensures the input is valid and generates an error otherwise.
37
38 Args:
39 master_name (str): The name of the master the flaky test was found on.
40 builder_name (str): The name of the builder the flaky test was found on.
41 build_number (str): The build number the flaky test was found on.
42 step_name (str): The step the flaky test was found on.
43 test_name (str): The name of the flaky test.
44 bug_id (str): The bug number associated with the flaky test.
45
46 Returns:
47 None if all input fields are valid, or an error dict otherwise.
48 """
49
50 if not master_name:
51 return self.CreateError('Master name must be specified', 400)
52
53 if not builder_name:
54 return self.CreateError('Builder name must be specified', 400)
55
56 if not build_number or not build_number.isdigit():
57 return self.CreateError('Build number must be specified as an int', 400)
58
59 if not step_name:
60 return self.CreateError('Step name must be specified', 400)
61
62 if not test_name:
63 return self.CreateError('Test name must be specified', 400)
64
65 if bug_id and not bug_id.isdigit():
66 return self.CreateError('Bug id (optional) must be an int', 400)
67
68 return None
69
33 def HandleGet(self): 70 def HandleGet(self):
34 master_name = self.request.get('master_name').strip() 71 master_name = self.request.get('master_name', '').strip()
35 builder_name = self.request.get('builder_name').strip() 72 builder_name = self.request.get('builder_name', '').strip()
36 build_number = int(self.request.get('build_number', '0').strip()) 73 build_number = self.request.get('build_number', '').strip()
37 step_name = self.request.get('step_name').strip() 74 step_name = self.request.get('step_name', '').strip()
38 test_name = self.request.get('test_name').strip() 75 test_name = self.request.get('test_name', '').strip()
76 bug_id = self.request.get('bug_id', '').strip()
77 # TODO(lijeffrey): Add support for force flag to trigger a rerun.
39 78
40 if not (master_name and builder_name and build_number and 79 error = self._ValidateInput(
41 step_name and test_name): # pragma: no cover. 80 master_name, builder_name, build_number, step_name, test_name, bug_id)
42 return self.CreateError(
43 'Invalid value of master/builder/build_number/step/test', 400)
44 81
45 force = (auth_util.IsCurrentUserAdmin() and 82 if error: # pragma: no cover
46 self.request.get('force') == '1') 83 return error
47 allow_new_analysis = self.IsCorpUserOrAdmin()
48 84
49 # TODO(lijeffrey): Use flake_analysis_service.ScheduleAnalysisForFlake. 85 build_number = int(build_number)
86 bug_id = int(bug_id) if bug_id else None
50 user_email = auth_util.GetUserEmail() 87 user_email = auth_util.GetUserEmail()
51 analysis = initialize_flake_pipeline.ScheduleAnalysisIfNeeded( 88 is_admin = auth_util.IsCurrentUserAdmin()
52 master_name, builder_name, build_number, step_name, test_name,
53 allow_new_analysis, force=force, manually_triggered=True,
54 user_email=user_email, triggering_source=triggering_sources.FINDIT_UI,
55 queue_name=constants.WATERFALL_ANALYSIS_QUEUE)
56 89
57 if not analysis: # pragma: no cover. 90 request = FlakeAnalysisRequest.Create(test_name, False, bug_id)
58 return { 91 request.AddBuildStep(master_name, builder_name, build_number, step_name,
59 'template': 'error.html', 92 time_util.GetUTCNow())
60 'data': { 93 scheduled = flake_analysis_service.ScheduleAnalysisForFlake(
61 'error_message': 94 request, user_email, is_admin, triggering_sources.FINDIT_UI)
62 ('You could schedule an analysis for flaky test only after ' 95
63 'you login with google.com account.'), 96 analysis = MasterFlakeAnalysis.GetVersion(
64 'login_url': self.GetLoginUrl(), 97 master_name, builder_name, build_number, step_name, test_name)
65 }, 98
66 'return_code': 401, 99 if not analysis:
67 } 100 if scheduled is None:
101 # User does not have permission to trigger, nor was any previous
102 # analysis triggered to view.
103 return {
104 'template': 'error.html',
105 'data': {
106 'error_message':
107 ('You could schedule an analysis for flaky test only after '
108 'you login with google.com account.'),
109 'login_url': self.GetLoginUrl(),
110 },
111 'return_code': 401,
112 }
113
114 # Check if a previous request has already covered this analysis so use the
115 # results from that analysis.
116 request = FlakeAnalysisRequest.GetVersion(key=test_name)
117
118 if request and request.analyses:
119 analysis = request.analyses[-1].get()
stgao 2016/10/31 22:03:15 How do we plan to deal with the legacy data for th
stgao 2016/10/31 22:08:03 Will this always return the analysis for the maste
120 else:
121 return {
122 'template': 'error.html',
123 'data': {
124 'error_message': (
125 'Flake analysis is not supported for this request. Either '
126 'the build step may not be supported or the test is not '
127 'swarmed.'),
128 },
129 'return_code': 401,
130 }
68 131
69 suspected_flake = _GetSuspectedFlakeAnalysisAndTriageResult(analysis) 132 suspected_flake = _GetSuspectedFlakeAnalysisAndTriageResult(analysis)
70 133
71 data = { 134 data = {
72 'pass_rates': [], 135 'pass_rates': [],
73 'analysis_status': analysis.status_description, 136 'analysis_status': analysis.status_description,
74 'master_name': master_name, 137 'master_name': master_name,
75 'builder_name': builder_name, 138 'builder_name': builder_name,
76 'build_number': build_number, 139 'build_number': build_number,
77 'step_name': step_name, 140 'step_name': step_name,
(...skipping 25 matching lines...) Expand all
103 coordinates.append([data_point.build_number, data_point.pass_rate]) 166 coordinates.append([data_point.build_number, data_point.pass_rate])
104 167
105 # Order by build number from earliest to latest. 168 # Order by build number from earliest to latest.
106 coordinates.sort(key=lambda x: x[0]) 169 coordinates.sort(key=lambda x: x[0])
107 170
108 data['pass_rates'] = coordinates 171 data['pass_rates'] = coordinates
109 return { 172 return {
110 'template': 'flake/result.html', 173 'template': 'flake/result.html',
111 'data': data 174 'data': data
112 } 175 }
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/handlers/flake/test/check_flake_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698