You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
12 KiB
Python
381 lines
12 KiB
Python
# Copyright 2025 The Chromium Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
"""Tests for buildbucket tools."""
|
|
|
|
import json
|
|
import os
|
|
import pathlib
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from unittest import mock
|
|
|
|
sys.path.insert(
|
|
0,
|
|
os.path.abspath(
|
|
pathlib.Path(__file__).resolve().parent.parent.joinpath(
|
|
pathlib.Path('infra_lib'))))
|
|
import buildbucket
|
|
|
|
|
|
class BuildbucketTest(unittest.IsolatedAsyncioTestCase):
|
|
|
|
def setUp(self):
|
|
self.mock_context = mock.AsyncMock()
|
|
self.mock_context.info = mock.AsyncMock()
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_status_success(self, mock_subprocess_run):
|
|
build_id = '12345'
|
|
expected_status = 'SUCCESS'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[],
|
|
returncode=0,
|
|
stdout=json.dumps({'status': expected_status}),
|
|
stderr='')
|
|
|
|
status = await buildbucket.get_build_status(
|
|
self.mock_context,
|
|
build_id,
|
|
)
|
|
|
|
self.assertEqual(status, expected_status)
|
|
expected_command = [
|
|
'prpc', 'call', 'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.GetBuildStatus'
|
|
]
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps({'id': build_id}),
|
|
check=True,
|
|
text=True,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_status_exception(self, mock_subprocess_run):
|
|
build_id = '12345'
|
|
mock_subprocess_run.side_effect = Exception('PRPC call failed')
|
|
|
|
with self.assertRaisesRegex(Exception, 'PRPC call failed'):
|
|
await buildbucket.get_build_status(self.mock_context, build_id)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_from_id_success(self, mock_subprocess_run):
|
|
build_id = '12345'
|
|
fields = ['steps', 'tags']
|
|
expected_output = '{"id": "12345", "steps": [], "tags": []}'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[], returncode=0, stdout=expected_output, stderr='')
|
|
|
|
output = await buildbucket.get_build_from_id(
|
|
self.mock_context,
|
|
build_id,
|
|
fields,
|
|
)
|
|
|
|
self.assertEqual(output, expected_output)
|
|
expected_command = [
|
|
'prpc', 'call', 'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.GetBuild'
|
|
]
|
|
expected_request = {'id': build_id, 'mask': {'fields': 'steps,tags'}}
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps(expected_request),
|
|
check=True,
|
|
text=True)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_from_id_exception(self, mock_subprocess_run):
|
|
build_id = '12345'
|
|
fields = ['steps']
|
|
mock_subprocess_run.side_effect = Exception('PRPC call failed')
|
|
|
|
with self.assertRaisesRegex(Exception, 'PRPC call failed'):
|
|
await buildbucket.get_build_from_id(
|
|
self.mock_context,
|
|
build_id,
|
|
fields,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_from_build_number_success(
|
|
self,
|
|
mock_subprocess_run,
|
|
):
|
|
build_number = 987
|
|
builder_name = 'test_builder'
|
|
builder_bucket = 'try'
|
|
builder_project = 'chromium'
|
|
fields = ['status']
|
|
expected_output = '{"status": "SUCCESS"}'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[], returncode=0, stdout=expected_output, stderr='')
|
|
|
|
output = await buildbucket.get_build_from_build_number(
|
|
self.mock_context, build_number, builder_name, builder_bucket,
|
|
builder_project, fields)
|
|
|
|
self.assertEqual(output, expected_output)
|
|
expected_command = [
|
|
'prpc', 'call', 'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.GetBuild'
|
|
]
|
|
expected_request = {
|
|
'buildNumber': build_number,
|
|
'builder': {
|
|
'builder': builder_name,
|
|
'bucket': builder_bucket,
|
|
'project': builder_project
|
|
},
|
|
'mask': {
|
|
'fields': 'status'
|
|
}
|
|
}
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps(expected_request),
|
|
check=True,
|
|
text=True)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_from_build_number_exception(
|
|
self, mock_subprocess_run):
|
|
build_number = 987
|
|
builder_name = 'test_builder'
|
|
builder_bucket = 'try'
|
|
builder_project = 'chromium'
|
|
fields = ['status']
|
|
mock_subprocess_run.side_effect = Exception('PRPC call failed')
|
|
|
|
with self.assertRaisesRegex(Exception, 'PRPC call failed'):
|
|
await buildbucket.get_build_from_build_number(
|
|
self.mock_context, build_number, builder_name, builder_bucket,
|
|
builder_project, fields)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_success(self, mock_subprocess_run):
|
|
request = {"id": "12345"}
|
|
expected_output = '{"id": "12345"}'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[],
|
|
returncode=0,
|
|
stdout=expected_output,
|
|
stderr='',
|
|
)
|
|
|
|
output = await buildbucket.get_build(self.mock_context, request)
|
|
|
|
self.assertEqual(output, expected_output)
|
|
expected_command = [
|
|
'prpc', 'call', 'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.GetBuild'
|
|
]
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps(request),
|
|
check=True,
|
|
text=True,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_build_exception(self, mock_subprocess_run):
|
|
request = {"id": "12345"}
|
|
mock_subprocess_run.side_effect = Exception('PRPC call failed')
|
|
|
|
with self.assertRaisesRegex(Exception, 'PRPC call failed'):
|
|
await buildbucket.get_build(self.mock_context, request)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_recent_builds_success(self, mock_subprocess_run):
|
|
expected_output = '{"builds": [{"id": "1"}]}'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[],
|
|
returncode=0,
|
|
stdout=expected_output,
|
|
stderr='',
|
|
)
|
|
|
|
output = await buildbucket.get_recent_builds(
|
|
self.mock_context,
|
|
'test_builder',
|
|
'try',
|
|
'chromium',
|
|
10,
|
|
)
|
|
|
|
self.assertEqual(output, expected_output)
|
|
expected_command = [
|
|
'prpc',
|
|
'call',
|
|
'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.SearchBuilds',
|
|
]
|
|
expected_request = {
|
|
'predicate': {
|
|
'builder': {
|
|
'project': 'chromium',
|
|
'bucket': 'try',
|
|
'builder': 'test_builder',
|
|
},
|
|
'status': 'ENDED_MASK',
|
|
},
|
|
'page_size': '10'
|
|
}
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps(expected_request),
|
|
check=True,
|
|
text=True,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_recent_builds_with_url_encoding_success(
|
|
self, mock_subprocess_run):
|
|
builder_name_encoded = 'test%20builder'
|
|
builder_name_decoded = 'test builder'
|
|
expected_output = '{"builds": [{"id": "1"}]}'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[],
|
|
returncode=0,
|
|
stdout=expected_output,
|
|
stderr='',
|
|
)
|
|
|
|
output = await buildbucket.get_recent_builds(
|
|
self.mock_context,
|
|
builder_name_encoded,
|
|
'try',
|
|
'chromium',
|
|
10,
|
|
)
|
|
|
|
self.assertEqual(output, expected_output)
|
|
expected_command = [
|
|
'prpc',
|
|
'call',
|
|
'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.SearchBuilds',
|
|
]
|
|
expected_request = {
|
|
'predicate': {
|
|
'builder': {
|
|
'project': 'chromium',
|
|
'bucket': 'try',
|
|
'builder': builder_name_decoded,
|
|
},
|
|
'status': 'ENDED_MASK',
|
|
},
|
|
'page_size': '10'
|
|
}
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps(expected_request),
|
|
check=True,
|
|
text=True,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_recent_builds_exception(self, mock_subprocess_run):
|
|
mock_subprocess_run.side_effect = Exception('PRPC call failed')
|
|
|
|
with self.assertRaisesRegex(Exception, 'PRPC call failed'):
|
|
await buildbucket.get_recent_builds(
|
|
self.mock_context,
|
|
'test_builder',
|
|
'try',
|
|
'chromium',
|
|
10,
|
|
)
|
|
|
|
async def test_get_recent_builds_invalid_num_builds(self):
|
|
with self.assertRaisesRegex(ValueError,
|
|
'Provided num_builds 0 is not positive'):
|
|
await buildbucket.get_recent_builds(
|
|
self.mock_context,
|
|
'test_builder',
|
|
'try',
|
|
'chromium',
|
|
0,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_recent_failed_builds_success(self, mock_subprocess_run):
|
|
expected_output = '{"builds": [{"id": "1", "status": "FAILURE"}]}'
|
|
mock_subprocess_run.return_value = subprocess.CompletedProcess(
|
|
args=[],
|
|
returncode=0,
|
|
stdout=expected_output,
|
|
stderr='',
|
|
)
|
|
|
|
output = await buildbucket.get_recent_failed_builds(
|
|
self.mock_context,
|
|
'test_builder',
|
|
'try',
|
|
'chromium',
|
|
10,
|
|
)
|
|
|
|
self.assertEqual(output, expected_output)
|
|
expected_command = [
|
|
'prpc',
|
|
'call',
|
|
'cr-buildbucket.appspot.com',
|
|
'buildbucket.v2.Builds.SearchBuilds',
|
|
]
|
|
expected_request = {
|
|
'predicate': {
|
|
'builder': {
|
|
'project': 'chromium',
|
|
'bucket': 'try',
|
|
'builder': 'test_builder',
|
|
},
|
|
'status': 'FAILURE',
|
|
},
|
|
'page_size': '10'
|
|
}
|
|
mock_subprocess_run.assert_called_once_with(
|
|
expected_command,
|
|
capture_output=True,
|
|
input=json.dumps(expected_request),
|
|
check=True,
|
|
text=True,
|
|
)
|
|
|
|
@mock.patch('subprocess.run')
|
|
async def test_get_recent_failed_builds_exception(self,
|
|
mock_subprocess_run):
|
|
mock_subprocess_run.side_effect = Exception('PRPC call failed')
|
|
|
|
with self.assertRaisesRegex(Exception, 'PRPC call failed'):
|
|
await buildbucket.get_recent_failed_builds(
|
|
self.mock_context,
|
|
'test_builder',
|
|
'try',
|
|
'chromium',
|
|
10,
|
|
)
|
|
|
|
async def test_get_recent_failed_builds_invalid_num_builds(self):
|
|
with self.assertRaisesRegex(ValueError,
|
|
'Provided num_builds -1 is not positive'):
|
|
await buildbucket.get_recent_failed_builds(
|
|
self.mock_context,
|
|
'test_builder',
|
|
'try',
|
|
'chromium',
|
|
-1,
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|