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

Side by Side Diff: appengine/findit/waterfall/test/swarming_util_test.py

Issue 2491473002: [Findit] Implementing swarming task error detection (Closed)
Patch Set: 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
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 import collections 5 import collections
6 import json 6 import json
7 import mock
7 import os 8 import os
8 import urllib 9 import urllib
9 import zlib 10 import zlib
10 11
12 from google.appengine.api.urlfetch_errors import (
13 DeadlineExceededError, DownloadError, ConnectionClosedError)
14
15 from common.http_client_appengine import HttpClientAppengine as HttpClient
11 from common.retry_http_client import RetryHttpClient 16 from common.retry_http_client import RetryHttpClient
12 from model.wf_config import FinditConfig 17 from model.wf_config import FinditConfig
13 from model.wf_step import WfStep 18 from model.wf_step import WfStep
14 from waterfall import swarming_util 19 from waterfall import swarming_util
15 from waterfall import waterfall_config 20 from waterfall import waterfall_config
16 from waterfall.swarming_task_request import SwarmingTaskRequest 21 from waterfall.swarming_task_request import SwarmingTaskRequest
17 from waterfall.test import wf_testcase 22 from waterfall.test import wf_testcase
18 23
19 24
20 class SwarmingHttpClient(RetryHttpClient): 25 class SwarmingHttpClient(RetryHttpClient):
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 url = ('https://chromium-swarm.appspot.com/' 163 url = ('https://chromium-swarm.appspot.com/'
159 '_ah/api/swarming/v1/task/%s/request' % task_id) 164 '_ah/api/swarming/v1/task/%s/request' % task_id)
160 self.logged_http_client.SetResponse( 165 self.logged_http_client.SetResponse(
161 'get', url, json.dumps(task_request_json), 200) 166 'get', url, json.dumps(task_request_json), 200)
162 167
163 task_request = swarming_util.GetSwarmingTaskRequest( 168 task_request = swarming_util.GetSwarmingTaskRequest(
164 task_id, self.logged_http_client) 169 task_id, self.logged_http_client)
165 170
166 self.assertEqual(task_request_json, task_request.Serialize()) 171 self.assertEqual(task_request_json, task_request.Serialize())
167 172
173 @mock.patch.object(swarming_util, '_SendRequestToServer',
174 return_value=(None, {'code': 1, 'message': 'error'}))
175 def testGetSwarmingTaskRequestError(self, _):
176 self.assertIsNone(
177 swarming_util.GetSwarmingTaskRequest('task_id1', HttpClient()))
178
168 def testTriggerSwarmingTask(self): 179 def testTriggerSwarmingTask(self):
169 request = SwarmingTaskRequest() 180 request = SwarmingTaskRequest()
170 request.expiration_secs = 2 181 request.expiration_secs = 2
171 request.name = 'name' 182 request.name = 'name'
172 request.parent_task_id = 'pti' 183 request.parent_task_id = 'pti'
173 request.priority = 1 184 request.priority = 1
174 request.tags = ['tag'] 185 request.tags = ['tag']
175 request.user = 'user' 186 request.user = 'user'
176 request.command = 'cmd' 187 request.command = 'cmd'
177 request.dimensions = [{'key': 'd', 'value': 'dv'}] 188 request.dimensions = [{'key': 'd', 'value': 'dv'}]
(...skipping 22 matching lines...) Expand all
200 'extra_args': ['--flag'], 211 'extra_args': ['--flag'],
201 'grace_period_secs': 5, 212 'grace_period_secs': 5,
202 'idempotent': True, 213 'idempotent': True,
203 'inputs_ref': {'isolated': 'i'}, 214 'inputs_ref': {'isolated': 'i'},
204 'io_timeout_secs': 3, 215 'io_timeout_secs': 3,
205 }, 216 },
206 'tags': ['tag', 'findit:1', 'project:Chromium', 'purpose:post-commit'], 217 'tags': ['tag', 'findit:1', 'project:Chromium', 'purpose:post-commit'],
207 'user': 'user', 218 'user': 'user',
208 } 219 }
209 220
210 task_id = swarming_util.TriggerSwarmingTask( 221 task_id, error = swarming_util.TriggerSwarmingTask(
211 request, self.logged_http_client) 222 request, self.logged_http_client)
212 self.assertEqual('1', task_id) 223 self.assertEqual('1', task_id)
224 self.assertIsNone(error)
213 225
214 method, data, _ = self.logged_http_client.GetRequest(url) 226 method, data, _ = self.logged_http_client.GetRequest(url)
215 self.assertEqual('post', method) 227 self.assertEqual('post', method)
216 self.assertEqual(expected_task_request_json, json.loads(data)) 228 self.assertEqual(expected_task_request_json, json.loads(data))
217 229
230 @mock.patch.object(swarming_util, '_SendRequestToServer',
231 return_value=(None, {'code': 1, 'message': 'error'}))
232 def testTriggerSwarmingTaskError(self, _):
233 request = SwarmingTaskRequest()
234 task_id, error = swarming_util.TriggerSwarmingTask(
235 request, HttpClient())
236 self.assertIsNone(task_id)
237 self.assertIsNotNone(error)
238
218 def testGetIsolatedDataForFailedBuild(self): 239 def testGetIsolatedDataForFailedBuild(self):
219 master_name = 'm' 240 master_name = 'm'
220 builder_name = 'b' 241 builder_name = 'b'
221 build_number = 223 242 build_number = 223
222 failed_steps = { 243 failed_steps = {
223 'a_tests': { 244 'a_tests': {
224 'current_failure': 2, 245 'current_failure': 2,
225 'first_failure': 0 246 'first_failure': 0
226 }, 247 },
227 'unit_tests': { 248 'unit_tests': {
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 389 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
369 'isolated_server') 390 'isolated_server')
370 } 391 }
371 isolated_storage_url = waterfall_config.GetSwarmingSettings().get( 392 isolated_storage_url = waterfall_config.GetSwarmingSettings().get(
372 'isolated_storage_url') 393 'isolated_storage_url')
373 self.http_client._SetResponseForPostRequest('shard1_isolated') 394 self.http_client._SetResponseForPostRequest('shard1_isolated')
374 self.http_client._SetResponseForPostRequest('shard1_url') 395 self.http_client._SetResponseForPostRequest('shard1_url')
375 self.http_client._SetResponseForGetRequestIsolated( 396 self.http_client._SetResponseForGetRequestIsolated(
376 'https://%s/default-gzip/shard1' % isolated_storage_url, 'shard1') 397 'https://%s/default-gzip/shard1' % isolated_storage_url, 'shard1')
377 398
378 result = swarming_util._DownloadTestResults( 399 result, error = swarming_util._DownloadTestResults(
379 isolated_data, self.http_client) 400 isolated_data, self.http_client)
380 401
381 expected_result = json.loads(zlib.decompress( 402 expected_result = json.loads(zlib.decompress(
382 self.http_client._GetData('isolated', 'shard1'))) 403 self.http_client._GetData('isolated', 'shard1')))
383 self.assertEqual(expected_result, result) 404 self.assertEqual(expected_result, result)
405 self.assertIsNone(error)
384 406
385 def testDownloadTestResultsFailedForSecondHash(self): 407 def testDownloadTestResultsFailedForSecondHash(self):
386 isolated_data = { 408 isolated_data = {
387 'digest': 'not found', 409 'digest': 'not found',
388 'namespace': 'default-gzip', 410 'namespace': 'default-gzip',
389 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 411 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
390 'isolated_server') 412 'isolated_server')
391 } 413 }
392 414
393 result = swarming_util._DownloadTestResults( 415 result, error = swarming_util._DownloadTestResults(
394 isolated_data, self.http_client) 416 isolated_data, self.http_client)
395 417
396 self.assertIsNone(result) 418 self.assertIsNone(result)
419 self.assertIsNotNone(error)
397 420
398 def testDownloadTestResultsFailedForParsingSecondHash(self): 421 def testDownloadTestResultsFailedForParsingSecondHash(self):
399 isolated_data = { 422 isolated_data = {
400 'digest': 'not found', 423 'digest': 'not found',
401 'namespace': 'default-gzip', 424 'namespace': 'default-gzip',
402 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 425 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
403 'isolated_server') 426 'isolated_server')
404 } 427 }
405 428
406 self.http_client._SetResponseForPostRequest('not found') 429 self.http_client._SetResponseForPostRequest('not found')
407 result = swarming_util._DownloadTestResults( 430 result, error = swarming_util._DownloadTestResults(
408 isolated_data, self.http_client) 431 isolated_data, self.http_client)
409 432
410 self.assertIsNone(result) 433 self.assertIsNone(result)
434 self.assertIsNone(error)
411 435
412 def testDownloadTestResultsFailedForFileUrl(self): 436 def testDownloadTestResultsFailedForFileUrl(self):
413 isolated_data = { 437 isolated_data = {
414 'digest': 'shard1_isolated', 438 'digest': 'shard1_isolated',
415 'namespace': 'default-gzip', 439 'namespace': 'default-gzip',
416 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 440 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
417 'isolated_server') 441 'isolated_server')
418 } 442 }
419 self.http_client._SetResponseForPostRequest('shard1_isolated') 443 self.http_client._SetResponseForPostRequest('shard1_isolated')
420 result = swarming_util._DownloadTestResults( 444 result, error = swarming_util._DownloadTestResults(
421 isolated_data, self.http_client) 445 isolated_data, self.http_client)
422 446
423 self.assertIsNone(result) 447 self.assertIsNone(result)
448 self.assertIsNotNone(error)
424 449
425 def testDownloadTestResultsFailedForFile(self): 450 def testDownloadTestResultsFailedForFile(self):
426 isolated_data = { 451 isolated_data = {
427 'digest': 'shard1_isolated', 452 'digest': 'shard1_isolated',
428 'namespace': 'default-gzip', 453 'namespace': 'default-gzip',
429 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 454 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
430 'isolated_server') 455 'isolated_server')
431 } 456 }
432 self.http_client._SetResponseForPostRequest('shard1_isolated') 457 self.http_client._SetResponseForPostRequest('shard1_isolated')
433 self.http_client._SetResponseForPostRequest('shard1_url') 458 self.http_client._SetResponseForPostRequest('shard1_url')
434 result = swarming_util._DownloadTestResults( 459 result, error = swarming_util._DownloadTestResults(
435 isolated_data, self.http_client) 460 isolated_data, self.http_client)
436 461
437 self.assertIsNone(result) 462 self.assertIsNone(result)
463 self.assertIsNone(error)
438 464
439 def testRetrieveShardedTestResultsFromIsolatedServer(self): 465 def testRetrieveShardedTestResultsFromIsolatedServer(self):
440 isolated_data = [ 466 isolated_data = [
441 { 467 {
442 'digest': 'shard1_isolated', 468 'digest': 'shard1_isolated',
443 'namespace': 'default-gzip', 469 'namespace': 'default-gzip',
444 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 470 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
445 'isolated_server') 471 'isolated_server')
446 }, 472 },
447 { 473 {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 result = swarming_util.RetrieveShardedTestResultsFromIsolatedServer( 543 result = swarming_util.RetrieveShardedTestResultsFromIsolatedServer(
518 isolated_data, self.http_client) 544 isolated_data, self.http_client)
519 545
520 self.assertIsNone(result) 546 self.assertIsNone(result)
521 547
522 def testGetSwarmingTaskResultById(self): 548 def testGetSwarmingTaskResultById(self):
523 task_id = '2944afa502297110' 549 task_id = '2944afa502297110'
524 550
525 self.http_client._SetResponseForGetRequestSwarmingResult(task_id) 551 self.http_client._SetResponseForGetRequestSwarmingResult(task_id)
526 552
527 data = swarming_util.GetSwarmingTaskResultById( 553 data, error = swarming_util.GetSwarmingTaskResultById(
528 task_id, self.http_client) 554 task_id, self.http_client)
529 555
530 expected_outputs_ref = { 556 expected_outputs_ref = {
531 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 557 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
532 'isolated_server'), 558 'isolated_server'),
533 'namespace': 'default-gzip', 559 'namespace': 'default-gzip',
534 'isolated': 'shard1_isolated' 560 'isolated': 'shard1_isolated'
535 } 561 }
536 562
537 self.assertEqual('COMPLETED', data['state']) 563 self.assertEqual('COMPLETED', data['state'])
538 self.assertEqual(expected_outputs_ref, data['outputs_ref']) 564 self.assertEqual(expected_outputs_ref, data['outputs_ref'])
565 self.assertIsNone(error)
566
567 @mock.patch.object(swarming_util, '_SendRequestToServer',
568 return_value=(None, {'code': 1, 'message': 'error'}))
569 def testGetSwarmingTaskResultByIdError(self, _):
570 data, error = swarming_util.GetSwarmingTaskResultById(
571 'task_id', HttpClient())
572 self.assertEqual({}, data)
573 self.assertIsNotNone(error)
539 574
540 def testGetSwarmingTaskFailureLog(self): 575 def testGetSwarmingTaskFailureLog(self):
541 outputs_ref = { 576 outputs_ref = {
542 'isolatedserver': waterfall_config.GetSwarmingSettings().get( 577 'isolatedserver': waterfall_config.GetSwarmingSettings().get(
543 'isolated_server'), 578 'isolated_server'),
544 'namespace': 'default-gzip', 579 'namespace': 'default-gzip',
545 'isolated': 'shard1_isolated' 580 'isolated': 'shard1_isolated'
546 } 581 }
547 582
548 self.http_client._SetResponseForPostRequest('shard1_isolated') 583 self.http_client._SetResponseForPostRequest('shard1_isolated')
549 self.http_client._SetResponseForPostRequest('shard1_url') 584 self.http_client._SetResponseForPostRequest('shard1_url')
550 self.http_client._SetResponseForGetRequestIsolated( 585 self.http_client._SetResponseForGetRequestIsolated(
551 'https://%s/default-gzip/shard1' % ( 586 'https://%s/default-gzip/shard1' % (
552 waterfall_config.GetSwarmingSettings().get('isolated_storage_url')), 587 waterfall_config.GetSwarmingSettings().get('isolated_storage_url')),
553 'shard1') 588 'shard1')
554 589
555 result = swarming_util.GetSwarmingTaskFailureLog( 590 result, error = swarming_util.GetSwarmingTaskFailureLog(
556 outputs_ref, self.http_client) 591 outputs_ref, self.http_client)
557 592
558 expected_result = json.loads(zlib.decompress( 593 expected_result = json.loads(zlib.decompress(
559 self.http_client._GetData('isolated', 'shard1'))) 594 self.http_client._GetData('isolated', 'shard1')))
560 self.assertEqual(expected_result, result) 595 self.assertEqual(expected_result, result)
596 self.assertIsNone(error)
561 597
562 def testRetrieveOutputJsonFileGetDirectly(self): 598 def testRetrieveOutputJsonFileGetDirectly(self):
563 output_json_content = ('{"content": "eJyrVkpLzMwpLUotVrKKVgpJLS4xV' 599 output_json_content = ('{"content": "eJyrVkpLzMwpLUotVrKKVgpJLS4xV'
564 'IrVUVAqS8zJTFGyUigpKk2tBQDr9wxZ"}') 600 'IrVUVAqS8zJTFGyUigpKk2tBQDr9wxZ"}')
565 601
566 failure_log = swarming_util._RetrieveOutputJsonFile( 602 failure_log = swarming_util._RetrieveOutputJsonFile(
567 output_json_content, self.http_client) 603 output_json_content, self.http_client)
568 604
569 expected_failure_log = { 605 expected_failure_log = {
570 'failures': ['Test1'], 606 'failures': ['Test1'],
571 'valid': True 607 'valid': True
572 } 608 }
573 609
574 self.assertEqual(expected_failure_log, failure_log) 610 self.assertEqual(expected_failure_log, failure_log)
575 611
576 def testGetTagValueInvalidTag(self): 612 def testGetTagValueInvalidTag(self):
577 tags = ['a:1', 'b:2'] 613 tags = ['a:1', 'b:2']
578 self.assertIsNone(swarming_util.GetTagValue(tags, 'c')) 614 self.assertIsNone(swarming_util.GetTagValue(tags, 'c'))
579 615
580 def testGenerateIsolatedDataOutputsrefNone(self): 616 def testGenerateIsolatedDataOutputsrefNone(self):
581 self.assertEqual({}, swarming_util._GenerateIsolatedData(None)) 617 self.assertEqual({}, swarming_util._GenerateIsolatedData(None))
582 618
583 def testFetchOutputJsonInfoFromIsolatedServerReturnNone(self): 619 def testFetchOutputJsonInfoFromIsolatedServerReturnNone(self):
584 self.assertIsNone(swarming_util._FetchOutputJsonInfoFromIsolatedServer( 620 self.assertIsNone(swarming_util._FetchOutputJsonInfoFromIsolatedServer(
585 None, self.http_client)) 621 None, self.http_client))
622
623 @mock.patch.object(
624 RetryHttpClient, 'Get', side_effect=ConnectionClosedError())
625 def testSendRequestToServerConnectionClosedError(self, _):
626 content, error = swarming_util._SendRequestToServer('url', HttpClient())
627 self.assertIsNone(content)
628 self.assertEqual(
629 error['code'], swarming_util.URLFETCH_CONNECTION_CLOSED_ERROR)
630
631 @mock.patch.object(
632 RetryHttpClient, 'Get', side_effect=DeadlineExceededError())
633 def testSendRequestToServerDeadlineExceededError(self, _):
634 content, error = swarming_util._SendRequestToServer('url', HttpClient())
635 self.assertIsNone(content)
636 self.assertEqual(
637 error['code'], swarming_util.URLFETCH_DEADLINE_EXCEEDED_ERROR)
638
639 @mock.patch.object(RetryHttpClient, 'Get', side_effect=DownloadError())
640 def testSendRequestToServerDownloadError(self, _):
641 content, error = swarming_util._SendRequestToServer('url', HttpClient())
642 self.assertIsNone(content)
643 self.assertEqual(error['code'], swarming_util.URLFETCH_DOWNLOAD_ERROR)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698