
The build-info subcommand fetches detailed information on a build given its UUID. It is possible to also either list the build's artifacts, the Ansible inventory used for the job, or download the build's console output. Fix incorrect info fetching. Change-Id: I1707ab083e4964a8ac410a7421f64acaffe06023
459 lines
18 KiB
Python
459 lines
18 KiB
Python
# Copyright 2020 Red Hat, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from tests.unit import BaseTestCase
|
|
from tests.unit import FakeRequestResponse
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
from zuulclient.api import ZuulRESTClient, BearerAuth
|
|
from zuulclient.api import ZuulRESTException
|
|
|
|
|
|
class TestApi(BaseTestCase):
|
|
|
|
def test_client_init(self):
|
|
"""Test initialization of a client"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
self.assertEqual('https://fake.zuul/', client.url)
|
|
self.assertEqual('https://fake.zuul/api/', client.base_url)
|
|
self.assertEqual(False, client.session.verify)
|
|
self.assertFalse('Authorization' in client.session.headers)
|
|
client = ZuulRESTClient(url='https://fake.zuul')
|
|
self.assertEqual('https://fake.zuul/', client.url)
|
|
self.assertEqual('https://fake.zuul/api/', client.base_url)
|
|
client = ZuulRESTClient(url='https://fake.zuul/with/path/')
|
|
self.assertEqual('https://fake.zuul/with/path/', client.url)
|
|
self.assertEqual('https://fake.zuul/with/path/api/', client.base_url)
|
|
token = 'aiaiaiai'
|
|
client = ZuulRESTClient(url='https://fake.zuul/', verify=True,
|
|
auth_token=token)
|
|
self.assertEqual('https://fake.zuul/', client.url)
|
|
self.assertEqual('https://fake.zuul/api/', client.base_url)
|
|
self.assertEqual(True, client.session.verify)
|
|
self.assertTrue(isinstance(client.session.auth, BearerAuth))
|
|
self.assertEqual(token, client.session.auth._token)
|
|
|
|
def _test_status_check(self, client, verb, func, *args, **kwargs):
|
|
# validate request errors
|
|
for error_code, regex in [(401, 'Unauthorized'),
|
|
(403, 'Insufficient privileges'),
|
|
(500, 'Unknown error')]:
|
|
with self.assertRaisesRegex(ZuulRESTException,
|
|
regex):
|
|
req = FakeRequestResponse(error_code)
|
|
if verb == 'post':
|
|
client.session.post = MagicMock(return_value=req)
|
|
elif verb == 'get':
|
|
client.session.get = MagicMock(return_value=req)
|
|
elif verb == 'delete':
|
|
client.session.delete = MagicMock(return_value=req)
|
|
else:
|
|
raise Exception('Unknown HTTP "verb" %s' % verb)
|
|
func(*args, **kwargs)
|
|
|
|
def test_autohold(self):
|
|
"""Test autohold"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
# token required
|
|
with self.assertRaisesRegex(Exception, 'Auth Token required'):
|
|
client.autohold(
|
|
'tenant', 'project', 'job', 1, None, 'reason', 1, 3600)
|
|
|
|
client = ZuulRESTClient(url='https://fake.zuul/',
|
|
auth_token='aiaiaiai')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'post', client.autohold,
|
|
'tenant', 'project', 'job', 1, None, 'reason', 1, 3600)
|
|
# test REST call
|
|
req = FakeRequestResponse(200, True)
|
|
client.session.post = MagicMock(return_value=req)
|
|
ah = client.autohold(
|
|
'tenant', 'project', 'job', 1, None, 'reason', 1, 3600)
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant/project/project/autohold',
|
|
json={'reason': 'reason',
|
|
'count': 1,
|
|
'job': 'job',
|
|
'change': 1,
|
|
'ref': None,
|
|
'node_hold_expiration': 3600}
|
|
)
|
|
self.assertEqual(True, ah)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
ah = client.autohold(
|
|
'tenant1', 'project', 'job', 1, None, 'reason', 1, 3600)
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/project/project/autohold',
|
|
json={'reason': 'reason',
|
|
'count': 1,
|
|
'job': 'job',
|
|
'change': 1,
|
|
'ref': None,
|
|
'node_hold_expiration': 3600}
|
|
)
|
|
self.assertEqual(True, ah)
|
|
|
|
def test_autohold_list(self):
|
|
"""Test autohold-list"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'get', client.autohold_list, 'tenant1')
|
|
|
|
fakejson = [
|
|
{'id': 123,
|
|
'tenant': 'tenant1',
|
|
'project': 'project1',
|
|
'job': 'job1',
|
|
'ref_filter': '.*',
|
|
'max_count': 1,
|
|
'current_count': 0,
|
|
'reason': 'because',
|
|
'nodes': ['node1', 'node2']}
|
|
]
|
|
req = FakeRequestResponse(200, fakejson)
|
|
client.session.get = MagicMock(return_value=req)
|
|
ahl = client.autohold_list('tenant1')
|
|
client.session.get.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/autohold')
|
|
self.assertEqual(fakejson, ahl)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
ahl = client.autohold_list('tenant1')
|
|
client.session.get.assert_called_with(
|
|
'https://fake.zuul/api/autohold')
|
|
self.assertEqual(fakejson, ahl)
|
|
|
|
def test_autohold_delete(self):
|
|
"""Test autohold-delete"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# token required
|
|
with self.assertRaisesRegex(Exception, 'Auth Token required'):
|
|
client.autohold_delete(123, 'tenant1')
|
|
|
|
client = ZuulRESTClient(url='https://fake.zuul/',
|
|
auth_token='aiaiaiai')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'delete', client.autohold_delete,
|
|
123, 'tenant1')
|
|
|
|
# test REST call
|
|
req = FakeRequestResponse(204)
|
|
client.session.delete = MagicMock(return_value=req)
|
|
ahd = client.autohold_delete(123, 'tenant1')
|
|
client.session.delete.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/autohold/123'
|
|
)
|
|
self.assertEqual(True, ahd)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
ahd = client.autohold_delete(123, 'tenant1')
|
|
client.session.delete.assert_called_with(
|
|
'https://fake.zuul/api/autohold/123'
|
|
)
|
|
self.assertEqual(True, ahd)
|
|
|
|
def test_autohold_info(self):
|
|
"""Test autohold-info"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'get', client.autohold_info, 123, 'tenant1')
|
|
|
|
fakejson = {
|
|
'id': 123,
|
|
'tenant': 'tenant1',
|
|
'project': 'project1',
|
|
'job': 'job1',
|
|
'ref_filter': '.*',
|
|
'max_count': 1,
|
|
'current_count': 0,
|
|
'reason': 'because',
|
|
'nodes': ['node1', 'node2']
|
|
}
|
|
req = FakeRequestResponse(200, fakejson)
|
|
client.session.get = MagicMock(return_value=req)
|
|
ahl = client.autohold_info(tenant='tenant1', id=123)
|
|
client.session.get.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/autohold/123')
|
|
self.assertEqual(fakejson, ahl)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
ahl = client.autohold_info(tenant='tenant1', id=123)
|
|
client.session.get.assert_called_with(
|
|
'https://fake.zuul/api/autohold/123')
|
|
self.assertEqual(fakejson, ahl)
|
|
|
|
def test_enqueue(self):
|
|
"""Test enqueue"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# token required
|
|
with self.assertRaisesRegex(Exception, 'Auth Token required'):
|
|
client.enqueue('tenant1', 'check', 'project1', '1,1')
|
|
|
|
client = ZuulRESTClient(url='https://fake.zuul/',
|
|
auth_token='aiaiaiai')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'post', client.enqueue,
|
|
'tenant1', 'check', 'project1', '1,1')
|
|
|
|
# test REST call
|
|
req = FakeRequestResponse(200, True)
|
|
client.session.post = MagicMock(return_value=req)
|
|
enq = client.enqueue('tenant1', 'check', 'project1', '1,1')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/project/project1/enqueue',
|
|
json={'change': '1,1',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, enq)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
enq = client.enqueue('tenant1', 'check', 'project1', '1,1')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/project/project1/enqueue',
|
|
json={'change': '1,1',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, enq)
|
|
|
|
def test_enqueue_ref(self):
|
|
"""Test enqueue ref"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# token required
|
|
with self.assertRaisesRegex(Exception, 'Auth Token required'):
|
|
client.enqueue_ref(
|
|
'tenant1', 'check', 'project1', 'refs/heads/stable', '0', '0')
|
|
|
|
client = ZuulRESTClient(url='https://fake.zuul/',
|
|
auth_token='aiaiaiai')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'post', client.enqueue_ref,
|
|
'tenant1', 'check', 'project1', 'refs/heads/stable', '0', '0')
|
|
|
|
# test REST call
|
|
req = FakeRequestResponse(200, True)
|
|
client.session.post = MagicMock(return_value=req)
|
|
enq_ref = client.enqueue_ref(
|
|
'tenant1', 'check', 'project1', 'refs/heads/stable', '0', '0')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/project/project1/enqueue',
|
|
json={'ref': 'refs/heads/stable',
|
|
'oldrev': '0',
|
|
'newrev': '0',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, enq_ref)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
enq_ref = client.enqueue_ref(
|
|
'tenant1', 'check', 'project1', 'refs/heads/stable', '0', '0')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/project/project1/enqueue',
|
|
json={'ref': 'refs/heads/stable',
|
|
'oldrev': '0',
|
|
'newrev': '0',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, enq_ref)
|
|
|
|
def test_dequeue(self):
|
|
"""Test dequeue"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# token required
|
|
with self.assertRaisesRegex(Exception, 'Auth Token required'):
|
|
client.dequeue('tenant1', 'check', 'project1', '1,1')
|
|
|
|
client = ZuulRESTClient(url='https://fake.zuul/',
|
|
auth_token='aiaiaiai')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'post', client.dequeue,
|
|
'tenant1', 'check', 'project1', '1,1')
|
|
|
|
# test conditions on ref and change
|
|
with self.assertRaisesRegex(Exception, 'need change OR ref'):
|
|
client.dequeue(
|
|
'tenant1', 'check', 'project1', '1,1', 'refs/heads/stable')
|
|
|
|
# test REST call
|
|
req = FakeRequestResponse(200, True)
|
|
client.session.post = MagicMock(return_value=req)
|
|
deq = client.dequeue('tenant1', 'check', 'project1', change='1,1')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/project/project1/dequeue',
|
|
json={'change': '1,1',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, deq)
|
|
deq = client.dequeue(
|
|
'tenant1', 'check', 'project1', ref='refs/heads/stable')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/project/project1/dequeue',
|
|
json={'ref': 'refs/heads/stable',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, deq)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
deq = client.dequeue('tenant1', 'check', 'project1', change='1,1')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/project/project1/dequeue',
|
|
json={'change': '1,1',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, deq)
|
|
deq = client.dequeue(
|
|
'tenant1', 'check', 'project1', ref='refs/heads/stable')
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/project/project1/dequeue',
|
|
json={'ref': 'refs/heads/stable',
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, deq)
|
|
|
|
def test_promote(self):
|
|
"""Test promote"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
# token required
|
|
with self.assertRaisesRegex(Exception, 'Auth Token required'):
|
|
client.promote('tenant1', 'check', ['1,1', '2,1'])
|
|
|
|
client = ZuulRESTClient(url='https://fake.zuul/',
|
|
auth_token='aiaiaiai')
|
|
client.info_ = {}
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'post', client.promote,
|
|
'tenant1', 'check', ['1,1', '2,1'])
|
|
|
|
# test REST call
|
|
req = FakeRequestResponse(200, True)
|
|
client.session.post = MagicMock(return_value=req)
|
|
prom = client.promote('tenant1', 'check', ['1,1', '2,1'])
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/promote',
|
|
json={'changes': ['1,1', '2,1'],
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, prom)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
prom = client.promote('tenant1', 'check', ['1,1', '2,1'])
|
|
client.session.post.assert_called_with(
|
|
'https://fake.zuul/api/promote',
|
|
json={'changes': ['1,1', '2,1'],
|
|
'pipeline': 'check'}
|
|
)
|
|
self.assertEqual(True, prom)
|
|
|
|
def test_get_key(self):
|
|
"""Test getting a project's public key"""
|
|
pubkey = """
|
|
-----BEGIN PUBLIC KEY-----
|
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqiwMzHBCMu8Nsz6LH5Rr
|
|
E0hUJvuHhEfGF2S+1Y7ux7MtrE7zFsKK3JYZLbJuuQ62w5UsDtjRCQ8A4RhDVItZ
|
|
lPzEIvrz3SVnOX61cAkc3FOZq3GG+vXZHzbyZUgQV6eh7cvvxKACaI10WLNTKvD2
|
|
0Hb8comVtrFFG333x+9MxGQIKhoaBFGDcBnTsWlSVFxyWFxkvmlmFfglR2IV7c5O
|
|
YAKWItpRYDCfZMvptwsDm8fRnafW7ADvMsFhKgSkQX0YnXBwVDIjywYMiaz9zzo6
|
|
zOfxhwe8fGWxUtaQObpnJ7uAiXrFBEefXdTR+5Zh5j0mR1MB0W0VupK7ezVOQ6LW
|
|
JNKtggslhDR/iPUbRaMMILWUJtLAin4I6ZOP05wNrau0zoYp5iW3hY4AV4+i+oYL
|
|
Rcl2SNzPYnZXMTvfsZV1f4J6fu1vLivRS6ynYWjYZWucK0C2NpD0NTMfP5jcUU3K
|
|
uM10zi/xzsPZ42xkVQFv0OfznwJVBDVMovQFOCBVKFP52wT44mmcMcTZQjyMBJLR
|
|
psLogzoSlPF9MfewbYwStYcA1HroexMPifQ7unvdzdb0S9y/RiN2WJgt8meXGrWU
|
|
JHyRBXb/ZW7Hy5CEMEkPY8+DcwvyNfN6cdTni8htcDZA/N1hzhaslKoUYcdCS8dH
|
|
GuS6/ewjS+arA1Iyeg/IxmECAwEAAQ==
|
|
-----END PUBLIC KEY-----"""
|
|
req = FakeRequestResponse(200, text=pubkey)
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
client.info_ = {}
|
|
client.session.get = MagicMock(return_value=req)
|
|
key = client.get_key('tenant1', 'project1')
|
|
client.session.get.assert_called_with(
|
|
'https://fake.zuul/api/tenant/tenant1/key/project1.pub'
|
|
)
|
|
self.assertEqual(pubkey, key)
|
|
client.info_ = {'tenant': 'tenant1'}
|
|
key = client.get_key('tenant1', 'project1')
|
|
client.session.get.assert_called_with(
|
|
'https://fake.zuul/api/key/project1.pub'
|
|
)
|
|
self.assertEqual(pubkey, key)
|
|
|
|
def test_build(self):
|
|
"""Test build endpoint"""
|
|
client = ZuulRESTClient(url='https://fake.zuul/')
|
|
# test status checks
|
|
self._test_status_check(
|
|
client, 'get', client.build, 'tenant1', 'a1a1a1a1')
|
|
|
|
fakejson = {
|
|
'uuid': 'a1a1a1a1',
|
|
'job_name': 'tox-py38',
|
|
'result': 'SUCCESS',
|
|
'held': False,
|
|
'start_time': '2020-09-10T14:08:55',
|
|
'end_time': '2020-09-10T14:13:35',
|
|
'duration': 280.0,
|
|
'voting': True,
|
|
'log_url': 'https://log.storage/',
|
|
'node_name': None,
|
|
'error_detail': None,
|
|
'final': True,
|
|
'artifacts': [
|
|
{'name': 'Download all logs',
|
|
'url': 'https://log.storage/download-logs.sh',
|
|
'metadata': {
|
|
'command': 'xxx'}
|
|
},
|
|
{'name': 'Zuul Manifest',
|
|
'url': 'https://log.storage/zuul-manifest.json',
|
|
'metadata': {
|
|
'type': 'zuul_manifest'
|
|
}
|
|
},
|
|
{'name': 'Unit Test Report',
|
|
'url': 'https://log.storage/testr_results.html',
|
|
'metadata': {
|
|
'type': 'unit_test_report'
|
|
}
|
|
}],
|
|
'provides': [],
|
|
'project': 'project1',
|
|
'branch': 'master',
|
|
'pipeline': 'check',
|
|
'change': 1234,
|
|
'patchset': '1',
|
|
'ref': 'refs/changes/34/1234/1',
|
|
'newrev': None,
|
|
'ref_url': 'https://gerrit/1234',
|
|
'event_id': '6b28762adfce415ba47e440c365ae624',
|
|
'buildset': {'uuid': 'b1b1b1'}}
|
|
req = FakeRequestResponse(200, fakejson)
|
|
client.session.get = MagicMock(return_value=req)
|
|
ahl = client.build(tenant='tenant1', uuid='a1a1a1a1')
|
|
client.session.get.assert_any_call(
|
|
'https://fake.zuul/api/tenant/tenant1/build/a1a1a1a1')
|
|
self.assertEqual(fakejson, ahl)
|