Merge "Raise an exception on 404"
This commit is contained in:
@@ -128,6 +128,11 @@ class JenkinsException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NotFoundException(JenkinsException):
|
||||||
|
'''A special exception to call out the case of receiving a 404.'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def auth_headers(username, password):
|
def auth_headers(username, password):
|
||||||
'''Simple implementation of HTTP Basic Authentication.
|
'''Simple implementation of HTTP Basic Authentication.
|
||||||
|
|
||||||
@@ -169,13 +174,14 @@ class Jenkins(object):
|
|||||||
def maybe_add_crumb(self, req):
|
def maybe_add_crumb(self, req):
|
||||||
# We don't know yet whether we need a crumb
|
# We don't know yet whether we need a crumb
|
||||||
if self.crumb is None:
|
if self.crumb is None:
|
||||||
response = self.jenkins_open(Request(
|
try:
|
||||||
self.server + CRUMB_URL), add_crumb=False)
|
response = self.jenkins_open(Request(
|
||||||
if response:
|
self.server + CRUMB_URL), add_crumb=False)
|
||||||
self.crumb = json.loads(response.decode('utf-8'))
|
except NotFoundException:
|
||||||
else:
|
|
||||||
# Don't need crumbs
|
# Don't need crumbs
|
||||||
self.crumb = False
|
self.crumb = False
|
||||||
|
else:
|
||||||
|
self.crumb = json.loads(response.decode('utf-8'))
|
||||||
if self.crumb:
|
if self.crumb:
|
||||||
req.add_header(self.crumb['crumbRequestField'], self.crumb['crumb'])
|
req.add_header(self.crumb['crumbRequestField'], self.crumb['crumb'])
|
||||||
|
|
||||||
@@ -209,17 +215,19 @@ class Jenkins(object):
|
|||||||
:param name: Job name, ``str``
|
:param name: Job name, ``str``
|
||||||
:returns: Name of job or None
|
:returns: Name of job or None
|
||||||
'''
|
'''
|
||||||
response = self.jenkins_open(
|
try:
|
||||||
Request(self.server + JOB_NAME % self._get_encoded_params(locals())))
|
response = self.jenkins_open(
|
||||||
if response:
|
Request(self.server + JOB_NAME %
|
||||||
|
self._get_encoded_params(locals())))
|
||||||
|
except NotFoundException:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
actual = json.loads(response)['name']
|
actual = json.loads(response)['name']
|
||||||
if actual != name:
|
if actual != name:
|
||||||
raise JenkinsException(
|
raise JenkinsException(
|
||||||
'Jenkins returned an unexpected job name %s '
|
'Jenkins returned an unexpected job name %s '
|
||||||
'(expected: %s)' % (actual, name))
|
'(expected: %s)' % (actual, name))
|
||||||
return actual
|
return actual
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def debug_job_info(self, job_name):
|
def debug_job_info(self, job_name):
|
||||||
'''Print out job info in more readable format.'''
|
'''Print out job info in more readable format.'''
|
||||||
@@ -250,6 +258,8 @@ class Jenkins(object):
|
|||||||
'Possibly authentication failed [%s]: %s' % (
|
'Possibly authentication failed [%s]: %s' % (
|
||||||
e.code, e.msg)
|
e.code, e.msg)
|
||||||
)
|
)
|
||||||
|
elif e.code == 404:
|
||||||
|
raise NotFoundException('Requested item could not be found')
|
||||||
# right now I'm getting 302 infinites on a successful delete
|
# right now I'm getting 302 infinites on a successful delete
|
||||||
|
|
||||||
def get_build_info(self, name, number, depth=0):
|
def get_build_info(self, name, number, depth=0):
|
||||||
@@ -307,9 +317,14 @@ class Jenkins(object):
|
|||||||
'''
|
'''
|
||||||
# Jenkins seems to always return a 404 when using this REST endpoint
|
# Jenkins seems to always return a 404 when using this REST endpoint
|
||||||
# https://issues.jenkins-ci.org/browse/JENKINS-21311
|
# https://issues.jenkins-ci.org/browse/JENKINS-21311
|
||||||
self.jenkins_open(
|
try:
|
||||||
Request(self.server + CANCEL_QUEUE % locals(), '',
|
self.jenkins_open(
|
||||||
headers={'Referer': self.server}))
|
Request(self.server + CANCEL_QUEUE % locals(), '',
|
||||||
|
headers={'Referer': self.server}))
|
||||||
|
except NotFoundException:
|
||||||
|
# Exception is expected; cancel_queue() is a best-effort
|
||||||
|
# mechanism, so ignore it
|
||||||
|
pass
|
||||||
|
|
||||||
def get_info(self):
|
def get_info(self):
|
||||||
"""Get information on this Master.
|
"""Get information on this Master.
|
||||||
|
@@ -88,7 +88,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
|
|
||||||
@patch('jenkins.urlopen')
|
@patch('jenkins.urlopen')
|
||||||
def test_maybe_add_crumb(self, jenkins_mock):
|
def test_maybe_add_crumb(self, jenkins_mock):
|
||||||
jenkins_mock.return_value = get_mock_urlopen_return_value()
|
jenkins_mock.side_effect = jenkins.NotFoundException()
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
request = jenkins.Request('http://example.com/job/TestJob')
|
request = jenkins.Request('http://example.com/job/TestJob')
|
||||||
|
|
||||||
@@ -162,11 +162,29 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
jenkins_mock.call_args[0][0].get_full_url(),
|
jenkins_mock.call_args[0][0].get_full_url(),
|
||||||
'http://example.com/job/TestJob')
|
'http://example.com/job/TestJob')
|
||||||
|
|
||||||
|
@patch('jenkins.urlopen')
|
||||||
|
def test_jenkins_open__404(self, jenkins_mock):
|
||||||
|
jenkins_mock.side_effect = jenkins.HTTPError(
|
||||||
|
'http://example.com/job/TestJob',
|
||||||
|
code=404,
|
||||||
|
msg="basic auth failed",
|
||||||
|
hdrs=[],
|
||||||
|
fp=None)
|
||||||
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
request = jenkins.Request('http://example.com/job/TestJob')
|
||||||
|
|
||||||
|
with self.assertRaises(jenkins.NotFoundException) as context_manager:
|
||||||
|
j.jenkins_open(request, add_crumb=False)
|
||||||
|
self.assertEqual(
|
||||||
|
str(context_manager.exception),
|
||||||
|
'Requested item could not be found')
|
||||||
|
self.assertEqual(
|
||||||
|
jenkins_mock.call_args[0][0].get_full_url(),
|
||||||
|
'http://example.com/job/TestJob')
|
||||||
|
|
||||||
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
||||||
def test_assert_job_exists__job_missing(self, jenkins_mock):
|
def test_assert_job_exists__job_missing(self, jenkins_mock):
|
||||||
jenkins_mock.side_effect = [
|
jenkins_mock.side_effect = jenkins.NotFoundException()
|
||||||
None,
|
|
||||||
]
|
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
with self.assertRaises(jenkins.JenkinsException) as context_manager:
|
with self.assertRaises(jenkins.JenkinsException) as context_manager:
|
||||||
@@ -191,7 +209,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
<description>Foo</description>
|
<description>Foo</description>
|
||||||
</matrix-project>"""
|
</matrix-project>"""
|
||||||
jenkins_mock.side_effect = [
|
jenkins_mock.side_effect = [
|
||||||
None,
|
jenkins.NotFoundException(),
|
||||||
None,
|
None,
|
||||||
json.dumps({'name': 'Test Job'}),
|
json.dumps({'name': 'Test Job'}),
|
||||||
]
|
]
|
||||||
@@ -233,9 +251,9 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
<description>Foo</description>
|
<description>Foo</description>
|
||||||
</matrix-project>"""
|
</matrix-project>"""
|
||||||
jenkins_mock.side_effect = [
|
jenkins_mock.side_effect = [
|
||||||
|
jenkins.NotFoundException(),
|
||||||
None,
|
None,
|
||||||
None,
|
jenkins.NotFoundException(),
|
||||||
None,
|
|
||||||
]
|
]
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
@@ -317,7 +335,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
|
|
||||||
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
||||||
def test_build_job__job_doesnt_exist(self, jenkins_mock):
|
def test_build_job__job_doesnt_exist(self, jenkins_mock):
|
||||||
jenkins_mock.side_effect = [None]
|
jenkins_mock.side_effect = jenkins.NotFoundException()
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
with self.assertRaises(jenkins.JenkinsException) as context_manager:
|
with self.assertRaises(jenkins.JenkinsException) as context_manager:
|
||||||
@@ -833,8 +851,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
jenkins_mock.side_effect = [
|
jenkins_mock.side_effect = [
|
||||||
json.dumps({'name': 'TestJob'}),
|
json.dumps({'name': 'TestJob'}),
|
||||||
None,
|
None,
|
||||||
None,
|
jenkins.NotFoundException(),
|
||||||
None,
|
|
||||||
]
|
]
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
@@ -870,8 +887,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
jenkins_mock.side_effect = [
|
jenkins_mock.side_effect = [
|
||||||
json.dumps({'name': 'TestJob'}),
|
json.dumps({'name': 'TestJob'}),
|
||||||
None,
|
None,
|
||||||
None,
|
jenkins.NotFoundException(),
|
||||||
None,
|
|
||||||
]
|
]
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
@@ -889,8 +905,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
jenkins_mock.side_effect = [
|
jenkins_mock.side_effect = [
|
||||||
json.dumps({'name': 'Test Job'}),
|
json.dumps({'name': 'Test Job'}),
|
||||||
None,
|
None,
|
||||||
None,
|
jenkins.NotFoundException(),
|
||||||
None,
|
|
||||||
]
|
]
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
@@ -899,7 +914,6 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
jenkins_mock.call_args_list[1][0][0].get_full_url(),
|
jenkins_mock.call_args_list[1][0][0].get_full_url(),
|
||||||
'http://example.com/job/Test%20Job/doDelete')
|
'http://example.com/job/Test%20Job/doDelete')
|
||||||
self.assertFalse(j.job_exists('Test Job'))
|
|
||||||
|
|
||||||
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
||||||
def test_delete_job__delete_failed(self, jenkins_mock):
|
def test_delete_job__delete_failed(self, jenkins_mock):
|
||||||
@@ -967,7 +981,7 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
|
|
||||||
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
||||||
def test_get_job_name__None(self, jenkins_mock):
|
def test_get_job_name__None(self, jenkins_mock):
|
||||||
jenkins_mock.return_value = None
|
jenkins_mock.side_effect = jenkins.NotFoundException()
|
||||||
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
job_name = j.get_job_name(u'TestJob')
|
job_name = j.get_job_name(u'TestJob')
|
||||||
@@ -1005,6 +1019,19 @@ class JenkinsTest(unittest.TestCase):
|
|||||||
jenkins_mock.call_args[0][0].get_full_url(),
|
jenkins_mock.call_args[0][0].get_full_url(),
|
||||||
u'http://example.com/queue/cancelItem?id=52')
|
u'http://example.com/queue/cancelItem?id=52')
|
||||||
|
|
||||||
|
@patch.object(jenkins.Jenkins, 'jenkins_open',
|
||||||
|
side_effect=jenkins.NotFoundException('not found'))
|
||||||
|
def test_cancel_queue__notfound(self, jenkins_mock):
|
||||||
|
job_name_to_return = {u'name': 'TestJob'}
|
||||||
|
jenkins_mock.return_value = json.dumps(job_name_to_return)
|
||||||
|
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
|
||||||
|
|
||||||
|
j.cancel_queue(52)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
jenkins_mock.call_args[0][0].get_full_url(),
|
||||||
|
u'http://example.com/queue/cancelItem?id=52')
|
||||||
|
|
||||||
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
@patch.object(jenkins.Jenkins, 'jenkins_open')
|
||||||
def test_get_node_info(self, jenkins_mock):
|
def test_get_node_info(self, jenkins_mock):
|
||||||
node_info = {
|
node_info = {
|
||||||
|
Reference in New Issue
Block a user