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

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

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

Powered by Google App Engine
This is Rietveld 408576698