diff --git a/jenkins/__init__.py b/jenkins/__init__.py index b1ec039..716208a 100755 --- a/jenkins/__init__.py +++ b/jenkins/__init__.py @@ -530,6 +530,7 @@ class Jenkins(object): headers = response.headers if (headers.get('content-length') is None and headers.get('transfer-encoding') is None and + headers.get('location') is None and (response.content is None or len(response.content) <= 0)): # response body should only exist if one of these is provided raise EmptyResponseException( @@ -1291,6 +1292,12 @@ class Jenkins(object): ''' response = self.jenkins_request(requests.Request( 'POST', self.build_job_url(name, parameters, token))) + + if 'Location' not in response.headers: + raise EmptyResponseException( + "Header 'Location' not found in " + "response from server[%s]" % self.server) + location = response.headers['Location'] # location is a queue item, eg. "http://jenkins/queue/item/25/" if location.endswith('/'): diff --git a/tests/helper.py b/tests/helper.py index 882ca83..f6f57cc 100644 --- a/tests/helper.py +++ b/tests/helper.py @@ -78,14 +78,15 @@ class NullServer(socketserver.TCPServer): *args, **kwargs) -def build_response_mock(status_code, json_body=None, headers=None, **kwargs): +def build_response_mock(status_code, json_body=None, headers=None, + add_content_length=True, **kwargs): real_response = requests.Response() real_response.status_code = status_code text = None if json_body is not None: text = json.dumps(json_body) - if headers is not {}: + if add_content_length and headers is not {}: real_response.headers['content-length'] = len(text) if headers is not None: diff --git a/tests/jobs/test_build.py b/tests/jobs/test_build.py index 7fac8e4..611925a 100644 --- a/tests/jobs/test_build.py +++ b/tests/jobs/test_build.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from mock import patch +import jenkins from six.moves.urllib.parse import quote from tests.helper import build_response_mock from tests.jobs.base import JenkinsJobsTestBase @@ -19,6 +20,49 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase): self.make_url(quote(u'job/Test Jøb/build'.encode('utf8')))) self.assertEqual(queue_id, 25) + @patch('jenkins.requests.Session.send', autospec=True) + def test_assert_no_location(self, session_send_mock): + session_send_mock.return_value = build_response_mock(302, {}) + + with self.assertRaises(jenkins.EmptyResponseException) as context_mgr: + self.j.build_job(u'Test Job') + + self.assertEqual( + str(context_mgr.exception), + "Header 'Location' not found in response from server[{0}]".format( + self.make_url(''))) + + @patch.object(jenkins.Jenkins, 'maybe_add_crumb') + @patch('jenkins.requests.Session.send', autospec=True) + def test_simple_no_content_lenght(self, session_send_mock, + maybe_add_crumb_mock): + maybe_add_crumb_mock.return_value = None + session_send_mock.return_value = build_response_mock( + 201, None, add_content_length=False, + headers={'Location': self.make_url('/queue/item/25/')}) + + queue_id = self.j.build_job(u'Test Job') + + self.assertEqual(session_send_mock.call_args[0][1].url, + self.make_url('job/Test%20Job/build')) + self.assertEqual(queue_id, 25) + + @patch.object(jenkins.Jenkins, 'maybe_add_crumb') + @patch('jenkins.requests.Session.send', autospec=True) + def test_assert_no_content_lenght_no_location(self, session_send_mock, + maybe_add_crumb_mock): + maybe_add_crumb_mock.return_value = None + session_send_mock.return_value = build_response_mock( + 201, None, add_content_length=False) + + with self.assertRaises(jenkins.EmptyResponseException) as context_mgr: + self.j.build_job(u'Test Job') + + self.assertEqual( + str(context_mgr.exception), + 'Error communicating with server[{0}]: empty response'.format( + self.make_url(''))) + @patch('jenkins.requests.Session.send', autospec=True) def test_in_folder(self, session_send_mock): session_send_mock.return_value = build_response_mock(