diff --git a/jenkins/__init__.py b/jenkins/__init__.py
index 4aea85b..dd98dcb 100644
--- a/jenkins/__init__.py
+++ b/jenkins/__init__.py
@@ -128,6 +128,11 @@ class JenkinsException(Exception):
pass
+class NotFoundException(JenkinsException):
+ '''A special exception to call out the case of receiving a 404.'''
+ pass
+
+
def auth_headers(username, password):
'''Simple implementation of HTTP Basic Authentication.
@@ -169,13 +174,14 @@ class Jenkins(object):
def maybe_add_crumb(self, req):
# We don't know yet whether we need a crumb
if self.crumb is None:
- response = self.jenkins_open(Request(
- self.server + CRUMB_URL), add_crumb=False)
- if response:
- self.crumb = json.loads(response.decode('utf-8'))
- else:
+ try:
+ response = self.jenkins_open(Request(
+ self.server + CRUMB_URL), add_crumb=False)
+ except NotFoundException:
# Don't need crumbs
self.crumb = False
+ else:
+ self.crumb = json.loads(response.decode('utf-8'))
if self.crumb:
req.add_header(self.crumb['crumbRequestField'], self.crumb['crumb'])
@@ -209,17 +215,19 @@ class Jenkins(object):
:param name: Job name, ``str``
:returns: Name of job or None
'''
- response = self.jenkins_open(
- Request(self.server + JOB_NAME % self._get_encoded_params(locals())))
- if response:
+ try:
+ response = self.jenkins_open(
+ Request(self.server + JOB_NAME %
+ self._get_encoded_params(locals())))
+ except NotFoundException:
+ return None
+ else:
actual = json.loads(response)['name']
if actual != name:
raise JenkinsException(
'Jenkins returned an unexpected job name %s '
'(expected: %s)' % (actual, name))
return actual
- else:
- return None
def debug_job_info(self, job_name):
'''Print out job info in more readable format.'''
@@ -250,6 +258,8 @@ class Jenkins(object):
'Possibly authentication failed [%s]: %s' % (
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
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
# https://issues.jenkins-ci.org/browse/JENKINS-21311
- self.jenkins_open(
- Request(self.server + CANCEL_QUEUE % locals(), '',
- headers={'Referer': self.server}))
+ try:
+ self.jenkins_open(
+ 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):
"""Get information on this Master.
diff --git a/tests/test_jenkins.py b/tests/test_jenkins.py
index afe6f53..e7aec31 100644
--- a/tests/test_jenkins.py
+++ b/tests/test_jenkins.py
@@ -88,7 +88,7 @@ class JenkinsTest(unittest.TestCase):
@patch('jenkins.urlopen')
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')
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(),
'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')
def test_assert_job_exists__job_missing(self, jenkins_mock):
- jenkins_mock.side_effect = [
- None,
- ]
+ jenkins_mock.side_effect = jenkins.NotFoundException()
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
with self.assertRaises(jenkins.JenkinsException) as context_manager:
@@ -191,7 +209,7 @@ class JenkinsTest(unittest.TestCase):
Foo
"""
jenkins_mock.side_effect = [
- None,
+ jenkins.NotFoundException(),
None,
json.dumps({'name': 'Test Job'}),
]
@@ -233,9 +251,9 @@ class JenkinsTest(unittest.TestCase):
Foo
"""
jenkins_mock.side_effect = [
+ jenkins.NotFoundException(),
None,
- None,
- None,
+ jenkins.NotFoundException(),
]
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
@@ -317,7 +335,7 @@ class JenkinsTest(unittest.TestCase):
@patch.object(jenkins.Jenkins, 'jenkins_open')
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')
with self.assertRaises(jenkins.JenkinsException) as context_manager:
@@ -833,8 +851,7 @@ class JenkinsTest(unittest.TestCase):
jenkins_mock.side_effect = [
json.dumps({'name': 'TestJob'}),
None,
- None,
- None,
+ jenkins.NotFoundException(),
]
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
@@ -870,8 +887,7 @@ class JenkinsTest(unittest.TestCase):
jenkins_mock.side_effect = [
json.dumps({'name': 'TestJob'}),
None,
- None,
- None,
+ jenkins.NotFoundException(),
]
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
@@ -889,8 +905,7 @@ class JenkinsTest(unittest.TestCase):
jenkins_mock.side_effect = [
json.dumps({'name': 'Test Job'}),
None,
- None,
- None,
+ jenkins.NotFoundException(),
]
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
@@ -899,7 +914,6 @@ class JenkinsTest(unittest.TestCase):
self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(),
'http://example.com/job/Test%20Job/doDelete')
- self.assertFalse(j.job_exists('Test Job'))
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_delete_job__delete_failed(self, jenkins_mock):
@@ -967,7 +981,7 @@ class JenkinsTest(unittest.TestCase):
@patch.object(jenkins.Jenkins, 'jenkins_open')
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')
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(),
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')
def test_get_node_info(self, jenkins_mock):
node_info = {