Update URLS that require depth or tree filters
Some API endpoints require the use of a filter or they will respond with HTTP error code 418 I'm a teapot. This was seen on CloudBees Jenkins Enterprise 2.107.2.1-rolling. Adding a depth filter will ensure the API calls will succeed. Change-Id: Ib4d6a251bf3a024a76081b2fc83baa7839ad4015
This commit is contained in:
parent
cd440ab4ac
commit
f1f97ab4bf
@ -95,13 +95,13 @@ DEFAULT_HEADERS = {'Content-Type': 'text/xml; charset=utf-8'}
|
|||||||
INFO = 'api/json'
|
INFO = 'api/json'
|
||||||
PLUGIN_INFO = 'pluginManager/api/json?depth=%(depth)s'
|
PLUGIN_INFO = 'pluginManager/api/json?depth=%(depth)s'
|
||||||
CRUMB_URL = 'crumbIssuer/api/json'
|
CRUMB_URL = 'crumbIssuer/api/json'
|
||||||
WHOAMI_URL = 'me/api/json'
|
WHOAMI_URL = 'me/api/json?depth=%(depth)s'
|
||||||
JOBS_QUERY = '?tree=jobs[url,color,name,jobs]'
|
JOBS_QUERY = '?tree=jobs[url,color,name,jobs]'
|
||||||
JOB_INFO = '%(folder_url)sjob/%(short_name)s/api/json?depth=%(depth)s'
|
JOB_INFO = '%(folder_url)sjob/%(short_name)s/api/json?depth=%(depth)s'
|
||||||
JOB_NAME = '%(folder_url)sjob/%(short_name)s/api/json?tree=name'
|
JOB_NAME = '%(folder_url)sjob/%(short_name)s/api/json?tree=name'
|
||||||
ALL_BUILDS = '%(folder_url)sjob/%(short_name)s/api/json?tree=allBuilds[number,url]'
|
ALL_BUILDS = '%(folder_url)sjob/%(short_name)s/api/json?tree=allBuilds[number,url]'
|
||||||
Q_INFO = 'queue/api/json?depth=0'
|
Q_INFO = 'queue/api/json?depth=0'
|
||||||
Q_ITEM = 'queue/item/%(number)d/api/json'
|
Q_ITEM = 'queue/item/%(number)d/api/json?depth=%(depth)s'
|
||||||
CANCEL_QUEUE = 'queue/cancelItem?id=%(id)s'
|
CANCEL_QUEUE = 'queue/cancelItem?id=%(id)s'
|
||||||
CREATE_JOB = '%(folder_url)screateItem?name=%(short_name)s' # also post config.xml
|
CREATE_JOB = '%(folder_url)screateItem?name=%(short_name)s' # also post config.xml
|
||||||
CONFIG_JOB = '%(folder_url)sjob/%(short_name)s/config.xml'
|
CONFIG_JOB = '%(folder_url)sjob/%(short_name)s/config.xml'
|
||||||
@ -122,7 +122,7 @@ BUILD_TEST_REPORT = '%(folder_url)sjob/%(short_name)s/%(number)d/testReport/api/
|
|||||||
'?depth=%(depth)s'
|
'?depth=%(depth)s'
|
||||||
DELETE_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/doDelete'
|
DELETE_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/doDelete'
|
||||||
WIPEOUT_JOB_WORKSPACE = '%(folder_url)sjob/%(short_name)s/doWipeOutWorkspace'
|
WIPEOUT_JOB_WORKSPACE = '%(folder_url)sjob/%(short_name)s/doWipeOutWorkspace'
|
||||||
NODE_LIST = 'computer/api/json'
|
NODE_LIST = 'computer/api/json?depth=%(depth)s'
|
||||||
CREATE_NODE = 'computer/doCreateItem'
|
CREATE_NODE = 'computer/doCreateItem'
|
||||||
DELETE_NODE = 'computer/%(name)s/doDelete'
|
DELETE_NODE = 'computer/%(name)s/doDelete'
|
||||||
NODE_INFO = 'computer/%(name)s/api/json?depth=%(depth)s'
|
NODE_INFO = 'computer/%(name)s/api/json?depth=%(depth)s'
|
||||||
@ -578,7 +578,7 @@ class Jenkins(object):
|
|||||||
raise TimeoutException('Error in request: %s' % (e.reason))
|
raise TimeoutException('Error in request: %s' % (e.reason))
|
||||||
raise JenkinsException('Error in request: %s' % (e.reason))
|
raise JenkinsException('Error in request: %s' % (e.reason))
|
||||||
|
|
||||||
def get_queue_item(self, number):
|
def get_queue_item(self, number, depth=0):
|
||||||
'''Get information about a queued item (to-be-created job).
|
'''Get information about a queued item (to-be-created job).
|
||||||
|
|
||||||
The returned dict will have a "why" key if the queued item is still
|
The returned dict will have a "why" key if the queued item is still
|
||||||
@ -755,7 +755,7 @@ class Jenkins(object):
|
|||||||
raise JenkinsException("Could not parse JSON info for server[%s]"
|
raise JenkinsException("Could not parse JSON info for server[%s]"
|
||||||
% self.server)
|
% self.server)
|
||||||
|
|
||||||
def get_whoami(self):
|
def get_whoami(self, depth=0):
|
||||||
"""Get information about the user account that authenticated to
|
"""Get information about the user account that authenticated to
|
||||||
Jenkins. This is a simple way to verify that your credentials are
|
Jenkins. This is a simple way to verify that your credentials are
|
||||||
correct.
|
correct.
|
||||||
@ -771,7 +771,7 @@ class Jenkins(object):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
response = self.jenkins_open(requests.Request(
|
response = self.jenkins_open(requests.Request(
|
||||||
'GET', self._build_url(WHOAMI_URL)
|
'GET', self._build_url(WHOAMI_URL, locals())
|
||||||
))
|
))
|
||||||
if response is None:
|
if response is None:
|
||||||
raise EmptyResponseException(
|
raise EmptyResponseException(
|
||||||
@ -1410,7 +1410,7 @@ class Jenkins(object):
|
|||||||
'executor': executor_number})
|
'executor': executor_number})
|
||||||
return builds
|
return builds
|
||||||
|
|
||||||
def get_nodes(self):
|
def get_nodes(self, depth=0):
|
||||||
'''Get a list of nodes connected to the Master
|
'''Get a list of nodes connected to the Master
|
||||||
|
|
||||||
Each node is a dict with keys 'name' and 'offline'
|
Each node is a dict with keys 'name' and 'offline'
|
||||||
@ -1419,7 +1419,7 @@ class Jenkins(object):
|
|||||||
'''
|
'''
|
||||||
try:
|
try:
|
||||||
nodes_data = json.loads(self.jenkins_open(
|
nodes_data = json.loads(self.jenkins_open(
|
||||||
requests.Request('GET', self._build_url(NODE_LIST))))
|
requests.Request('GET', self._build_url(NODE_LIST, locals()))))
|
||||||
return [{'name': c["displayName"], 'offline': c["offline"]}
|
return [{'name': c["displayName"], 'offline': c["offline"]}
|
||||||
for c in nodes_data["computer"]]
|
for c in nodes_data["computer"]]
|
||||||
except (req_exc.HTTPError, BadStatusLine):
|
except (req_exc.HTTPError, BadStatusLine):
|
||||||
|
@ -45,7 +45,7 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
|
|||||||
self.j.get_nodes()
|
self.j.get_nodes()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
jenkins_mock.call_args[0][0].url,
|
jenkins_mock.call_args[0][0].url,
|
||||||
self.make_url('computer/api/json'))
|
self.make_url('computer/api/json?depth=0'))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(context_manager.exception),
|
str(context_manager.exception),
|
||||||
'Could not parse JSON info for server[{0}]'.format(
|
'Could not parse JSON info for server[{0}]'.format(
|
||||||
@ -74,7 +74,7 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
|
|||||||
self.j.get_nodes()
|
self.j.get_nodes()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
session_send_mock.call_args_list[1][0][1].url,
|
session_send_mock.call_args_list[1][0][1].url,
|
||||||
self.make_url('computer/api/json'))
|
self.make_url('computer/api/json?depth=0'))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
str(context_manager.exception),
|
str(context_manager.exception),
|
||||||
'Error communicating with server[{0}]'.format(
|
'Error communicating with server[{0}]'.format(
|
||||||
|
@ -107,5 +107,5 @@ class JenkinsQueueItemTest(JenkinsTestBase):
|
|||||||
self.assertEqual(queue_item, queue_item_to_return)
|
self.assertEqual(queue_item, queue_item_to_return)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
jenkins_mock.call_args[0][0].url,
|
jenkins_mock.call_args[0][0].url,
|
||||||
self.make_url('queue/item/25/api/json'))
|
self.make_url('queue/item/25/api/json?depth=0'))
|
||||||
self._check_requests(jenkins_mock.call_args_list)
|
self._check_requests(jenkins_mock.call_args_list)
|
||||||
|
39
tests/test_rest_endpoints.py
Normal file
39
tests/test_rest_endpoints.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import jenkins
|
||||||
|
from tests.base import JenkinsTestBase
|
||||||
|
|
||||||
|
# Vars in the jenkins module scope that do not need validating
|
||||||
|
VAR_WHITELIST = ['__doc__',
|
||||||
|
'__file__',
|
||||||
|
'__name__',
|
||||||
|
'__package__',
|
||||||
|
'CRUMB_URL',
|
||||||
|
'DEFAULT_HEADERS',
|
||||||
|
'EMPTY_CONFIG_XML',
|
||||||
|
'EMPTY_FOLDER_XML',
|
||||||
|
'EMPTY_PROMO_CONFIG_XML',
|
||||||
|
'EMPTY_VIEW_CONFIG_XML',
|
||||||
|
'INFO',
|
||||||
|
'LAUNCHER_SSH',
|
||||||
|
'LAUNCHER_COMMAND',
|
||||||
|
'LAUNCHER_JNLP',
|
||||||
|
'LAUNCHER_WINDOWS_SERVICE',
|
||||||
|
'NODE_TYPE',
|
||||||
|
'PROMO_RECONFIG_XML',
|
||||||
|
'RECONFIG_XML']
|
||||||
|
|
||||||
|
|
||||||
|
class JenkinsRestTest(JenkinsTestBase):
|
||||||
|
|
||||||
|
# If there is no filter (depth or tree) we will get an exception
|
||||||
|
# on some Jenkins instances
|
||||||
|
def test_url_has_filter(self):
|
||||||
|
for var in dir(jenkins):
|
||||||
|
if var in VAR_WHITELIST:
|
||||||
|
continue
|
||||||
|
# Misses unicode on 2.x
|
||||||
|
val = getattr(jenkins, var)
|
||||||
|
if isinstance(val, str):
|
||||||
|
# If we end the path in api/json and don't have depth or tree encoded, fail
|
||||||
|
self.assertEqual(val.endswith('api/json'), False,
|
||||||
|
"URLS that end in 'api/json' must be called with depth or tree:" +
|
||||||
|
"var: [{}] val: [{}]".format(var, val))
|
@ -31,7 +31,7 @@ class JenkinsWhoamiTest(JenkinsTestBase):
|
|||||||
self.assertEqual(user, user_to_return)
|
self.assertEqual(user, user_to_return)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
jenkins_mock.call_args[0][0].url,
|
jenkins_mock.call_args[0][0].url,
|
||||||
self.make_url('me/api/json'))
|
self.make_url('me/api/json?depth=0'))
|
||||||
self._check_requests(jenkins_mock.call_args_list)
|
self._check_requests(jenkins_mock.call_args_list)
|
||||||
|
|
||||||
@patch('jenkins.requests.Session.send', autospec=True)
|
@patch('jenkins.requests.Session.send', autospec=True)
|
||||||
@ -45,4 +45,4 @@ class JenkinsWhoamiTest(JenkinsTestBase):
|
|||||||
self.j.get_whoami()
|
self.j.get_whoami()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
session_send_mock.call_args_list[1][0][1].url,
|
session_send_mock.call_args_list[1][0][1].url,
|
||||||
self.make_url('me/api/json'))
|
self.make_url('me/api/json?depth=0'))
|
||||||
|
Loading…
Reference in New Issue
Block a user