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

Side by Side Diff: appengine/findit/handlers/test/triage_analysis_test.py

Issue 2029873002: [Findit] Cross-platform triage (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Pacific time midnight matching analysis cutoff Created 4 years, 6 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 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 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 datetime import datetime
6 from datetime import timedelta
7
5 from google.appengine.ext import ndb 8 from google.appengine.ext import ndb
6 import webapp2 9 import webapp2
7 10
8 from testing_utils import testing 11 from testing_utils import testing
9 12
10 from handlers import triage_analysis 13 from handlers import triage_analysis
14 from model import analysis_status
15 from model import result_status
11 from model.wf_analysis import WfAnalysis 16 from model.wf_analysis import WfAnalysis
12 from model import result_status
13 from model import analysis_status
14 from waterfall import buildbot 17 from waterfall import buildbot
15 18
16 19
17 class TriageAnalysisTest(testing.AppengineTestCase): 20 class TriageAnalysisTest(testing.AppengineTestCase):
18 app_module = webapp2.WSGIApplication([ 21 app_module = webapp2.WSGIApplication([
19 ('/triage-analysis', triage_analysis.TriageAnalysis), 22 ('/triage-analysis', triage_analysis.TriageAnalysis),
20 ], debug=True) 23 ], debug=True)
21 24
22 def setUp(self): 25 def setUp(self):
23 super(TriageAnalysisTest, self).setUp() 26 super(TriageAnalysisTest, self).setUp()
24 self.master_name = 'm' 27 self.master_name = 'm'
25 self.builder_name = 'b' 28 self.builder_name = 'b'
26 self.build_number_incomplete = 120 # Analysis is not completed yet. 29 self.build_number_incomplete = 120 # Analysis is not completed yet.
27 self.build_number_found = 122 # Suspected CLs are found for this build. 30 self.build_number_found = 122 # Suspected CLs are found for this build.
28 self.build_number_not_found = 123 # No suspected CLs found. 31 self.build_number_not_found = 123 # No suspected CLs found.
29 self.suspected_cls = [{ 32 self.suspected_cls = [{
30 'repo_name': 'chromium', 33 'repo_name': 'chromium',
31 'revision': 'r1', 34 'revision': 'r1',
32 'commit_position': 123, 35 'commit_position': 123,
33 'url': 'https://codereview.chromium.org/123', 36 'url': 'https://codereview.chromium.org/123',
34 }] 37 }]
35 38
39 self.build_start_time = (datetime.utcnow() - timedelta(2)).replace(
40 hour=12, minute=0, second=0, microsecond=0) # Two days ago, UTC Noon.
41
36 analysis = WfAnalysis.Create( 42 analysis = WfAnalysis.Create(
37 self.master_name, self.builder_name, self.build_number_incomplete) 43 self.master_name, self.builder_name, self.build_number_incomplete)
38 analysis.status = analysis_status.RUNNING 44 analysis.status = analysis_status.RUNNING
39 analysis.put() 45 analysis.put()
40 46
41 analysis = WfAnalysis.Create( 47 analysis = WfAnalysis.Create(
42 self.master_name, self.builder_name, self.build_number_found) 48 self.master_name, self.builder_name, self.build_number_found)
43 analysis.status = analysis_status.COMPLETED 49 analysis.status = analysis_status.COMPLETED
44 analysis.suspected_cls = self.suspected_cls 50 analysis.suspected_cls = self.suspected_cls
51 analysis.build_start_time = self.build_start_time
45 analysis.put() 52 analysis.put()
46 53
47 analysis = WfAnalysis.Create( 54 analysis = WfAnalysis.Create(
48 self.master_name, self.builder_name, self.build_number_not_found) 55 self.master_name, self.builder_name, self.build_number_not_found)
49 analysis.status = analysis_status.COMPLETED 56 analysis.status = analysis_status.COMPLETED
50 analysis.put() 57 analysis.put()
51 58
52 self.mock_current_user(user_email='test@chromium.org', is_admin=True) 59 self.mock_current_user(user_email='test@chromium.org', is_admin=True)
53 60
54 def testUpdateAnalysisResultStatusWhenAnalysisIsIncomplete(self): 61 def testUpdateAnalysisResultStatusWhenAnalysisIsIncomplete(self):
55 success = triage_analysis._UpdateAnalysisResultStatus( 62 success, _ = triage_analysis._UpdateAnalysisResultStatus(
56 self.master_name, self.builder_name, self.build_number_incomplete, True) 63 self.master_name, self.builder_name, self.build_number_incomplete, True)
57 self.assertFalse(success) 64 self.assertFalse(success)
58 analysis = WfAnalysis.Get( 65 analysis = WfAnalysis.Get(
59 self.master_name, self.builder_name, self.build_number_found) 66 self.master_name, self.builder_name, self.build_number_found)
60 self.assertIsNone(analysis.result_status) 67 self.assertIsNone(analysis.result_status)
61 68
62 def testUpdateAnalysisResultStatusWhenFoundAndCorrect(self): 69 def testUpdateAnalysisResultStatusWhenFoundAndCorrect(self):
63 success = triage_analysis._UpdateAnalysisResultStatus( 70 success = triage_analysis._UpdateAnalysisResultStatus(
64 self.master_name, self.builder_name, self.build_number_found, True) 71 self.master_name, self.builder_name, self.build_number_found, True)
65 self.assertTrue(success) 72 self.assertTrue(success)
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 self.assertEquals({'success': False}, response.json_body) 130 self.assertEquals({'success': False}, response.json_body)
124 131
125 def testSuccessfulTriage(self): 132 def testSuccessfulTriage(self):
126 build_url = buildbot.CreateBuildUrl( 133 build_url = buildbot.CreateBuildUrl(
127 self.master_name, self.builder_name, self.build_number_found) 134 self.master_name, self.builder_name, self.build_number_found)
128 response = self.test_app.get( 135 response = self.test_app.get(
129 '/triage-analysis', 136 '/triage-analysis',
130 params={'url': build_url, 'correct': True, 'format': 'json'}) 137 params={'url': build_url, 'correct': True, 'format': 'json'})
131 self.assertEquals(200, response.status_int) 138 self.assertEquals(200, response.status_int)
132 self.assertEquals({'success': True}, response.json_body) 139 self.assertEquals({'success': True}, response.json_body)
140
141 def testIncompleteTriage(self):
142 build_url = buildbot.CreateBuildUrl(
143 self.master_name, self.builder_name, self.build_number_incomplete)
144 response = self.test_app.get(
145 '/triage-analysis',
146 params={'url': build_url, 'correct': True, 'format': 'json'})
147 self.assertEquals(200, response.status_int)
148 self.assertEquals({'success': False}, response.json_body)
149
150 def testAnalysesMatch(self):
151 analysis_with_empty_failures = WfAnalysis.Create(
152 self.master_name, self.builder_name, 200)
153 analysis_with_empty_failures.result = {
154 'failures': []
155 }
156 analysis_with_empty_failures.put()
157
158 analysis_with_no_suspected_cls = WfAnalysis.Create(
159 self.master_name, self.builder_name, 201)
160 analysis_with_no_suspected_cls.result = {
161 'failures': [
162 {
163 'suspected_cls': []
164 },
165 {
166 'suspected_cls': []
167 },
168 ]
169 }
170 analysis_with_no_suspected_cls.put()
171
172 analysis_with_suspected_cls_1 = WfAnalysis.Create(
173 self.master_name, self.builder_name, 202)
174 analysis_with_suspected_cls_1.result = {
175 'failures': [
176 {
177 'step_name': 'interactive_ui_tests',
178 'suspected_cls': [
179 {
180 'revision': '3cf9343f4602d4ec11717cb6ff56a793c1d5f84b',
181 }
182 ],
183 }
184 ]
185 }
186 analysis_with_suspected_cls_1.put()
187
188 analysis_with_suspected_cls_2 = WfAnalysis.Create(
189 self.master_name, self.builder_name, 203)
190 analysis_with_suspected_cls_2.result = {
191 'failures': [
192 {
193 'suspected_cls': [],
194 'step_name': 'browser_tests'
195 },
196 {
197 'suspected_cls': [
198 {
199 'revision': '0e8dc209f5e4a6140e43551de0e036324c68a383',
200 }
201 ],
202 'step_name': 'content_browsertests'
203 }
204 ]
205 }
206 analysis_with_suspected_cls_2.put()
207
208 analysis_with_suspected_cls_3 = WfAnalysis.Create(
209 self.master_name, self.builder_name, 204)
210 analysis_with_suspected_cls_3.result = {
211 'failures': [
212 {
213 'suspected_cls': [],
214 'step_name': 'browser_tests',
215 },
216 {
217 'suspected_cls': [
218 {
219 'revision': '0e8dc209f5e4a6140e43551de0e036324c68a383',
220 },
221 {
222 'revision': '292b41bbd603ae2f11d239f457a8a5f04387fa85',
223 },
224 {
225 'revision': 'f6c9ef029e28a6bef28e727cd70751d782963e21',
226 }
227 ],
228 'step_name': 'content_browsertests',
229 }
230 ]
231 }
232 analysis_with_suspected_cls_3.result_status = result_status.FOUND_UNTRIAGED
233 analysis_with_suspected_cls_3.build_start_time = self.build_start_time
234 analysis_with_suspected_cls_3.put()
235
236 analysis_with_suspected_cls_4 = WfAnalysis.Create(
237 self.master_name, self.builder_name, 205)
238 analysis_with_suspected_cls_4.result = {
239 'failures': [
240 {
241 'suspected_cls': [],
242 'step_name': 'browser_tests',
243 },
244 {
245 'suspected_cls': [
246 {
247 'revision': '0e8dc209f5e4a6140e43551de0e036324c68a383',
lijeffrey 2016/06/24 01:30:06 nit: this is fine but you can get away with using
josiahk 2016/06/24 18:12:39 Ah ok. I changed them. Thanks!
248 },
249 {
250 'revision': '292b41bbd603ae2f11d239f457a8a5f04387fa85',
251 },
252 {
253 'revision': 'f6c9ef029e28a6bef28e727cd70751d782963e21',
254 }
255 ],
256 'step_name': 'content_browsertests',
257 }
258 ]
259 }
260 analysis_with_suspected_cls_4.result_status = result_status.FOUND_UNTRIAGED
261 analysis_with_suspected_cls_4.build_start_time = self.build_start_time
262 analysis_with_suspected_cls_4.put()
263
264 analysis_with_tests_1 = WfAnalysis.Create(
265 self.master_name, self.builder_name, 206)
266 analysis_with_tests_1.result = {
267 'failures': [
268 {
269 'tests': [
270 {
271 'test_name': 'super_test_1',
272 'suspected_cls': [
273 {
274 'revision': 'abc'
275 }
276 ]
277 }, {
278 'test_name': 'super_test_2',
279 'suspected_cls': [
280 {
281 'revision': 'def'
282 },
283 {
284 'revision': 'ghi'
285 }
286 ]
287 }
288 ],
289 'step_name': 'interactive_ui_tests',
290 'suspected_cls': [
291 {
292 'revision': '3cf9343f4602d4ec11717cb6ff56a793c1d5f84b',
293 }
294 ],
295 }
296 ]
297 }
298 analysis_with_tests_1.put()
299
300 analysis_with_tests_2 = WfAnalysis.Create(
301 self.master_name, self.builder_name, 207)
302 analysis_with_tests_2.result = {
303 'failures': [
304 {
305 'tests': [
306 {
307 'test_name': 'super_test_3',
308 'suspected_cls': [
309 {
310 'revision': 'ab'
311 },
312 {
313 'revision': 'cd'
314 },
315 {
316 'revision': 'ef'
317 }
318 ]
319 }
320 ],
321 'step_name': 'interactive_ui_tests',
322 'suspected_cls': [
323 {
324 'revision': '3cf9343f4602d4ec11717cb6ff56a793c1d5f84b',
325 }
326 ],
327 }
328 ]
329 }
330 analysis_with_tests_2.put()
331
332 # Empty failures list.
333 self.assertFalse(triage_analysis._DoAnalysesMatch(
334 analysis_with_empty_failures,
335 analysis_with_empty_failures))
336 # Zero culprit-tuples.
337 self.assertFalse(triage_analysis._DoAnalysesMatch(
338 analysis_with_no_suspected_cls,
339 analysis_with_no_suspected_cls))
340 # Zero culprit-tuples and some culprit-tuples.
341 self.assertFalse(triage_analysis._DoAnalysesMatch(
342 analysis_with_no_suspected_cls,
343 analysis_with_suspected_cls_1))
344 # Has step-level culprit-tuples, and should detect match.
345 self.assertTrue(triage_analysis._DoAnalysesMatch(
346 analysis_with_suspected_cls_2,
347 analysis_with_suspected_cls_2))
348 # Two different step-level culprit-tuples, and should fail to match.
349 self.assertFalse(triage_analysis._DoAnalysesMatch(
350 analysis_with_suspected_cls_2,
351 analysis_with_suspected_cls_3))
352 # Has test-level culprit-tuples, and should detect match.
353 self.assertTrue(triage_analysis._DoAnalysesMatch(
354 analysis_with_tests_1,
355 analysis_with_tests_1))
356 # Two different test-level culprit-tuples, and should fail to match.
357 self.assertFalse(triage_analysis._DoAnalysesMatch(
358 analysis_with_tests_1,
359 analysis_with_tests_2))
360
361 def createAnalysis(self, build_number, build_start_time):
lijeffrey 2016/06/24 01:30:06 nit: I would make this an internal method, i.e. _c
josiahk 2016/06/24 18:12:39 Done.
362 analysis = WfAnalysis.Create(
363 self.master_name, self.builder_name, build_number)
364 analysis.result = {
365 'failures': [
366 {
367 'suspected_cls': [
368 {
369 'revision': 'abc',
370 }
371 ],
372 'step_name': 'turing_test',
373 }
374 ]
375 }
376 analysis.result_status = result_status.FOUND_UNTRIAGED
377 analysis.build_start_time = build_start_time
378 analysis.status = analysis_status.COMPLETED
379 analysis.put()
380 return analysis
381
382 def testGetDuplicateAnalysesTooEarly(self):
383 # Two days ago, UTC Noon.
384 original_time = (datetime.utcnow() - timedelta(days=2)).replace(
385 hour=12, minute=0, second=0, microsecond=0)
386 analysis_original = self.createAnalysis(300, original_time)
387
388 # An earlier time, outside bounds.
389 too_early_time = (original_time - timedelta(
390 hours=triage_analysis.MATCHING_ANALYSIS_HOURS_AGO_START*2))
391 self.createAnalysis(301, too_early_time)
392
393 self.assertEquals(
394 len(triage_analysis._GetDuplicateAnalyses(analysis_original)), 0)
395
396 def testGetDuplicateAnalysesEarlier(self):
397 # Two days ago, UTC Noon.
398 original_time = (datetime.utcnow() - timedelta(days=2)).replace(
399 hour=12, minute=0, second=0, microsecond=0)
400 analysis_original = self.createAnalysis(302, original_time)
401
402 # An earlier time, within bounds.
403 earlier_time = (original_time - timedelta(
404 hours=triage_analysis.MATCHING_ANALYSIS_HOURS_AGO_START/2))
405 self.createAnalysis(303, earlier_time)
406
407 self.assertEquals(
408 len(triage_analysis._GetDuplicateAnalyses(analysis_original)), 1)
409
410 def testGetDuplicateAnalysesLater(self):
411 # Two days ago, UTC Noon.
412 original_time = (datetime.utcnow() - timedelta(days=2)).replace(
413 hour=12, minute=0, second=0, microsecond=0)
414 analysis_original = self.createAnalysis(304, original_time)
415
416 # A later time, within bounds.
417 later_time = (original_time + timedelta(
418 hours=triage_analysis.MATCHING_ANALYSIS_HOURS_AGO_START/2))
419 self.createAnalysis(305, later_time)
420
421 self.assertEquals(
422 len(triage_analysis._GetDuplicateAnalyses(analysis_original)), 1)
423
424 def testGetDuplicateAnalysesTooLate(self):
425 # Two days ago, UTC Noon.
426 original_time = (datetime.utcnow() - timedelta(days=2)).replace(
427 hour=12, minute=0, second=0, microsecond=0)
428 analysis_original = self.createAnalysis(306, original_time)
429
430 # A later time, outside bounds.
431 too_late_time = (original_time + timedelta(
432 hours=triage_analysis.MATCHING_ANALYSIS_HOURS_AGO_START*2))
433 self.createAnalysis(307, too_late_time)
434
435 self.assertEquals(
436 len(triage_analysis._GetDuplicateAnalyses(analysis_original)), 0)
437
438 def testGetDuplicateAnalysesNotToday(self):
439 # Tomorrow, UTC Noon.
440 original_time = (datetime.utcnow() + timedelta(days=1)).replace(
441 hour=12, minute=0, second=0, microsecond=0)
442 analysis_original = self.createAnalysis(308, original_time)
443
444 # Create another analysis at the same time (also tomorrow).
445 self.createAnalysis(309, original_time)
446
447 self.assertEquals(
448 len(triage_analysis._GetDuplicateAnalyses(analysis_original)), 0)
449
450 def testTriageDuplicateResults(self):
451 # Two days ago, UTC Noon.
452 original_time = (datetime.utcnow() - timedelta(days=2)).replace(
453 hour=12, minute=0, second=0, microsecond=0)
454 analysis_original = self.createAnalysis(310, original_time)
455
456 # Create another analysis at the same time (also two days ago).
457 self.createAnalysis(311, original_time)
458
459 triage_analysis._TriageDuplicateResults(analysis_original, True)
460
461 second_analysis = WfAnalysis.Get(self.master_name, self.builder_name, 311)
462
463 self.assertEquals(result_status.NOT_FOUND_CORRECT,
464 second_analysis.result_status)
465
OLDNEW
« no previous file with comments | « no previous file | appengine/findit/handlers/triage_analysis.py » ('j') | appengine/findit/handlers/triage_analysis.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698