Merge "Migration to using requests"

This commit is contained in:
Zuul 2018-04-04 20:40:17 +00:00 committed by Gerrit Code Review
commit 7166e97eb2
34 changed files with 648 additions and 833 deletions

View File

@ -46,7 +46,6 @@
See examples at :doc:`examples` See examples at :doc:`examples`
''' '''
import base64
import json import json
import re import re
import socket import socket
@ -55,24 +54,18 @@ import time
import warnings import warnings
import multi_key_dict import multi_key_dict
import six import requests
import requests.exceptions as req_exc
from six.moves.http_client import BadStatusLine from six.moves.http_client import BadStatusLine
from six.moves.urllib.error import HTTPError
from six.moves.urllib.error import URLError from six.moves.urllib.error import URLError
from six.moves.urllib.parse import quote, urlencode, urljoin, urlparse from six.moves.urllib.parse import quote, urlencode, urljoin, urlparse
from six.moves.urllib.request import Request, install_opener, build_opener, urlopen
from jenkins import plugins from jenkins import plugins
try: try:
import kerberos import requests_kerberos
assert kerberos # pyflakes
from jenkins import urllib_kerb
opener = build_opener()
opener.add_handler(urllib_kerb.HTTPNegotiateHandler())
install_opener(opener)
except ImportError: except ImportError:
pass requests_kerberos = None
if sys.version_info < (2, 7, 0): if sys.version_info < (2, 7, 0):
@ -240,17 +233,6 @@ class TimeoutException(JenkinsException):
'''A special exception to call out in the case of a socket timeout.''' '''A special exception to call out in the case of a socket timeout.'''
def auth_headers(username, password):
'''Simple implementation of HTTP Basic Authentication.
Returns the 'Authentication' header value.
'''
auth = '%s:%s' % (username, password)
if isinstance(auth, six.text_type):
auth = auth.encode('utf-8')
return b'Basic ' + base64.b64encode(auth)
class Jenkins(object): class Jenkins(object):
_timeout_warning_issued = False _timeout_warning_issued = False
@ -269,12 +251,25 @@ class Jenkins(object):
self.server = url self.server = url
else: else:
self.server = url + '/' self.server = url + '/'
self._auths = [('anonymous', None)]
self._auth_resolved = False
if username is not None and password is not None: if username is not None and password is not None:
self.auth = auth_headers(username, password) self._auths[0] = (
else: 'basic',
requests.auth.HTTPBasicAuth(
username.encode('utf-8'), password.encode('utf-8'))
)
if requests_kerberos is not None:
self._auths.append(
('kerberos', requests_kerberos.HTTPKerberosAuth())
)
self.auth = None self.auth = None
self.crumb = None self.crumb = None
self.timeout = timeout self.timeout = timeout
self._session = requests.Session()
def _get_encoded_params(self, params): def _get_encoded_params(self, params):
for k, v in params.items(): for k, v in params.items():
@ -296,14 +291,48 @@ class Jenkins(object):
# 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:
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(CRUMB_URL)), add_crumb=False) 'GET', self._build_url(CRUMB_URL)), add_crumb=False)
except (NotFoundException, EmptyResponseException): except (NotFoundException, EmptyResponseException):
self.crumb = False self.crumb = False
else: else:
self.crumb = json.loads(response) self.crumb = json.loads(response)
if self.crumb: if self.crumb:
req.add_header(self.crumb['crumbRequestField'], self.crumb['crumb']) req.headers[self.crumb['crumbRequestField']] = self.crumb['crumb']
def _maybe_add_auth(self):
if self._auth_resolved:
return
if len(self._auths) == 1:
# If we only have one auth mechanism specified, just require it
self._session.auth = self._auths[0][1]
else:
# Attempt the list of auth mechanisms and keep the first that works
# otherwise default to the first one in the list (last popped).
# This is a hack to allow the transparent use of kerberos to work
# in future, we should require explicit request to use kerberos
failures = []
for name, auth in reversed(self._auths):
try:
self.jenkins_open(
requests.Request('GET', self._build_url(INFO),
auth=auth),
add_crumb=False, resolve_auth=False)
self._session.auth = auth
break
except Exception as exc:
# assume authentication failure
failures.append("auth(%s) %s" % (name, exc))
continue
else:
raise JenkinsException(
'Unable to authenticate with any scheme:\n%s'
% '\n'.join(failures))
self._auth_resolved = True
self.auth = self._session.auth
def _add_missing_builds(self, data): def _add_missing_builds(self, data):
"""Query Jenkins to get all builds of a job. """Query Jenkins to get all builds of a job.
@ -327,8 +356,9 @@ class Jenkins(object):
if all_builds_loaded: if all_builds_loaded:
return data return data
folder_url, short_name = self._get_job_folder(data["name"]) folder_url, short_name = self._get_job_folder(data["name"])
response = self.jenkins_open(Request(self._build_url(ALL_BUILDS, response = self.jenkins_open(requests.Request(
locals()))) 'GET', self._build_url(ALL_BUILDS, locals())
))
if response: if response:
data["builds"] = json.loads(response)["allBuilds"] data["builds"] = json.loads(response)["allBuilds"]
else: else:
@ -352,8 +382,8 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(JOB_INFO, locals()) 'GET', self._build_url(JOB_INFO, locals())
)) ))
if response: if response:
if fetch_all_builds: if fetch_all_builds:
@ -362,7 +392,7 @@ class Jenkins(object):
return json.loads(response) return json.loads(response)
else: else:
raise JenkinsException('job[%s] does not exist' % name) raise JenkinsException('job[%s] does not exist' % name)
except HTTPError: except (req_exc.HTTPError, NotFoundException):
raise JenkinsException('job[%s] does not exist' % name) raise JenkinsException('job[%s] does not exist' % name)
except ValueError: except ValueError:
raise JenkinsException( raise JenkinsException(
@ -397,8 +427,8 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(JOB_NAME, locals()) 'GET', self._build_url(JOB_NAME, locals())
)) ))
except NotFoundException: except NotFoundException:
return None return None
@ -415,40 +445,57 @@ class Jenkins(object):
for k, v in self.get_job_info(job_name).items(): for k, v in self.get_job_info(job_name).items():
print(k, v) print(k, v)
def jenkins_open(self, req, add_crumb=True): def _response_handler(self, response):
'''Handle response objects'''
# raise exceptions if occurred
response.raise_for_status()
headers = response.headers
if (headers.get('content-length') is None and
headers.get('transfer-encoding') is None):
# response body should only exist if one of these is provided
raise EmptyResponseException(
"Error communicating with server[%s]: "
"empty response" % self.server)
# Reponse objects will automatically return unicode encoded
# when accessing .text property
return response
def _request(self, req):
r = self._session.prepare_request(req)
return self._session.send(r, timeout=self.timeout)
def jenkins_open(self, req, add_crumb=True, resolve_auth=True):
'''Utility routine for opening an HTTP request to a Jenkins server. '''Utility routine for opening an HTTP request to a Jenkins server.
This should only be used to extends the :class:`Jenkins` API. This should only be used to extends the :class:`Jenkins` API.
''' '''
try: try:
if self.auth: if resolve_auth:
req.add_header('Authorization', self.auth) self._maybe_add_auth()
if add_crumb: if add_crumb:
self.maybe_add_crumb(req) self.maybe_add_crumb(req)
response = urlopen(req, timeout=self.timeout).read()
if response is None: return self._response_handler(
raise EmptyResponseException( self._request(req)).text
"Error communicating with server[%s]: "
"empty response" % self.server) except req_exc.HTTPError as e:
return response.decode('utf-8')
except HTTPError as e:
# Jenkins's funky authentication means its nigh impossible to # Jenkins's funky authentication means its nigh impossible to
# distinguish errors. # distinguish errors.
if e.code in [401, 403, 500]: if e.response.status_code in [401, 403, 500]:
# six.moves.urllib.error.HTTPError provides a 'reason'
# attribute for all python version except for ver 2.6
# Falling back to HTTPError.msg since it contains the
# same info as reason
raise JenkinsException( raise JenkinsException(
'Error in request. ' + 'Error in request. ' +
'Possibly authentication failed [%s]: %s' % ( 'Possibly authentication failed [%s]: %s' % (
e.code, e.msg) e.response.status_code, e.response.reason)
) )
elif e.code == 404: elif e.response.status_code == 404:
raise NotFoundException('Requested item could not be found') raise NotFoundException('Requested item could not be found')
else: else:
raise raise
except socket.timeout as e: except req_exc.Timeout as e:
raise TimeoutException('Error in request: %s' % (e)) raise TimeoutException('Error in request: %s' % (e))
except URLError as e: except URLError as e:
# python 2.6 compatibility to ensure same exception raised # python 2.6 compatibility to ensure same exception raised
@ -476,15 +523,15 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(BUILD_INFO, locals()) 'GET', self._build_url(BUILD_INFO, locals())
)) ))
if response: if response:
return json.loads(response) return json.loads(response)
else: else:
raise JenkinsException('job[%s] number[%d] does not exist' raise JenkinsException('job[%s] number[%d] does not exist'
% (name, number)) % (name, number))
except HTTPError: except (req_exc.HTTPError, NotFoundException):
raise JenkinsException('job[%s] number[%d] does not exist' raise JenkinsException('job[%s] number[%d] does not exist'
% (name, number)) % (name, number))
except ValueError: except ValueError:
@ -502,7 +549,7 @@ class Jenkins(object):
{u'task': {u'url': u'http://your_url/job/my_job/', u'color': u'aborted_anime', u'name': u'my_job'}, u'stuck': False, u'actions': [{u'causes': [{u'shortDescription': u'Started by timer'}]}], u'buildable': False, u'params': u'', u'buildableStartMilliseconds': 1315087293316, u'why': u'Build #2,532 is already in progress (ETA:10 min)', u'blocked': True} {u'task': {u'url': u'http://your_url/job/my_job/', u'color': u'aborted_anime', u'name': u'my_job'}, u'stuck': False, u'actions': [{u'causes': [{u'shortDescription': u'Started by timer'}]}], u'buildable': False, u'params': u'', u'buildableStartMilliseconds': 1315087293316, u'why': u'Build #2,532 is already in progress (ETA:10 min)', u'blocked': True}
''' '''
return json.loads(self.jenkins_open( return json.loads(self.jenkins_open(
Request(self._build_url(Q_INFO)) requests.Request('GET', self._build_url(Q_INFO))
))['items'] ))['items']
def cancel_queue(self, id): def cancel_queue(self, id):
@ -514,7 +561,8 @@ class Jenkins(object):
# https://issues.jenkins-ci.org/browse/JENKINS-21311 # https://issues.jenkins-ci.org/browse/JENKINS-21311
try: try:
self.jenkins_open( self.jenkins_open(
Request(self._build_url(CANCEL_QUEUE, locals()), b'', requests.Request(
'POST', self._build_url(CANCEL_QUEUE, locals()),
headers={'Referer': self.server})) headers={'Referer': self.server}))
except NotFoundException: except NotFoundException:
# Exception is expected; cancel_queue() is a best-effort # Exception is expected; cancel_queue() is a best-effort
@ -546,9 +594,9 @@ class Jenkins(object):
url += query url += query
try: try:
return json.loads(self.jenkins_open( return json.loads(self.jenkins_open(
Request(self._build_url(url)) requests.Request('GET', self._build_url(INFO))
)) ))
except (HTTPError, BadStatusLine): except (req_exc.HTTPError, BadStatusLine):
raise BadHTTPException("Error communicating with server[%s]" raise BadHTTPException("Error communicating with server[%s]"
% self.server) % self.server)
except ValueError: except ValueError:
@ -570,7 +618,9 @@ class Jenkins(object):
""" """
try: try:
response = self.jenkins_open(Request(self._build_url(WHOAMI_URL))) response = self.jenkins_open(requests.Request(
'GET', self._build_url(WHOAMI_URL)
))
if response is None: if response is None:
raise EmptyResponseException( raise EmptyResponseException(
"Error communicating with server[%s]: " "Error communicating with server[%s]: "
@ -578,7 +628,7 @@ class Jenkins(object):
return json.loads(response) return json.loads(response)
except (HTTPError, BadStatusLine): except (req_exc.HTTPError, BadStatusLine):
raise BadHTTPException("Error communicating with server[%s]" raise BadHTTPException("Error communicating with server[%s]"
% self.server) % self.server)
@ -595,21 +645,13 @@ class Jenkins(object):
""" """
try: try:
request = Request(self._build_url('')) request = requests.Request('GET', self._build_url(''))
request.add_header('X-Jenkins', '0.0') request.headers['X-Jenkins'] = '0.0'
response = urlopen(request, timeout=self.timeout) response = self._response_handler(self._request(request))
if response is None:
raise EmptyResponseException(
"Error communicating with server[%s]: "
"empty response" % self.server)
if six.PY2: return response.headers['X-Jenkins']
return response.info().getheader('X-Jenkins')
if six.PY3: except (req_exc.HTTPError, BadStatusLine):
return response.getheader('X-Jenkins')
except (HTTPError, BadStatusLine):
raise BadHTTPException("Error communicating with server[%s]" raise BadHTTPException("Error communicating with server[%s]"
% self.server) % self.server)
@ -711,8 +753,8 @@ class Jenkins(object):
try: try:
plugins_info_json = json.loads(self.jenkins_open( plugins_info_json = json.loads(self.jenkins_open(
Request(self._build_url(PLUGIN_INFO, locals())))) requests.Request('GET', self._build_url(PLUGIN_INFO, locals()))))
except (HTTPError, BadStatusLine): except (req_exc.HTTPError, BadStatusLine):
raise BadHTTPException("Error communicating with server[%s]" raise BadHTTPException("Error communicating with server[%s]"
% self.server) % self.server)
except ValueError: except ValueError:
@ -758,7 +800,7 @@ class Jenkins(object):
""" """
if view_name: if view_name:
return self._get_view_jobs(view_name=view_name) return self._get_view_jobs(name=view_name)
else: else:
return self.get_all_jobs(folder_depth=folder_depth) return self.get_all_jobs(folder_depth=folder_depth)
@ -848,8 +890,9 @@ class Jenkins(object):
raise JenkinsException('copy[%s to %s] failed, source and destination ' raise JenkinsException('copy[%s to %s] failed, source and destination '
'folder must be the same' % (from_name, to_name)) 'folder must be the same' % (from_name, to_name))
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(COPY_JOB, locals()), b'')) 'POST', self._build_url(COPY_JOB, locals())
))
self.assert_job_exists(to_name, 'create[%s] failed') self.assert_job_exists(to_name, 'create[%s] failed')
def rename_job(self, from_name, to_name): def rename_job(self, from_name, to_name):
@ -868,8 +911,9 @@ class Jenkins(object):
if from_folder_url != to_folder_url: if from_folder_url != to_folder_url:
raise JenkinsException('rename[%s to %s] failed, source and destination folder ' raise JenkinsException('rename[%s to %s] failed, source and destination folder '
'must be the same' % (from_name, to_name)) 'must be the same' % (from_name, to_name))
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(RENAME_JOB, locals()), b'')) 'POST', self._build_url(RENAME_JOB, locals())
))
self.assert_job_exists(to_name, 'rename[%s] failed') self.assert_job_exists(to_name, 'rename[%s] failed')
def delete_job(self, name): def delete_job(self, name):
@ -878,8 +922,9 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str`` :param name: Name of Jenkins job, ``str``
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(DELETE_JOB, locals()), b'')) 'POST', self._build_url(DELETE_JOB, locals())
))
if self.job_exists(name): if self.job_exists(name):
raise JenkinsException('delete[%s] failed' % (name)) raise JenkinsException('delete[%s] failed' % (name))
@ -889,8 +934,9 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str`` :param name: Name of Jenkins job, ``str``
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(ENABLE_JOB, locals()), b'')) 'POST', self._build_url(ENABLE_JOB, locals())
))
def disable_job(self, name): def disable_job(self, name):
'''Disable Jenkins job. '''Disable Jenkins job.
@ -900,8 +946,9 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str`` :param name: Name of Jenkins job, ``str``
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(DISABLE_JOB, locals()), b'')) 'POST', self._build_url(DISABLE_JOB, locals())
))
def set_next_build_number(self, name, number): def set_next_build_number(self, name, number):
'''Set a job's next build number. '''Set a job's next build number.
@ -924,9 +971,9 @@ class Jenkins(object):
>>> server.set_next_build_number('job_name', next_bn + 50) >>> server.set_next_build_number('job_name', next_bn + 50)
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
self.jenkins_open( self.jenkins_open(requests.Request(
Request(self._build_url(SET_JOB_BUILD_NUMBER, locals()), 'POST', self._build_url(SET_JOB_BUILD_NUMBER, locals()),
("nextBuildNumber=%d" % number).encode('utf-8'))) data=("nextBuildNumber=%d" % number).encode('utf-8')))
def job_exists(self, name): def job_exists(self, name):
'''Check whether a job exists '''Check whether a job exists
@ -984,9 +1031,11 @@ class Jenkins(object):
raise JenkinsException('job[%s] already exists' % (name)) raise JenkinsException('job[%s] already exists' % (name))
try: try:
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(CREATE_JOB, locals()), 'POST', self._build_url(CREATE_JOB, locals()),
config_xml.encode('utf-8'), DEFAULT_HEADERS)) data=config_xml.encode('utf-8'),
headers=DEFAULT_HEADERS
))
except NotFoundException: except NotFoundException:
raise JenkinsException('Cannot create job[%s] because folder ' raise JenkinsException('Cannot create job[%s] because folder '
'for the job does not exist' % (name)) 'for the job does not exist' % (name))
@ -999,7 +1048,7 @@ class Jenkins(object):
:returns: job configuration (XML format) :returns: job configuration (XML format)
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
request = Request(self._build_url(CONFIG_JOB, locals())) request = requests.Request('GET', self._build_url(CONFIG_JOB, locals()))
return self.jenkins_open(request) return self.jenkins_open(request)
def reconfig_job(self, name, config_xml): def reconfig_job(self, name, config_xml):
@ -1012,8 +1061,11 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
reconfig_url = self._build_url(CONFIG_JOB, locals()) reconfig_url = self._build_url(CONFIG_JOB, locals())
self.jenkins_open(Request(reconfig_url, config_xml.encode('utf-8'), self.jenkins_open(requests.Request(
DEFAULT_HEADERS)) 'POST', reconfig_url,
data=config_xml.encode('utf-8'),
headers=DEFAULT_HEADERS
))
def build_job_url(self, name, parameters=None, token=None): def build_job_url(self, name, parameters=None, token=None):
'''Get URL to trigger build job. '''Get URL to trigger build job.
@ -1044,8 +1096,8 @@ class Jenkins(object):
:param parameters: parameters for job, or ``None``, ``dict`` :param parameters: parameters for job, or ``None``, ``dict``
:param token: Jenkins API token :param token: Jenkins API token
''' '''
return self.jenkins_open(Request( return self.jenkins_open(requests.Request(
self.build_job_url(name, parameters, token), b'')) 'POST', self.build_job_url(name, parameters, token)))
def run_script(self, script): def run_script(self, script):
'''Execute a groovy script on the jenkins master. '''Execute a groovy script on the jenkins master.
@ -1061,8 +1113,10 @@ class Jenkins(object):
Plugin:mailer, Plugin:jquery, Plugin:antisamy-markup-formatter, Plugin:mailer, Plugin:jquery, Plugin:antisamy-markup-formatter,
Plugin:maven-plugin, Plugin:pam-auth]' Plugin:maven-plugin, Plugin:pam-auth]'
''' '''
return self.jenkins_open(Request(self._build_url(SCRIPT_TEXT), return self.jenkins_open(
"script=".encode('utf-8') + quote(script).encode('utf-8'))) requests.Request(
'POST', self._build_url(SCRIPT_TEXT),
data="script=".encode('utf-8') + quote(script).encode('utf-8')))
def install_plugin(self, name, include_dependencies=True): def install_plugin(self, name, include_dependencies=True):
'''Install a plugin and its dependencies from the Jenkins public '''Install a plugin and its dependencies from the Jenkins public
@ -1104,8 +1158,9 @@ class Jenkins(object):
:param number: Jenkins build number for the job, ``int`` :param number: Jenkins build number for the job, ``int``
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(STOP_BUILD, locals()), b'')) 'POST', self._build_url(STOP_BUILD, locals())
))
def get_running_builds(self): def get_running_builds(self):
'''Return list of running builds. '''Return list of running builds.
@ -1164,10 +1219,11 @@ class Jenkins(object):
:returns: List of nodes, ``[ { str: str, str: bool} ]`` :returns: List of nodes, ``[ { str: str, str: bool} ]``
''' '''
try: try:
nodes_data = json.loads(self.jenkins_open(Request(self._build_url(NODE_LIST)))) nodes_data = json.loads(self.jenkins_open(
requests.Request('GET', self._build_url(NODE_LIST))))
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 (HTTPError, BadStatusLine): except (req_exc.HTTPError, BadStatusLine):
raise BadHTTPException("Error communicating with server[%s]" raise BadHTTPException("Error communicating with server[%s]"
% self.server) % self.server)
except ValueError: except ValueError:
@ -1182,13 +1238,14 @@ class Jenkins(object):
:returns: Dictionary of node info, ``dict`` :returns: Dictionary of node info, ``dict``
''' '''
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(NODE_INFO, locals()))) 'GET', self._build_url(NODE_INFO, locals())
))
if response: if response:
return json.loads(response) return json.loads(response)
else: else:
raise JenkinsException('node[%s] does not exist' % name) raise JenkinsException('node[%s] does not exist' % name)
except HTTPError: except (req_exc.HTTPError, NotFoundException):
raise JenkinsException('node[%s] does not exist' % name) raise JenkinsException('node[%s] does not exist' % name)
except ValueError: except ValueError:
raise JenkinsException("Could not parse JSON info for node[%s]" raise JenkinsException("Could not parse JSON info for node[%s]"
@ -1224,8 +1281,9 @@ class Jenkins(object):
:param name: Name of Jenkins node, ``str`` :param name: Name of Jenkins node, ``str``
''' '''
self.get_node_info(name) self.get_node_info(name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(DELETE_NODE, locals()), b'')) 'POST', self._build_url(DELETE_NODE, locals())
))
if self.node_exists(name): if self.node_exists(name):
raise JenkinsException('delete[%s] failed' % (name)) raise JenkinsException('delete[%s] failed' % (name))
@ -1238,8 +1296,9 @@ class Jenkins(object):
info = self.get_node_info(name) info = self.get_node_info(name)
if info['offline']: if info['offline']:
return return
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(TOGGLE_OFFLINE, locals()), b'')) 'POST', self._build_url(TOGGLE_OFFLINE, locals())
))
def enable_node(self, name): def enable_node(self, name):
'''Enable a node '''Enable a node
@ -1250,8 +1309,9 @@ class Jenkins(object):
if not info['offline']: if not info['offline']:
return return
msg = '' msg = ''
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(TOGGLE_OFFLINE, locals()), b'')) 'POST', self._build_url(TOGGLE_OFFLINE, locals())
))
def create_node(self, name, numExecutors=2, nodeDescription=None, def create_node(self, name, numExecutors=2, nodeDescription=None,
remoteFS='/var/lib/jenkins', labels=None, exclusive=False, remoteFS='/var/lib/jenkins', labels=None, exclusive=False,
@ -1296,9 +1356,9 @@ class Jenkins(object):
'json': json.dumps(inner_params) 'json': json.dumps(inner_params)
} }
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(CREATE_NODE, locals()), 'POST', self._build_url(CREATE_NODE, locals()), data=params)
urlencode(params).encode('utf-8'))) )
self.assert_node_exists(name, 'create[%s] failed') self.assert_node_exists(name, 'create[%s] failed')
@ -1308,7 +1368,7 @@ class Jenkins(object):
:param name: Jenkins node name, ``str`` :param name: Jenkins node name, ``str``
''' '''
get_config_url = self._build_url(CONFIG_NODE, locals()) get_config_url = self._build_url(CONFIG_NODE, locals())
return self.jenkins_open(Request(get_config_url)) return self.jenkins_open(requests.Request('GET', get_config_url))
def reconfig_node(self, name, config_xml): def reconfig_node(self, name, config_xml):
'''Change the configuration for an existing node. '''Change the configuration for an existing node.
@ -1317,7 +1377,11 @@ class Jenkins(object):
:param config_xml: New XML configuration, ``str`` :param config_xml: New XML configuration, ``str``
''' '''
reconfig_url = self._build_url(CONFIG_NODE, locals()) reconfig_url = self._build_url(CONFIG_NODE, locals())
self.jenkins_open(Request(reconfig_url, config_xml.encode('utf-8'), DEFAULT_HEADERS)) self.jenkins_open(requests.Request(
'POST', reconfig_url,
data=config_xml.encode('utf-8'),
headers=DEFAULT_HEADERS
))
def get_build_console_output(self, name, number): def get_build_console_output(self, name, number):
'''Get build console text. '''Get build console text.
@ -1328,15 +1392,15 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(name) folder_url, short_name = self._get_job_folder(name)
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(BUILD_CONSOLE_OUTPUT, locals()) 'GET', self._build_url(BUILD_CONSOLE_OUTPUT, locals())
)) ))
if response: if response:
return response return response
else: else:
raise JenkinsException('job[%s] number[%d] does not exist' raise JenkinsException('job[%s] number[%d] does not exist'
% (name, number)) % (name, number))
except HTTPError: except (req_exc.HTTPError, NotFoundException):
raise JenkinsException('job[%s] number[%d] does not exist' raise JenkinsException('job[%s] number[%d] does not exist'
% (name, number)) % (name, number))
@ -1358,7 +1422,7 @@ class Jenkins(object):
return folder_url, short_name return folder_url, short_name
def _get_view_jobs(self, view_name): def _get_view_jobs(self, name):
'''Get list of jobs on the view specified. '''Get list of jobs on the view specified.
Each job is a dictionary with 'name', 'url', 'color' and 'fullname' Each job is a dictionary with 'name', 'url', 'color' and 'fullname'
@ -1374,18 +1438,18 @@ class Jenkins(object):
''' '''
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(VIEW_JOBS, {u'name': view_name}) 'GET', self._build_url(VIEW_JOBS, locals())
)) ))
if response: if response:
jobs = json.loads(response)['jobs'] jobs = json.loads(response)['jobs']
else: else:
raise JenkinsException('view[%s] does not exist' % view_name) raise JenkinsException('view[%s] does not exist' % name)
except HTTPError: except NotFoundException:
raise JenkinsException('view[%s] does not exist' % view_name) raise JenkinsException('view[%s] does not exist' % name)
except ValueError: except ValueError:
raise JenkinsException( raise JenkinsException(
'Could not parse JSON info for view[%s]' % view_name) 'Could not parse JSON info for view[%s]' % name)
for job_dict in jobs: for job_dict in jobs:
job_dict.update({u'fullname': job_dict[u'name']}) job_dict.update({u'fullname': job_dict[u'name']})
@ -1403,8 +1467,8 @@ class Jenkins(object):
:returns: Name of view or None :returns: Name of view or None
''' '''
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(VIEW_NAME, locals()))) 'GET', self._build_url(VIEW_NAME, locals())))
except NotFoundException: except NotFoundException:
return None return None
else: else:
@ -1425,7 +1489,7 @@ class Jenkins(object):
:throws: :class:`JenkinsException` whenever the view does not exist :throws: :class:`JenkinsException` whenever the view does not exist
''' '''
if not self.view_exists(name): if not self.view_exists(name):
raise JenkinsException(exception_message % name) raise NotFoundException(exception_message % name)
def view_exists(self, name): def view_exists(self, name):
'''Check whether a view exists '''Check whether a view exists
@ -1450,8 +1514,8 @@ class Jenkins(object):
:param name: Name of Jenkins view, ``str`` :param name: Name of Jenkins view, ``str``
''' '''
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(DELETE_VIEW, locals()), b'' 'POST', self._build_url(DELETE_VIEW, locals())
)) ))
if self.view_exists(name): if self.view_exists(name):
raise JenkinsException('delete[%s] failed' % (name)) raise JenkinsException('delete[%s] failed' % (name))
@ -1465,9 +1529,11 @@ class Jenkins(object):
if self.view_exists(name): if self.view_exists(name):
raise JenkinsException('view[%s] already exists' % (name)) raise JenkinsException('view[%s] already exists' % (name))
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(CREATE_VIEW, locals()), 'POST', self._build_url(CREATE_VIEW, locals()),
config_xml.encode('utf-8'), DEFAULT_HEADERS)) data=config_xml.encode('utf-8'),
headers=DEFAULT_HEADERS
))
self.assert_view_exists(name, 'create[%s] failed') self.assert_view_exists(name, 'create[%s] failed')
def reconfig_view(self, name, config_xml): def reconfig_view(self, name, config_xml):
@ -1479,8 +1545,11 @@ class Jenkins(object):
:param config_xml: New XML configuration, ``str`` :param config_xml: New XML configuration, ``str``
''' '''
reconfig_url = self._build_url(CONFIG_VIEW, locals()) reconfig_url = self._build_url(CONFIG_VIEW, locals())
self.jenkins_open(Request(reconfig_url, config_xml.encode('utf-8'), self.jenkins_open(requests.Request(
DEFAULT_HEADERS)) 'POST', reconfig_url,
data=config_xml.encode('utf-8'),
headers=DEFAULT_HEADERS
))
def get_view_config(self, name): def get_view_config(self, name):
'''Get configuration of existing Jenkins view. '''Get configuration of existing Jenkins view.
@ -1488,7 +1557,7 @@ class Jenkins(object):
:param name: Name of Jenkins view, ``str`` :param name: Name of Jenkins view, ``str``
:returns: view configuration (XML format) :returns: view configuration (XML format)
''' '''
request = Request(self._build_url(CONFIG_VIEW, locals())) request = requests.Request('GET', self._build_url(CONFIG_VIEW, locals()))
return self.jenkins_open(request) return self.jenkins_open(request)
def get_promotion_name(self, name, job_name): def get_promotion_name(self, name, job_name):
@ -1504,8 +1573,8 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(job_name) folder_url, short_name = self._get_job_folder(job_name)
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(PROMOTION_NAME, locals()))) 'GET', self._build_url(PROMOTION_NAME, locals())))
except NotFoundException: except NotFoundException:
return None return None
else: else:
@ -1549,13 +1618,13 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(job_name) folder_url, short_name = self._get_job_folder(job_name)
try: try:
response = self.jenkins_open(Request( response = self.jenkins_open(requests.Request(
self._build_url(PROMOTION_INFO, locals()))) 'GET', self._build_url(PROMOTION_INFO, locals())))
if response: if response:
return json.loads(response) return json.loads(response)
else: else:
raise JenkinsException('job[%s] does not exist' % job_name) raise JenkinsException('job[%s] does not exist' % job_name)
except HTTPError: except req_exc.HTTPError:
raise JenkinsException('job[%s] does not exist' % job_name) raise JenkinsException('job[%s] does not exist' % job_name)
except ValueError: except ValueError:
raise JenkinsException("Could not parse JSON info for " raise JenkinsException("Could not parse JSON info for "
@ -1578,8 +1647,8 @@ class Jenkins(object):
:param name: Name of Jenkins promotion, ``str`` :param name: Name of Jenkins promotion, ``str``
''' '''
folder_url, short_name = self._get_job_folder(job_name) folder_url, short_name = self._get_job_folder(job_name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(DELETE_PROMOTION, locals()), b'' 'POST', self._build_url(DELETE_PROMOTION, locals())
)) ))
if self.promotion_exists(name, job_name): if self.promotion_exists(name, job_name):
raise JenkinsException('delete[%s] from job[%s] failed' % raise JenkinsException('delete[%s] from job[%s] failed' %
@ -1597,9 +1666,9 @@ class Jenkins(object):
% (name, job_name)) % (name, job_name))
folder_url, short_name = self._get_job_folder(job_name) folder_url, short_name = self._get_job_folder(job_name)
self.jenkins_open(Request( self.jenkins_open(requests.Request(
self._build_url(CREATE_PROMOTION, locals()), 'POST', self._build_url(CREATE_PROMOTION, locals()),
config_xml.encode('utf-8'), DEFAULT_HEADERS)) data=config_xml.encode('utf-8'), headers=DEFAULT_HEADERS))
self.assert_promotion_exists(name, job_name, 'create[%s] at ' self.assert_promotion_exists(name, job_name, 'create[%s] at '
'job[%s] failed') 'job[%s] failed')
@ -1614,8 +1683,11 @@ class Jenkins(object):
''' '''
folder_url, short_name = self._get_job_folder(job_name) folder_url, short_name = self._get_job_folder(job_name)
reconfig_url = self._build_url(CONFIG_PROMOTION, locals()) reconfig_url = self._build_url(CONFIG_PROMOTION, locals())
self.jenkins_open(Request(reconfig_url, config_xml.encode('utf-8'), self.jenkins_open(requests.Request(
DEFAULT_HEADERS)) 'POST', reconfig_url,
data=config_xml.encode('utf-8'),
headers=DEFAULT_HEADERS
))
def get_promotion_config(self, name, job_name): def get_promotion_config(self, name, job_name):
'''Get configuration of existing Jenkins promotion. '''Get configuration of existing Jenkins promotion.
@ -1625,7 +1697,8 @@ class Jenkins(object):
:returns: promotion configuration (XML format) :returns: promotion configuration (XML format)
''' '''
folder_url, short_name = self._get_job_folder(job_name) folder_url, short_name = self._get_job_folder(job_name)
request = Request(self._build_url(CONFIG_PROMOTION, locals())) request = requests.Request(
'GET', self._build_url(CONFIG_PROMOTION, locals()))
return self.jenkins_open(request) return self.jenkins_open(request)
def quiet_down(self): def quiet_down(self):
@ -1634,7 +1707,7 @@ class Jenkins(object):
No new builds will be started allowing running builds to complete No new builds will be started allowing running builds to complete
prior to shutdown of the server. prior to shutdown of the server.
''' '''
request = Request(self._build_url(QUIET_DOWN)) request = requests.Request('POST', self._build_url(QUIET_DOWN))
self.jenkins_open(request) self.jenkins_open(request)
info = self.get_info() info = self.get_info()
if not info['quietingDown']: if not info['quietingDown']:

View File

@ -1,121 +0,0 @@
# Copyright (C) 2015 OpenStack Foundation
#
# 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.
import logging
import re
import kerberos
from six.moves.urllib import error, request
logger = logging.getLogger(__name__)
class HTTPNegotiateHandler(request.BaseHandler):
handler_order = 490 # before Digest auth
def __init__(self, max_tries=5):
self.krb_context = None
self.tries = 0
self.max_tries = max_tries
self.re_extract_auth = re.compile('.*?Negotiate\s*([^,]*)', re.I)
def http_error_401(self, req, fp, code, msg, headers):
logger.debug("INSIDE http_error_401")
try:
try:
krb_req = self._extract_krb_value(headers)
except ValueError:
# Negotiate header not found or a similar error
# we can't handle this, let the next handler have a go
return None
if not krb_req:
# First reply from server (no neg value)
self.tries = 0
krb_req = ""
else:
if self.tries > self.max_tries:
raise error.HTTPError(
req.get_full_url(), 401, "Negotiate auth failed",
headers, None)
self.tries += 1
try:
krb_resp = self._krb_response(req.host, krb_req)
req.add_unredirected_header('Authorization',
"Negotiate %s" % krb_resp)
resp = self.parent.open(req, timeout=req.timeout)
self._authenticate_server(resp.headers)
return resp
except kerberos.GSSError as err:
try:
msg = err.args[1][0]
except Exception:
msg = "Negotiate auth failed"
logger.debug(msg)
return None # let the next handler (if any) have a go
finally:
if self.krb_context is not None:
kerberos.authGSSClientClean(self.krb_context)
self.krb_context = None
def _krb_response(self, host, krb_val):
logger.debug("INSIDE _krb_response")
_dummy, self.krb_context = kerberos.authGSSClientInit("HTTP@%s" % host)
kerberos.authGSSClientStep(self.krb_context, krb_val)
response = kerberos.authGSSClientResponse(self.krb_context)
logger.debug("kerb auth successful")
return response
def _authenticate_server(self, headers):
logger.debug("INSIDE _authenticate_server")
try:
val = self._extract_krb_value(headers)
except ValueError:
logger.critical("Server authentication failed."
"Auth value couldn't be extracted from headers.")
return None
if not val:
logger.critical("Server authentication failed."
"Empty 'Negotiate' value.")
return None
kerberos.authGSSClientStep(self.krb_context, val)
def _extract_krb_value(self, headers):
logger.debug("INSIDE _extract_krb_value")
header = headers.get('www-authenticate', None)
if header is None:
msg = "www-authenticate header not found"
logger.debug(msg)
raise ValueError(msg)
if "negotiate" in header.lower():
matches = self.re_extract_auth.search(header)
if matches:
return matches.group(1)
else:
return ""
else:
msg = "Negotiate not in www-authenticate header (%s)" % header
logger.debug(msg)
raise ValueError(msg)

View File

@ -1,3 +1,4 @@
six>=1.3.0 six>=1.3.0
pbr>=0.8.2 pbr>=0.8.2
multi_key_dict multi_key_dict
requests

View File

@ -1,9 +1,10 @@
coverage>=3.6 coverage>=3.6
hacking>=0.5.6,<0.11 hacking>=0.5.6,<0.11
kerberos>=1.2.4
mock<1.1 mock<1.1
unittest2 unittest2
python-subunit python-subunit
requests-mock>=1.4.0
requests-kerberos
sphinx>=1.2,<1.3.0 sphinx>=1.2,<1.3.0
testrepository testrepository
testscenarios testscenarios

View File

@ -1,6 +1,5 @@
import sys import sys
from six.moves.urllib.request import build_opener
from testscenarios import TestWithScenarios from testscenarios import TestWithScenarios
import jenkins import jenkins
@ -25,7 +24,8 @@ class JenkinsTestBase(TestWithScenarios, unittest.TestCase):
def setUp(self): def setUp(self):
super(JenkinsTestBase, self).setUp() super(JenkinsTestBase, self).setUp()
self.opener = build_opener() # TODO(darragh) would be useful if this could be mocked
jenkins.requests_kerberos = None
self.j = jenkins.Jenkins(self.base_url, 'test', 'test') self.j = jenkins.Jenkins(self.base_url, 'test', 'test')
@ -35,17 +35,4 @@ class JenkinsTestBase(TestWithScenarios, unittest.TestCase):
def _check_requests(self, requests): def _check_requests(self, requests):
for req in requests: for req in requests:
self._check_request(req[0][0]) req[0][0].prepare()
def _check_request(self, request):
# taken from opener.open() in request
# attribute request.type is only set automatically for python 3
# requests, must use request.get_type() for python 2.7
protocol = request.type or request.get_type()
# check that building the request doesn't throw any exception
meth_name = protocol + "_request"
for processor in self.opener.process_request.get(protocol, []):
meth = getattr(processor, meth_name)
request = meth(request)

View File

@ -1,8 +1,11 @@
import functools import functools
import json
from multiprocessing import Process from multiprocessing import Process
from multiprocessing import Queue from multiprocessing import Queue
import traceback import traceback
from mock import Mock
import requests
from six.moves import socketserver from six.moves import socketserver
@ -73,3 +76,31 @@ class NullServer(socketserver.TCPServer):
socketserver.TCPServer.__init__( socketserver.TCPServer.__init__(
self, server_address, socketserver.BaseRequestHandler, self, server_address, socketserver.BaseRequestHandler,
*args, **kwargs) *args, **kwargs)
def build_response_mock(status_code, json_body=None, headers=None, **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 {}:
real_response.headers['content-length'] = len(text)
if headers is not None:
for k, v in headers.items():
real_response.headers[k] = v
for k, v in kwargs.items():
setattr(real_response, k, v)
response = Mock(wraps=real_response, autospec=True)
if text:
response.text = text
# for some reason, wraps cannot handle attributes which are dicts
# and accessed by key
response.headers = real_response.headers
return response

View File

@ -14,7 +14,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
build_info = self.j.build_job(u'Test Job') build_info = self.j.build_job(u'Test Job')
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/build')) self.make_url('job/Test%20Job/build'))
self.assertEqual(build_info, {'foo': 'bar'}) self.assertEqual(build_info, {'foo': 'bar'})
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -27,7 +27,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
build_info = self.j.build_job(u'a Folder/Test Job') build_info = self.j.build_job(u'a Folder/Test Job')
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/build')) self.make_url('job/a%20Folder/job/Test%20Job/build'))
self.assertEqual(build_info, {'foo': 'bar'}) self.assertEqual(build_info, {'foo': 'bar'})
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -40,7 +40,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
build_info = self.j.build_job(u'TestJob', token='some_token') build_info = self.j.build_job(u'TestJob', token='some_token')
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/TestJob/build?token=some_token')) self.make_url('job/TestJob/build?token=some_token'))
self.assertEqual(build_info, {'foo': 'bar'}) self.assertEqual(build_info, {'foo': 'bar'})
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -53,7 +53,7 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
build_info = self.j.build_job(u'a Folder/TestJob', token='some_token') build_info = self.j.build_job(u'a Folder/TestJob', token='some_token')
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/TestJob/build?token=some_token')) self.make_url('job/a%20Folder/job/TestJob/build?token=some_token'))
self.assertEqual(build_info, {'foo': 'bar'}) self.assertEqual(build_info, {'foo': 'bar'})
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -69,8 +69,8 @@ class JenkinsBuildJobTest(JenkinsJobsTestBase):
parameters={'when': 'now', 'why': 'because I felt like it'}, parameters={'when': 'now', 'why': 'because I felt like it'},
token='some_token') token='some_token')
self.assertTrue('token=some_token' in jenkins_mock.call_args[0][0].get_full_url()) self.assertTrue('token=some_token' in jenkins_mock.call_args[0][0].url)
self.assertTrue('when=now' in jenkins_mock.call_args[0][0].get_full_url()) self.assertTrue('when=now' in jenkins_mock.call_args[0][0].url)
self.assertTrue('why=because+I+felt+like+it' in jenkins_mock.call_args[0][0].get_full_url()) self.assertTrue('why=because+I+felt+like+it' in jenkins_mock.call_args[0][0].url)
self.assertEqual(build_info, {'foo': 'bar'}) self.assertEqual(build_info, {'foo': 'bar'})
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -11,7 +11,7 @@ class JenkinsGetJobConfigTest(JenkinsJobsTestBase):
self.j.get_job_config(u'Test Job') self.j.get_job_config(u'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/config.xml')) self.make_url('job/Test%20Job/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -20,6 +20,6 @@ class JenkinsGetJobConfigTest(JenkinsJobsTestBase):
self.j.get_job_config(u'a folder/Test Job') self.j.get_job_config(u'a folder/Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20folder/job/Test%20Job/config.xml')) self.make_url('job/a%20folder/job/Test%20Job/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -18,7 +18,7 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
self.j.copy_job(u'Test Job', u'Test Job_2') self.j.copy_job(u'Test Job', u'Test Job_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('createItem?name=Test%20Job_2&mode=copy&from=Test%20Job')) self.make_url('createItem?name=Test%20Job_2&mode=copy&from=Test%20Job'))
self.assertTrue(self.j.job_exists('Test Job_2')) self.assertTrue(self.j.job_exists('Test Job_2'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -34,7 +34,7 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
self.j.copy_job(u'a Folder/Test Job', u'a Folder/Test Job_2') self.j.copy_job(u'a Folder/Test Job', u'a Folder/Test Job_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/createItem?name=Test%20Job_2' self.make_url('job/a%20Folder/createItem?name=Test%20Job_2'
'&mode=copy&from=Test%20Job')) '&mode=copy&from=Test%20Job'))
self.assertTrue(self.j.job_exists('a Folder/Test Job_2')) self.assertTrue(self.j.job_exists('a Folder/Test Job_2'))
@ -50,7 +50,7 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.copy_job(u'TestJob', u'TestJob_2') self.j.copy_job(u'TestJob', u'TestJob_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('createItem?name=TestJob_2&mode=copy&from=TestJob')) self.make_url('createItem?name=TestJob_2&mode=copy&from=TestJob'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -67,7 +67,7 @@ class JenkinsCopyJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.copy_job(u'a Folder/TestJob', u'a Folder/TestJob_2') self.j.copy_job(u'a Folder/TestJob', u'a Folder/TestJob_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/createItem?name=TestJob_2&mode=copy' self.make_url('job/a%20Folder/createItem?name=TestJob_2&mode=copy'
'&from=TestJob')) '&from=TestJob'))
self.assertEqual( self.assertEqual(

View File

@ -18,7 +18,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
self.j.create_job(u'Test Job', self.config_xml) self.j.create_job(u'Test Job', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('createItem?name=Test%20Job')) self.make_url('createItem?name=Test%20Job'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -33,7 +33,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
self.j.create_job(u'a Folder/Test Job', self.config_xml) self.j.create_job(u'a Folder/Test Job', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('job/a%20Folder/createItem?name=Test%20Job')) self.make_url('job/a%20Folder/createItem?name=Test%20Job'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -47,7 +47,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_job(u'TestJob', self.config_xml) self.j.create_job(u'TestJob', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/api/json?tree=name')) self.make_url('job/TestJob/api/json?tree=name'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -64,7 +64,7 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_job(u'a Folder/TestJob', self.config_xml) self.j.create_job(u'a Folder/TestJob', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name')) self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -82,10 +82,10 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_job(u'TestJob', self.config_xml) self.j.create_job(u'TestJob', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/api/json?tree=name')) self.make_url('job/TestJob/api/json?tree=name'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('createItem?name=TestJob')) self.make_url('createItem?name=TestJob'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -103,10 +103,10 @@ class JenkinsCreateJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_job(u'a Folder/TestJob', self.config_xml) self.j.create_job(u'a Folder/TestJob', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name')) self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('job/a%20Folder/createItem?name=TestJob')) self.make_url('job/a%20Folder/createItem?name=TestJob'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),

View File

@ -20,7 +20,7 @@ class JenkinsDebugJobInfoTest(JenkinsJobsTestBase):
self.j.debug_job_info(u'Test Job') self.j.debug_job_info(u'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/api/json?depth=0')) self.make_url('job/Test%20Job/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -37,6 +37,6 @@ class JenkinsDebugJobInfoTest(JenkinsJobsTestBase):
self.j.debug_job_info(u'a Folder/Test Job') self.j.debug_job_info(u'a Folder/Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/api/json?depth=0')) self.make_url('job/a%20Folder/job/Test%20Job/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -17,7 +17,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
self.j.delete_job(u'Test Job') self.j.delete_job(u'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/Test%20Job/doDelete')) self.make_url('job/Test%20Job/doDelete'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -31,7 +31,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
self.j.delete_job(u'a Folder/Test Job') self.j.delete_job(u'a Folder/Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/doDelete')) self.make_url('job/a%20Folder/job/Test%20Job/doDelete'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -46,7 +46,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.delete_job(u'TestJob') self.j.delete_job(u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/doDelete')) self.make_url('job/TestJob/doDelete'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -64,7 +64,7 @@ class JenkinsDeleteJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.delete_job(u'a Folder/TestJob') self.j.delete_job(u'a Folder/TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/doDelete')) self.make_url('job/a%20Folder/job/TestJob/doDelete'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),

View File

@ -17,7 +17,7 @@ class JenkinsDisableJobTest(JenkinsJobsTestBase):
self.j.disable_job(u'Test Job') self.j.disable_job(u'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/Test%20Job/disable')) self.make_url('job/Test%20Job/disable'))
self.assertTrue(self.j.job_exists('Test Job')) self.assertTrue(self.j.job_exists('Test Job'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -32,7 +32,7 @@ class JenkinsDisableJobTest(JenkinsJobsTestBase):
self.j.disable_job(u'a Folder/Test Job') self.j.disable_job(u'a Folder/Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/disable')) self.make_url('job/a%20Folder/job/Test%20Job/disable'))
self.assertTrue(self.j.job_exists('a Folder/Test Job')) self.assertTrue(self.j.job_exists('a Folder/Test Job'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -17,7 +17,7 @@ class JenkinsEnableJobTest(JenkinsJobsTestBase):
self.j.enable_job(u'TestJob') self.j.enable_job(u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/enable')) self.make_url('job/TestJob/enable'))
self.assertTrue(self.j.job_exists('TestJob')) self.assertTrue(self.j.job_exists('TestJob'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -32,7 +32,7 @@ class JenkinsEnableJobTest(JenkinsJobsTestBase):
self.j.enable_job(u'a Folder/TestJob') self.j.enable_job(u'a Folder/TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/enable')) self.make_url('job/a%20Folder/job/TestJob/enable'))
self.assertTrue(self.j.job_exists('a Folder/TestJob')) self.assertTrue(self.j.job_exists('a Folder/TestJob'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -2,6 +2,7 @@ import json
from mock import patch from mock import patch
import jenkins import jenkins
from tests.helper import build_response_mock
from tests.jobs.base import build_jobs_list_responses from tests.jobs.base import build_jobs_list_responses
from tests.jobs.base import JenkinsGetJobsTestBase from tests.jobs.base import JenkinsGetJobsTestBase
@ -23,8 +24,8 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
jobs[u'fullname'] = jobs[u'name'] jobs[u'fullname'] = jobs[u'name']
self.assertEqual(job_info, [jobs]) self.assertEqual(job_info, [jobs])
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('api/json?tree=jobs[url,color,name,jobs]')) self.make_url('api/json'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
@ -79,7 +80,7 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
self.assertEqual(view_jobs[1][u'name'], u'community.first') self.assertEqual(view_jobs[1][u'name'], u'community.first')
self.assertEqual(view_jobs[1][u'name'], view_jobs[1][u'fullname']) self.assertEqual(view_jobs[1][u'name'], view_jobs[1][u'fullname'])
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url( self.make_url(
'view/Test%20View/api/json?tree=jobs[url,color,name]' 'view/Test%20View/api/json?tree=jobs[url,color,name]'
)) ))
@ -93,7 +94,7 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
self.j.get_jobs(view_name=u'Test View') self.j.get_jobs(view_name=u'Test View')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url( self.make_url(
'view/Test%20View/api/json?tree=jobs[url,color,name]' 'view/Test%20View/api/json?tree=jobs[url,color,name]'
)) ))
@ -110,7 +111,7 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
self.j.get_jobs(view_name=u'Test View') self.j.get_jobs(view_name=u'Test View')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url( self.make_url(
'view/Test%20View/api/json?tree=jobs[url,color,name]' 'view/Test%20View/api/json?tree=jobs[url,color,name]'
)) ))
@ -119,25 +120,21 @@ class JenkinsGetJobsTest(JenkinsGetJobsTestBase):
'Could not parse JSON info for view[Test View]') 'Could not parse JSON info for view[Test View]')
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_get_view_jobs_raise_HTTPError(self, jenkins_mock): def test_get_view_jobs_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url( build_response_mock(404, reason="Not Found"), # crumb
'view/Test%20View/api/json?tree=jobs[url,color,name]'), build_response_mock(404, reason="Not Found"), # request
code=401, ])
msg="basic auth failed",
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_jobs(view_name=u'Test View') self.j.get_jobs(view_name=u'Test View')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url( self.make_url(
'view/Test%20View/api/json?tree=jobs[url,color,name]' 'view/Test%20View/api/json?tree=jobs[url,color,name]'
)) ))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'view[Test View] does not exist') 'view[Test View] does not exist')
self._check_requests(jenkins_mock.call_args_list)

View File

@ -2,6 +2,7 @@ import json
from mock import patch from mock import patch
import jenkins import jenkins
from tests.helper import build_response_mock
from tests.jobs.base import JenkinsJobsTestBase from tests.jobs.base import JenkinsJobsTestBase
@ -21,7 +22,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
self.assertEqual(job_info, job_info_to_return) self.assertEqual(job_info, job_info_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/api/json?depth=0')) self.make_url('job/Test%20Job/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -48,10 +49,10 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
self.assertEqual(job_info, expected) self.assertEqual(job_info, expected)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/Test%20Job/api/json?depth=0')) self.make_url('job/Test%20Job/api/json?depth=0'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url( self.make_url(
'job/Test%20Job/api/json?tree=allBuilds[number,url]')) 'job/Test%20Job/api/json?tree=allBuilds[number,url]'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -70,7 +71,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
self.assertEqual(job_info, job_info_to_return) self.assertEqual(job_info, job_info_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/api/json?depth=0')) self.make_url('job/a%20Folder/job/Test%20Job/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -101,7 +102,7 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_job_info(u'TestJob') self.j.get_job_info(u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/TestJob/api/json?depth=0')) self.make_url('job/TestJob/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -115,47 +116,41 @@ class JenkinsGetJobInfoTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_job_info(u'TestJob') self.j.get_job_info(u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/TestJob/api/json?depth=0')) self.make_url('job/TestJob/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for job[TestJob]') 'Could not parse JSON info for job[TestJob]')
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/TestJob/api/json?depth=0'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(404, reason="Not Found"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_job_info(u'TestJob') self.j.get_job_info(u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url('job/TestJob/api/json?depth=0')) self.make_url('job/TestJob/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'job[TestJob] does not exist') 'job[TestJob] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_in_folder_raise_HTTPError(self, jenkins_mock): def test_in_folder_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(404, reason="Not Found"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_job_info(u'a Folder/TestJob') self.j.get_job_info(u'a Folder/TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0')) self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'job[a Folder/TestJob] does not exist') 'job[a Folder/TestJob] does not exist')
self._check_requests(jenkins_mock.call_args_list)

View File

@ -16,7 +16,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
self.assertEqual(job_name, 'Test Job') self.assertEqual(job_name, 'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/api/json?tree=name')) self.make_url('job/Test%20Job/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -29,7 +29,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
self.assertEqual(job_name, 'Test Job') self.assertEqual(job_name, 'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/api/json?tree=name')) self.make_url('job/a%20Folder/job/Test%20Job/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -41,7 +41,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
self.assertEqual(job_name, None) self.assertEqual(job_name, None)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/TestJob/api/json?tree=name')) self.make_url('job/TestJob/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -53,7 +53,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
self.assertEqual(job_name, None) self.assertEqual(job_name, None)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name')) self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -65,7 +65,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_job_name(u'TestJob') self.j.get_job_name(u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/api/json?tree=name')) self.make_url('job/TestJob/api/json?tree=name'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -81,7 +81,7 @@ class JenkinsGetJobNameTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_job_name(u'a Folder/TestJob') self.j.get_job_name(u'a Folder/TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name')) self.make_url('job/a%20Folder/job/TestJob/api/json?tree=name'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),

View File

@ -16,7 +16,7 @@ class JenkinsReconfigJobTest(JenkinsJobsTestBase):
self.j.reconfig_job(u'Test Job', self.config_xml) self.j.reconfig_job(u'Test Job', self.config_xml)
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/config.xml')) self.make_url('job/Test%20Job/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -29,6 +29,6 @@ class JenkinsReconfigJobTest(JenkinsJobsTestBase):
self.j.reconfig_job(u'a Folder/Test Job', self.config_xml) self.j.reconfig_job(u'a Folder/Test Job', self.config_xml)
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/config.xml')) self.make_url('job/a%20Folder/job/Test%20Job/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -18,7 +18,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
self.j.rename_job(u'Test Job', u'Test Job_2') self.j.rename_job(u'Test Job', u'Test Job_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/Test%20Job/doRename?newName=Test%20Job_2')) self.make_url('job/Test%20Job/doRename?newName=Test%20Job_2'))
self.assertTrue(self.j.job_exists('Test Job_2')) self.assertTrue(self.j.job_exists('Test Job_2'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -34,7 +34,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
self.j.rename_job(u'a Folder/Test Job', u'a Folder/Test Job_2') self.j.rename_job(u'a Folder/Test Job', u'a Folder/Test Job_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/doRename?newName=Test%20Job_2')) self.make_url('job/a%20Folder/job/Test%20Job/doRename?newName=Test%20Job_2'))
self.assertTrue(self.j.job_exists('Test Job_2')) self.assertTrue(self.j.job_exists('Test Job_2'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -49,7 +49,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.rename_job(u'TestJob', u'TestJob_2') self.j.rename_job(u'TestJob', u'TestJob_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/doRename?newName=TestJob_2')) self.make_url('job/TestJob/doRename?newName=TestJob_2'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -66,7 +66,7 @@ class JenkinsRenameJobTest(JenkinsJobsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.rename_job(u'a Folder/TestJob', u'a Folder/TestJob_2') self.j.rename_job(u'a Folder/TestJob', u'a Folder/TestJob_2')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/doRename?newName=TestJob_2')) self.make_url('job/a%20Folder/job/TestJob/doRename?newName=TestJob_2'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),

View File

@ -11,7 +11,7 @@ class JenkinsSetNextBuildNumberTest(JenkinsJobsTestBase):
self.j.set_next_build_number('TestJob', 1234) self.j.set_next_build_number('TestJob', 1234)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/TestJob/nextbuildnumber/submit')) self.make_url('job/TestJob/nextbuildnumber/submit'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].data, jenkins_mock.call_args[0][0].data,

View File

@ -3,6 +3,7 @@ from mock import patch
import jenkins import jenkins
from tests.base import JenkinsTestBase from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
class JenkinsBuildConsoleTest(JenkinsTestBase): class JenkinsBuildConsoleTest(JenkinsTestBase):
@ -15,7 +16,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
self.assertEqual(build_info, jenkins_mock.return_value) self.assertEqual(build_info, jenkins_mock.return_value)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/52/consoleText')) self.make_url('job/Test%20Job/52/consoleText'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -27,7 +28,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
self.assertEqual(build_info, jenkins_mock.return_value) self.assertEqual(build_info, jenkins_mock.return_value)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/52/consoleText')) self.make_url('job/a%20Folder/job/Test%20Job/52/consoleText'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -59,45 +60,38 @@ class JenkinsBuildConsoleTest(JenkinsTestBase):
console_output = self.j.get_build_console_output(u'TestJob', number=52) console_output = self.j.get_build_console_output(u'TestJob', number=52)
self.assertEqual(console_output, jenkins_mock.return_value) self.assertEqual(console_output, jenkins_mock.return_value)
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send')
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/TestJob/52/consoleText'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(404, reason="Not Found"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_console_output(u'TestJob', number=52) self.j.get_build_console_output(u'TestJob', number=52)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][0].url,
self.make_url('job/TestJob/52/consoleText')) self.make_url('job/TestJob/52/consoleText'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'job[TestJob] number[52] does not exist') 'job[TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send')
def test_in_folder_raise_HTTPError(self, jenkins_mock): def test_in_folder_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/a%20Folder/job/TestJob/52/consoleText'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(404, reason="Not Found"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_console_output(u'a Folder/TestJob', number=52) self.j.get_build_console_output(u'a Folder/TestJob', number=52)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][0].url,
self.make_url('job/a%20Folder/job/TestJob/52/consoleText')) self.make_url('job/a%20Folder/job/TestJob/52/consoleText'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'job[a Folder/TestJob] number[52] does not exist') 'job[a Folder/TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsBuildInfoTest(JenkinsTestBase): class JenkinsBuildInfoTest(JenkinsTestBase):
@ -116,7 +110,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
self.assertEqual(build_info, build_info_to_return) self.assertEqual(build_info, build_info_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/52/api/json?depth=0')) self.make_url('job/Test%20Job/52/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -134,7 +128,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
self.assertEqual(build_info, build_info_to_return) self.assertEqual(build_info, build_info_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/52/api/json?depth=0')) self.make_url('job/a%20Folder/job/Test%20Job/52/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -160,37 +154,31 @@ class JenkinsBuildInfoTest(JenkinsTestBase):
'Could not parse JSON info for job[TestJob] number[52]') 'Could not parse JSON info for job[TestJob] number[52]')
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/TestJob/api/json?depth=0'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(404, reason="Not Found"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_info(u'TestJob', number=52) self.j.get_build_info(u'TestJob', number=52)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'job[TestJob] number[52] does not exist') 'job[TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_in_folder_raise_HTTPError(self, jenkins_mock): def test_in_folder_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(404, reason="Not Found"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_info(u'a Folder/TestJob', number=52) self.j.get_build_info(u'a Folder/TestJob', number=52)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'job[a Folder/TestJob] number[52] does not exist') 'job[a Folder/TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsStopBuildTest(JenkinsTestBase): class JenkinsStopBuildTest(JenkinsTestBase):
@ -200,7 +188,7 @@ class JenkinsStopBuildTest(JenkinsTestBase):
self.j.stop_build(u'Test Job', number=52) self.j.stop_build(u'Test Job', number=52)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/52/stop')) self.make_url('job/Test%20Job/52/stop'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -210,7 +198,7 @@ class JenkinsStopBuildTest(JenkinsTestBase):
self.j.stop_build(u'a Folder/Test Job', number=52) self.j.stop_build(u'a Folder/Test Job', number=52)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/a%20Folder/job/Test%20Job/52/stop')) self.make_url('job/a%20Folder/job/Test%20Job/52/stop'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -3,6 +3,7 @@ from mock import patch
import jenkins import jenkins
from tests.base import JenkinsTestBase from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
class JenkinsInfoTest(JenkinsTestBase): class JenkinsInfoTest(JenkinsTestBase):
@ -22,28 +23,25 @@ class JenkinsInfoTest(JenkinsTestBase):
self.assertEqual(job_info, job_info_to_return) self.assertEqual(job_info, job_info_to_return)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/TestJob/api/json?depth=0'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(499, reason="Unhandled Error"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_info() self.j.get_info()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url('api/json')) self.make_url('api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}]'.format(self.make_url('')))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_raise_BadStatusLine(self, jenkins_mock): def test_raise_BadStatusLine(self, jenkins_mock):
@ -52,11 +50,11 @@ class JenkinsInfoTest(JenkinsTestBase):
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_info() self.j.get_info()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}]'.format(self.make_url('')))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
@ -66,26 +64,26 @@ class JenkinsInfoTest(JenkinsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_info() self.j.get_info()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for server[{0}/]'.format(self.base_url)) 'Could not parse JSON info for server[{0}]'.format(self.make_url('')))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_empty_response(self, jenkins_mock): def test_return_empty_response(self, jenkins_mock):
jenkins_mock.side_effect = jenkins.JenkinsException( jenkins_mock.side_effect = jenkins.JenkinsException(
"Error communicating with server[{0}/]: empty response". "Error communicating with server[{0}]: empty response".
format(self.base_url)) format(self.make_url('')))
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_info() self.j.get_info()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]: ' 'Error communicating with server[{0}]: '
'empty response'.format(self.base_url)) 'empty response'.format(self.make_url('')))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -1,12 +1,13 @@
import json import json
import socket import socket
from mock import patch, Mock from mock import patch
import six import six
from six.moves.urllib.error import HTTPError
from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
import jenkins import jenkins
from tests.base import JenkinsTestBase
def get_mock_urlopen_return_value(a_dict=None): def get_mock_urlopen_return_value(a_dict=None):
@ -17,19 +18,28 @@ def get_mock_urlopen_return_value(a_dict=None):
class JenkinsConstructorTest(JenkinsTestBase): class JenkinsConstructorTest(JenkinsTestBase):
def setUp(self):
super(JenkinsConstructorTest, self).setUp()
self.req = jenkins.requests.Request('GET', self.base_url)
self.j._maybe_add_auth()
def test_url_with_trailing_slash(self): def test_url_with_trailing_slash(self):
self.assertEqual(self.j.server, self.make_url('')) self.assertEqual(self.j.server, self.make_url(''))
self.assertEqual(self.j.auth, b'Basic dGVzdDp0ZXN0') self.assertEqual(self.j.auth(self.req).headers['Authorization'],
'Basic dGVzdDp0ZXN0')
self.assertEqual(self.j.crumb, None) self.assertEqual(self.j.crumb, None)
def test_url_without_trailing_slash(self): def test_url_without_trailing_slash(self):
j = jenkins.Jenkins(self.base_url, 'test', 'test') j = jenkins.Jenkins(self.base_url, 'test', 'test')
j._maybe_add_auth()
self.assertEqual(j.server, self.make_url('')) self.assertEqual(j.server, self.make_url(''))
self.assertEqual(j.auth, b'Basic dGVzdDp0ZXN0') self.assertEqual(j.auth(self.req).headers['Authorization'],
'Basic dGVzdDp0ZXN0')
self.assertEqual(j.crumb, None) self.assertEqual(j.crumb, None)
def test_without_user_or_password(self): def test_without_user_or_password(self):
j = jenkins.Jenkins('{0}'.format(self.base_url)) j = jenkins.Jenkins('{0}'.format(self.base_url))
j._maybe_add_auth()
self.assertEqual(j.server, self.make_url('')) self.assertEqual(j.server, self.make_url(''))
self.assertEqual(j.auth, None) self.assertEqual(j.auth, None)
self.assertEqual(j.crumb, None) self.assertEqual(j.crumb, None)
@ -38,8 +48,10 @@ class JenkinsConstructorTest(JenkinsTestBase):
j = jenkins.Jenkins('{0}'.format(self.base_url), j = jenkins.Jenkins('{0}'.format(self.base_url),
six.u('nonascii'), six.u('nonascii'),
six.u('\xe9\u20ac')) six.u('\xe9\u20ac'))
j._maybe_add_auth()
self.assertEqual(j.server, self.make_url('')) self.assertEqual(j.server, self.make_url(''))
self.assertEqual(j.auth, b'Basic bm9uYXNjaWk6w6nigqw=') self.assertEqual(j.auth(self.req).headers['Authorization'],
'Basic bm9uYXNjaWk6w6nigqw=')
self.assertEqual(j.crumb, None) self.assertEqual(j.crumb, None)
def test_long_user_or_password(self): def test_long_user_or_password(self):
@ -47,9 +59,11 @@ class JenkinsConstructorTest(JenkinsTestBase):
long_str_b64 = 'YWFh' * 20 long_str_b64 = 'YWFh' * 20
j = jenkins.Jenkins('{0}'.format(self.base_url), long_str, long_str) j = jenkins.Jenkins('{0}'.format(self.base_url), long_str, long_str)
j._maybe_add_auth()
self.assertNotIn(b"\n", j.auth) auth_header = j.auth(self.req).headers['Authorization']
self.assertEqual(j.auth.decode('utf-8'), 'Basic %s' % ( self.assertNotIn("\n", auth_header)
self.assertEqual(auth_header, 'Basic %s' % (
long_str_b64 + 'Om' + long_str_b64[2:] + 'YQ==')) long_str_b64 + 'Om' + long_str_b64[2:] + 'YQ=='))
def test_default_timeout(self): def test_default_timeout(self):
@ -63,80 +77,74 @@ class JenkinsConstructorTest(JenkinsTestBase):
class JenkinsMaybeAddCrumbTest(JenkinsTestBase): class JenkinsMaybeAddCrumbTest(JenkinsTestBase):
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_simple(self, jenkins_mock): def test_simple(self, session_send_mock):
jenkins_mock.side_effect = jenkins.NotFoundException() session_send_mock.return_value = build_response_mock(
request = jenkins.Request(self.make_url('job/TestJob')) 404, reason="Not Found")
request = jenkins.requests.Request('http://example.com/job/TestJob')
self.j.maybe_add_crumb(request) self.j.maybe_add_crumb(request)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('crumbIssuer/api/json')) self.make_url('crumbIssuer/api/json'))
self.assertFalse(self.j.crumb) self.assertFalse(self.j.crumb)
self.assertFalse('.crumb' in request.headers) self.assertFalse('.crumb' in request.headers)
self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_with_data(self, jenkins_mock): def test_with_data(self, session_send_mock):
jenkins_mock.return_value = get_mock_urlopen_return_value(self.crumb_data) session_send_mock.return_value = build_response_mock(
request = jenkins.Request(self.make_url('job/TestJob')) 200, self.crumb_data)
request = jenkins.requests.Request('GET', 'http://example.com/job/TestJob')
self.j.maybe_add_crumb(request) self.j.maybe_add_crumb(request)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('crumbIssuer/api/json')) self.make_url('crumbIssuer/api/json'))
self.assertEqual(self.j.crumb, self.crumb_data) self.assertEqual(self.j.crumb, self.crumb_data)
self.assertEqual(request.headers['.crumb'], self.crumb_data['crumb']) self.assertEqual(request.headers['.crumb'], self.crumb_data['crumb'])
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_empty_response(self, jenkins_mock): def test_return_empty_response(self, jenkins_mock):
"Don't try to create crumb header from an empty response" "Don't try to create crumb header from an empty response"
jenkins_mock.side_effect = jenkins.EmptyResponseException("empty response") jenkins_mock.side_effect = jenkins.EmptyResponseException("empty response")
request = jenkins.Request(self.make_url('job/TestJob')) request = jenkins.requests.Request('GET', 'http://example.com/job/TestJob')
self.j.maybe_add_crumb(request) self.j.maybe_add_crumb(request)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('crumbIssuer/api/json')) self.make_url('crumbIssuer/api/json'))
self.assertFalse(self.j.crumb) self.assertFalse(self.j.crumb)
self.assertFalse('.crumb' in request.headers) self.assertFalse('.crumb' in request.headers)
self._check_requests(jenkins_mock.call_args_list)
class JenkinsOpenTest(JenkinsTestBase): class JenkinsOpenTest(JenkinsTestBase):
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_simple(self, jenkins_mock): def test_simple(self, session_send_mock):
data = {'foo': 'bar'} data = {'foo': 'bar'}
jenkins_mock.side_effect = [ session_send_mock.side_effect = iter([
get_mock_urlopen_return_value(self.crumb_data), build_response_mock(200, self.crumb_data),
get_mock_urlopen_return_value(data), build_response_mock(200, data),
] ])
request = jenkins.Request(self.make_url('job/TestJob')) request = jenkins.requests.Request('GET', self.make_url('job/TestJob'))
response = self.j.jenkins_open(request) response = self.j.jenkins_open(request)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('job/TestJob')) self.make_url('job/TestJob'))
self.assertEqual(response, json.dumps(data)) self.assertEqual(response, json.dumps(data))
self.assertEqual(self.j.crumb, self.crumb_data) self.assertEqual(self.j.crumb, self.crumb_data)
self.assertEqual(request.headers['.crumb'], self.crumb_data['crumb']) self.assertEqual(request.headers['.crumb'], self.crumb_data['crumb'])
self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_response_403(self, jenkins_mock): def test_response_403(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( request = jenkins.requests.Request('GET', self.make_url('job/TestJob'))
self.make_url('job/TestJob'), session_send_mock.return_value = build_response_mock(
code=401, 401, reason="basic auth failed")
msg="basic auth failed",
hdrs=[],
fp=None)
request = jenkins.Request(self.make_url('job/TestJob'))
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.jenkins_open(request, add_crumb=False) self.j.jenkins_open(request, add_crumb=False)
@ -145,19 +153,14 @@ class JenkinsOpenTest(JenkinsTestBase):
'Error in request. Possibly authentication failed [401]: ' 'Error in request. Possibly authentication failed [401]: '
'basic auth failed') 'basic auth failed')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('job/TestJob')) self.make_url('job/TestJob'))
self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_response_404(self, jenkins_mock): def test_response_404(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( request = jenkins.requests.Request('GET', self.make_url('job/TestJob'))
self.make_url('job/TestJob'), session_send_mock.return_value = build_response_mock(
code=404, 404, reason="basic auth failed")
msg="basic auth failed",
hdrs=[],
fp=None)
request = jenkins.Request(self.make_url('job/TestJob'))
with self.assertRaises(jenkins.NotFoundException) as context_manager: with self.assertRaises(jenkins.NotFoundException) as context_manager:
self.j.jenkins_open(request, add_crumb=False) self.j.jenkins_open(request, add_crumb=False)
@ -165,53 +168,46 @@ class JenkinsOpenTest(JenkinsTestBase):
str(context_manager.exception), str(context_manager.exception),
'Requested item could not be found') 'Requested item could not be found')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('job/TestJob')) self.make_url('job/TestJob'))
self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_empty_response(self, jenkins_mock): def test_empty_response(self, session_send_mock):
jenkins_mock.return_value = Mock(**{'read.return_value': None}) request = jenkins.requests.Request('GET', self.make_url('job/TestJob'))
session_send_mock.return_value = build_response_mock(
request = jenkins.Request(self.make_url('job/TestJob')) 401, reason="basic auth failed")
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.jenkins_open(request, False) self.j.jenkins_open(request, False)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]: ' 'Error in request. Possibly authentication failed [401]: '
'empty response'.format(self.base_url)) 'basic auth failed')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('job/TestJob')) self.make_url('job/TestJob'))
self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_response_501(self, jenkins_mock): def test_response_501(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( request = jenkins.requests.Request('GET', self.make_url('job/TestJob'))
self.make_url('job/TestJob'), session_send_mock.return_value = build_response_mock(
code=501, 501, reason="Not implemented")
msg="Not implemented",
hdrs=[],
fp=None)
request = jenkins.Request(self.make_url('job/TestJob'))
with self.assertRaises(HTTPError) as context_manager: with self.assertRaises(jenkins.req_exc.HTTPError) as context_manager:
self.j.jenkins_open(request, add_crumb=False) self.j.jenkins_open(request, add_crumb=False)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'HTTP Error 501: Not implemented') '501 Server Error: Not implemented for url: None')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('job/TestJob')) self.make_url('job/TestJob'))
self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_timeout(self, jenkins_mock): def test_timeout(self, session_send_mock):
jenkins_mock.side_effect = jenkins.URLError( session_send_mock.side_effect = jenkins.URLError(
reason="timed out") reason="timed out")
j = jenkins.Jenkins(self.make_url(''), 'test', 'test', timeout=1) j = jenkins.Jenkins(self.make_url(''), 'test', 'test', timeout=1)
request = jenkins.Request(self.make_url('job/TestJob')) request = jenkins.requests.Request('GET', self.make_url('job/TestJob'))
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
j.jenkins_open(request, add_crumb=False) j.jenkins_open(request, add_crumb=False)
@ -219,9 +215,8 @@ class JenkinsOpenTest(JenkinsTestBase):
str(context_manager.exception), str(context_manager.exception),
'Error in request: timed out') 'Error in request: timed out')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args[0][1].url,
self.make_url('job/TestJob')) self.make_url('job/TestJob'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open', @patch.object(jenkins.Jenkins, 'jenkins_open',
return_value=json.dumps({'mode': 'NORMAL'})) return_value=json.dumps({'mode': 'NORMAL'}))

View File

@ -23,7 +23,7 @@ class JenkinsRequestTimeoutTests(testtools.TestCase):
def test_jenkins_open_timeout(self): def test_jenkins_open_timeout(self):
j = jenkins.Jenkins("http://%s:%s" % self.server.server_address, j = jenkins.Jenkins("http://%s:%s" % self.server.server_address,
None, None, timeout=0.1) None, None, timeout=0.1)
request = jenkins.Request('http://%s:%s/job/TestJob' % request = jenkins.requests.Request('GET', 'http://%s:%s/job/TestJob' %
self.server.server_address) self.server.server_address)
# assert our request times out when no response # assert our request times out when no response
@ -33,7 +33,7 @@ class JenkinsRequestTimeoutTests(testtools.TestCase):
def test_jenkins_open_no_timeout(self): def test_jenkins_open_no_timeout(self):
j = jenkins.Jenkins("http://%s:%s" % self.server.server_address, j = jenkins.Jenkins("http://%s:%s" % self.server.server_address,
None, None) None, None)
request = jenkins.Request('http://%s:%s/job/TestJob' % request = jenkins.requests.Request('GET', 'http://%s:%s/job/TestJob' %
self.server.server_address) self.server.server_address)
# assert we don't timeout quickly like previous test when # assert we don't timeout quickly like previous test when

View File

@ -1,124 +0,0 @@
import kerberos
assert kerberos # pyflakes
from mock import patch, Mock
from six.moves.urllib.request import Request
import testtools
from jenkins import urllib_kerb
class KerberosTests(testtools.TestCase):
@patch('kerberos.authGSSClientResponse')
@patch('kerberos.authGSSClientStep')
@patch('kerberos.authGSSClientInit')
@patch('kerberos.authGSSClientClean')
def test_http_error_401_simple(self, clean_mock, init_mock, step_mock, response_mock):
headers_from_server = {'www-authenticate': 'Negotiate xxx'}
init_mock.side_effect = lambda x: (x, "context")
response_mock.return_value = "foo"
parent_mock = Mock()
parent_return_mock = Mock()
parent_return_mock.headers = {'www-authenticate': "Negotiate bar"}
parent_mock.open.return_value = parent_return_mock
request_mock = Mock(spec=self._get_dummy_request())
h = urllib_kerb.HTTPNegotiateHandler()
h.add_parent(parent_mock)
rv = h.http_error_401(request_mock, "", "", "", headers_from_server)
init_mock.assert_called()
step_mock.assert_any_call("context", "xxx")
# verify authGSSClientStep was called for response as well
step_mock.assert_any_call("context", "bar")
response_mock.assert_called_with("context")
request_mock.add_unredirected_header.assert_called_with(
'Authorization', 'Negotiate %s' % "foo")
self.assertEqual(rv, parent_return_mock)
clean_mock.assert_called_with("context")
@patch('kerberos.authGSSClientResponse')
@patch('kerberos.authGSSClientStep')
@patch('kerberos.authGSSClientInit')
@patch('kerberos.authGSSClientClean')
def test_http_error_401_gsserror(self, clean_mock, init_mock, step_mock, response_mock):
headers_from_server = {'www-authenticate': 'Negotiate xxx'}
init_mock.side_effect = kerberos.GSSError
h = urllib_kerb.HTTPNegotiateHandler()
rv = h.http_error_401(Mock(spec=self._get_dummy_request()), "", "", "",
headers_from_server)
self.assertEqual(rv, None)
@patch('kerberos.authGSSClientResponse')
@patch('kerberos.authGSSClientStep')
@patch('kerberos.authGSSClientInit')
@patch('kerberos.authGSSClientClean')
def test_http_error_401_empty(self, clean_mock, init_mock, step_mock, response_mock):
headers_from_server = {}
h = urllib_kerb.HTTPNegotiateHandler()
rv = h.http_error_401(Mock(spec=self._get_dummy_request()), "", "", "",
headers_from_server)
self.assertEqual(rv, None)
@patch('kerberos.authGSSClientResponse')
@patch('kerberos.authGSSClientStep')
@patch('kerberos.authGSSClientInit')
def test_krb_response_simple(self, init_mock, step_mock, response_mock):
response_mock.return_value = "foo"
init_mock.return_value = ("bar", "context")
h = urllib_kerb.HTTPNegotiateHandler()
rv = h._krb_response("host", "xxx")
self.assertEqual(rv, "foo")
@patch('kerberos.authGSSClientResponse')
@patch('kerberos.authGSSClientStep')
@patch('kerberos.authGSSClientInit')
def test_krb_response_gsserror(self, init_mock, step_mock, response_mock):
response_mock.side_effect = kerberos.GSSError
init_mock.return_value = ("bar", "context")
h = urllib_kerb.HTTPNegotiateHandler()
with testtools.ExpectedException(kerberos.GSSError):
h._krb_response("host", "xxx")
@patch('kerberos.authGSSClientStep')
def test_authenticate_server_simple(self, step_mock):
headers_from_server = {'www-authenticate': 'Negotiate xxx'}
h = urllib_kerb.HTTPNegotiateHandler()
h.krb_context = "foo"
h._authenticate_server(headers_from_server)
step_mock.assert_called_with("foo", "xxx")
@patch('kerberos.authGSSClientStep')
def test_authenticate_server_empty(self, step_mock):
headers_from_server = {'www-authenticate': 'Negotiate'}
h = urllib_kerb.HTTPNegotiateHandler()
rv = h._authenticate_server(headers_from_server)
self.assertEqual(rv, None)
def test_extract_krb_value_simple(self):
headers_from_server = {'www-authenticate': 'Negotiate xxx'}
h = urllib_kerb.HTTPNegotiateHandler()
rv = h._extract_krb_value(headers_from_server)
self.assertEqual(rv, "xxx")
def test_extract_krb_value_empty(self):
headers_from_server = {}
h = urllib_kerb.HTTPNegotiateHandler()
with testtools.ExpectedException(ValueError):
h._extract_krb_value(headers_from_server)
def test_extract_krb_value_invalid(self):
headers_from_server = {'www-authenticate': 'Foo-&#@^%:; bar'}
h = urllib_kerb.HTTPNegotiateHandler()
with testtools.ExpectedException(ValueError):
h._extract_krb_value(headers_from_server)
def _get_dummy_request(self):
r = Request('http://example.com')
r.timeout = 10
return r

View File

@ -2,7 +2,9 @@ import json
from mock import patch from mock import patch
import jenkins import jenkins
import requests_mock
from tests.base import JenkinsTestBase from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
class JenkinsNodesTestBase(JenkinsTestBase): class JenkinsNodesTestBase(JenkinsTestBase):
@ -42,41 +44,41 @@ class JenkinsGetNodesTest(JenkinsNodesTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_nodes() self.j.get_nodes()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('computer/api/json')) self.make_url('computer/api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for server[{0}/]'.format(self.base_url)) 'Could not parse JSON info for server[{0}]'.format(
self.make_url('')))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_BadStatusLine(self, urlopen_mock): def test_raise_BadStatusLine(self, session_send_mock):
urlopen_mock.side_effect = jenkins.BadStatusLine('not a valid status line') session_send_mock.side_effect = jenkins.BadStatusLine(
'not a valid status line')
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_nodes() self.j.get_nodes()
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}]'.format(
self._check_requests(urlopen_mock.call_args_list) self.make_url('')))
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/TestJob'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(499, reason="Unhandled Error"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_nodes() self.j.get_nodes()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url('computer/api/json')) self.make_url('computer/api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}]'.format(
self._check_requests(jenkins_mock.call_args_list) self.make_url('')))
class JenkinsGetNodeInfoTest(JenkinsNodesTestBase): class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
@ -87,11 +89,11 @@ class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
json.dumps(self.node_info), json.dumps(self.node_info),
] ]
self._check_requests(jenkins_mock.call_args_list)
self.assertEqual(self.j.get_node_info('test node'), self.node_info) self.assertEqual(self.j.get_node_info('test node'), self.node_info)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('computer/test%20node/api/json?depth=0')) self.make_url('computer/test%20node/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_invalid_json(self, jenkins_mock): def test_return_invalid_json(self, jenkins_mock):
@ -101,32 +103,30 @@ class JenkinsGetNodeInfoTest(JenkinsNodesTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_node_info('test_node') self.j.get_node_info('test_node')
self._check_requests(jenkins_mock.call_args_list)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('computer/test_node/api/json?depth=0')) self.make_url('computer/test_node/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for node[test_node]') 'Could not parse JSON info for node[test_node]')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/TestJob'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(499, reason="Unhandled Error"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_node_info('test_node') self.j.get_node_info('test_node')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url('computer/test_node/api/json?depth=0')) self.make_url('computer/test_node/api/json?depth=0'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'node[test_node] does not exist') 'node[test_node] does not exist')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsAssertNodeExistsTest(JenkinsNodesTestBase): class JenkinsAssertNodeExistsTest(JenkinsNodesTestBase):
@ -137,10 +137,11 @@ class JenkinsAssertNodeExistsTest(JenkinsNodesTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.assert_node_exists('NonExistentNode') self.j.assert_node_exists('NonExistentNode')
self._check_requests(jenkins_mock.call_args_list)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'node[NonExistentNode] does not exist') 'node[NonExistentNode] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_node_exists(self, jenkins_mock): def test_node_exists(self, jenkins_mock):
@ -164,11 +165,11 @@ class JenkinsDeleteNodeTest(JenkinsNodesTestBase):
self.j.delete_node('test node') self.j.delete_node('test node')
self._check_requests(jenkins_mock.call_args_list)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('computer/test%20node/doDelete')) self.make_url('computer/test%20node/doDelete'))
self.assertFalse(self.j.node_exists('test node')) self.assertFalse(self.j.node_exists('test node'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_failed(self, jenkins_mock): def test_failed(self, jenkins_mock):
@ -180,42 +181,55 @@ class JenkinsDeleteNodeTest(JenkinsNodesTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.delete_node('test_node') self.j.delete_node('test_node')
self._check_requests(jenkins_mock.call_args_list)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('computer/test_node/doDelete')) self.make_url('computer/test_node/doDelete'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'delete[test_node] failed') 'delete[test_node] failed')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsCreateNodeTest(JenkinsNodesTestBase): class JenkinsCreateNodeTest(JenkinsNodesTestBase):
@patch.object(jenkins.Jenkins, 'jenkins_open') @requests_mock.Mocker()
def test_simple(self, jenkins_mock): def test_simple(self, req_mock):
jenkins_mock.side_effect = [ req_mock.get(self.make_url(jenkins.CRUMB_URL))
None, req_mock.post(self.make_url(jenkins.CREATE_NODE), status_code=200,
None, text='success', headers={'content-length': '7'})
json.dumps(self.node_info), req_mock.get(
json.dumps(self.node_info), self.make_url('computer/test%20node/api/json?depth=0'),
] [{'status_code': 404, 'headers': {'content-length': '9'},
'text': 'NOT FOUND'},
{'status_code': 200, 'json': {'displayName': 'test%20node'},
'headers': {'content-length': '20'}}
])
self.j.create_node('test node', exclusive=True) self.j.create_node('test node', exclusive=True)
self.assertEqual( actual = req_mock.request_history[2]
jenkins_mock.call_args_list[1][0][0].get_full_url().split('?')[0], self.assertEqual(actual.url, self.make_url('computer/doCreateItem'))
self.make_url('computer/doCreateItem')) self.assertIn('name=test+node', actual.body)
self.assertTrue(self.j.node_exists('test node')) self.assertTrue(self.j.node_exists('test node'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @requests_mock.Mocker()
def test_urlencode(self, jenkins_mock): def test_urlencode(self, req_mock):
jenkins_mock.side_effect = [ # resp 0 (don't care about this succeeding)
None, req_mock.get(self.make_url(jenkins.CRUMB_URL))
None, # resp 2
json.dumps(self.node_info), req_mock.post(self.make_url(jenkins.CREATE_NODE), status_code=200,
json.dumps(self.node_info), text='success', headers={'content-length': '7'})
] # resp 1 & 3
req_mock.get(
self.make_url('computer/10.0.0.1%2Btest-node/api/json?depth=0'),
[{'status_code': 404, 'headers': {'content-length': '9'},
'text': 'NOT FOUND'},
{'status_code': 200,
'json': {'displayName': '10.0.0.1+test-node'},
'headers': {'content-length': '20'}}
])
params = { params = {
'port': '22', 'port': '22',
'username': 'juser', 'username': 'juser',
@ -232,11 +246,10 @@ class JenkinsCreateNodeTest(JenkinsNodesTestBase):
launcher=jenkins.LAUNCHER_SSH, launcher=jenkins.LAUNCHER_SSH,
launcher_params=params) launcher_params=params)
actual = jenkins_mock.call_args_list[1][0][0].data.decode('utf-8') actual = req_mock.request_history[2].body
# As python dicts do not guarantee order so the parameters get # As python dicts do not guarantee order so the parameters get
# re-ordered when it gets processed by _get_encoded_params(), # re-ordered when it gets processed by requests, verify sections
# verify sections of the URL with self.assertIn() instead of # of the URL with self.assertIn() instead of the entire URL
# the entire URL
self.assertIn(u'name=10.0.0.1%2Btest-node', actual) self.assertIn(u'name=10.0.0.1%2Btest-node', actual)
self.assertIn(u'type=hudson.slaves.DumbSlave%24DescriptorImpl', actual) self.assertIn(u'type=hudson.slaves.DumbSlave%24DescriptorImpl', actual)
self.assertIn(u'username%22%3A+%22juser', actual) self.assertIn(u'username%22%3A+%22juser', actual)
@ -250,20 +263,21 @@ class JenkinsCreateNodeTest(JenkinsNodesTestBase):
self.assertIn(u'port%22%3A+%2222', actual) self.assertIn(u'port%22%3A+%2222', actual)
self.assertIn(u'remoteFS%22%3A+%22%2Fhome%2Fjuser', actual) self.assertIn(u'remoteFS%22%3A+%22%2Fhome%2Fjuser', actual)
self.assertIn(u'labelString%22%3A+%22precise', actual) self.assertIn(u'labelString%22%3A+%22precise', actual)
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @requests_mock.Mocker()
def test_already_exists(self, jenkins_mock): def test_already_exists(self, req_mock):
jenkins_mock.side_effect = [ req_mock.get(self.make_url(jenkins.CRUMB_URL))
json.dumps(self.node_info), req_mock.get(
] self.make_url('computer/test_node/api/json?depth=0'),
status_code=200, json=self.node_info,
headers={'content-length': '20'}
)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_node('test_node') self.j.create_node('test_node')
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'node[test_node] already exists') 'node[test_node] already exists')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch.object(jenkins.Jenkins, 'jenkins_open')
def test_failed(self, jenkins_mock): def test_failed(self, jenkins_mock):
@ -277,7 +291,7 @@ class JenkinsCreateNodeTest(JenkinsNodesTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_node('test_node') self.j.create_node('test_node')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url().split('?')[0], jenkins_mock.call_args_list[1][0][0].url,
self.make_url('computer/doCreateItem')) self.make_url('computer/doCreateItem'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -297,9 +311,9 @@ class JenkinsEnableNodeTest(JenkinsNodesTestBase):
self.j.enable_node('test node') self.j.enable_node('test node')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
'{0}/computer/test%20node/' self.make_url('computer/test%20node/'
'toggleOffline?offlineMessage='.format(self.base_url)) 'toggleOffline?offlineMessage='))
jenkins_mock.side_effect = [json.dumps(self.online_node_info)] jenkins_mock.side_effect = [json.dumps(self.online_node_info)]
node_info = self.j.get_node_info('test node') node_info = self.j.get_node_info('test node')
@ -318,7 +332,7 @@ class JenkinsEnableNodeTest(JenkinsNodesTestBase):
# Node was not offline; so enable_node skips toggle # Node was not offline; so enable_node skips toggle
# Last call to jenkins was to check status # Last call to jenkins was to check status
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('computer/test_node/api/json?depth=0')) self.make_url('computer/test_node/api/json?depth=0'))
jenkins_mock.side_effect = [json.dumps(self.online_node_info)] jenkins_mock.side_effect = [json.dumps(self.online_node_info)]
@ -339,9 +353,9 @@ class JenkinsDisableNodeTest(JenkinsNodesTestBase):
self.j.disable_node('test node') self.j.disable_node('test node')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
'{0}/computer/test%20node/' self.make_url('computer/test%20node/'
'toggleOffline?offlineMessage='.format(self.base_url)) 'toggleOffline?offlineMessage='))
jenkins_mock.side_effect = [json.dumps(self.offline_node_info)] jenkins_mock.side_effect = [json.dumps(self.offline_node_info)]
node_info = self.j.get_node_info('test node') node_info = self.j.get_node_info('test node')
@ -360,7 +374,7 @@ class JenkinsDisableNodeTest(JenkinsNodesTestBase):
# Node was already offline; so disable_node skips toggle # Node was already offline; so disable_node skips toggle
# Last call to jenkins was to check status # Last call to jenkins was to check status
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('computer/test_node/api/json?depth=0')) self.make_url('computer/test_node/api/json?depth=0'))
jenkins_mock.side_effect = [json.dumps(self.offline_node_info)] jenkins_mock.side_effect = [json.dumps(self.offline_node_info)]

View File

@ -38,6 +38,7 @@ from testscenarios.scenarios import multiply_scenarios
import jenkins import jenkins
from jenkins import plugins from jenkins import plugins
from tests.base import JenkinsTestBase from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
class JenkinsPluginsBase(JenkinsTestBase): class JenkinsPluginsBase(JenkinsTestBase):
@ -83,7 +84,7 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
plugins_info = self.j.get_plugins_info() plugins_info = self.j.get_plugins_info()
self.assertEqual(plugins_info, self.plugin_info_json['plugins']) self.assertEqual(plugins_info, self.plugin_info_json['plugins'])
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=2')) self.make_url('pluginManager/api/json?depth=2'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -103,7 +104,7 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
self.j.get_plugins_info(depth=1) self.j.get_plugins_info(depth=1)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=1')) self.make_url('pluginManager/api/json?depth=1'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -114,7 +115,7 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_plugins_info() self.j.get_plugins_info()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=2')) self.make_url('pluginManager/api/json?depth=2'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -128,28 +129,23 @@ class JenkinsPluginsInfoTest(JenkinsPluginsBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_plugins_info() self.j.get_plugins_info()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=2')) self.make_url('pluginManager/api/json?depth=2'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for server[{0}/]'.format(self.base_url)) 'Could not parse JSON info for server[{0}/]'.format(self.base_url))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.return_value = build_response_mock(
self.make_url('job/pluginManager/api/json?depth=2'), 499, reason="Unhandled Error")
code=401,
msg="basic auth failed",
hdrs=[],
fp=None)
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_plugins_info(depth=52) self.j.get_plugins_info(depth=52)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}/]'.format(self.base_url))
self._check_requests(jenkins_mock.call_args_list)
class JenkinsPluginInfoTest(JenkinsPluginsBase): class JenkinsPluginInfoTest(JenkinsPluginsBase):
@ -209,7 +205,7 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
self.j.get_plugin_info('test', depth=1) self.j.get_plugin_info('test', depth=1)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=1')) self.make_url('pluginManager/api/json?depth=1'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -220,7 +216,7 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_plugin_info('test') self.j.get_plugin_info('test')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=2')) self.make_url('pluginManager/api/json?depth=2'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -234,28 +230,25 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_plugin_info('test') self.j.get_plugin_info('test')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('pluginManager/api/json?depth=2')) self.make_url('pluginManager/api/json?depth=2'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Could not parse JSON info for server[{0}/]'.format(self.base_url)) 'Could not parse JSON info for server[{0}/]'.format(self.base_url))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('job/pluginManager/api/json?depth=2'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(499, reason="Unhandled Error"), # request
msg="basic auth failed", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_plugin_info(u'TestPlugin', depth=52) self.j.get_plugin_info(u'TestPlugin', depth=52)
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}/]'.format(self.base_url))
self._check_requests(jenkins_mock.call_args_list)
class PluginsTestScenarios(JenkinsPluginsBase): class PluginsTestScenarios(JenkinsPluginsBase):

View File

@ -24,7 +24,7 @@ class JenkinsGetPromotionNameTest(JenkinsPromotionsTestBase):
self.assertEqual(promotion_name, 'Test Promotion') self.assertEqual(promotion_name, 'Test Promotion')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/promotion/process/' self.make_url('job/Test%20Job/promotion/process/'
'Test%20Promotion/api/json?tree=name')) 'Test%20Promotion/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -38,7 +38,7 @@ class JenkinsGetPromotionNameTest(JenkinsPromotionsTestBase):
self.assertEqual(promotion_name, None) self.assertEqual(promotion_name, None)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/promotion/process/' self.make_url('job/Test%20Job/promotion/process/'
'TestPromotion/api/json?tree=name')) 'TestPromotion/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -51,7 +51,7 @@ class JenkinsGetPromotionNameTest(JenkinsPromotionsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_promotion_name(u'TestPromotion', u'TestJob') self.j.get_promotion_name(u'TestPromotion', u'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/promotion/process/TestPromotion' self.make_url('job/TestJob/promotion/process/TestPromotion'
'/api/json?tree=name')) '/api/json?tree=name'))
self.assertEqual( self.assertEqual(
@ -122,7 +122,7 @@ class JenkinsGetPromotionsTest(JenkinsPromotionsTestBase):
self.assertEqual(promotion_info, promotions) self.assertEqual(promotion_info, promotions)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/TestJob/promotion/api/json?depth=0')) self.make_url('job/TestJob/promotion/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -164,7 +164,7 @@ class JenkinsDeletePromotionTest(JenkinsPromotionsTestBase):
self.j.delete_promotion(u'Test Promotion', 'TestJob') self.j.delete_promotion(u'Test Promotion', 'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/promotion/process/' self.make_url('job/TestJob/promotion/process/'
'Test%20Promotion/doDelete')) 'Test%20Promotion/doDelete'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -180,7 +180,7 @@ class JenkinsDeletePromotionTest(JenkinsPromotionsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.delete_promotion(u'TestPromotion', 'TestJob') self.j.delete_promotion(u'TestPromotion', 'TestJob')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/promotion/process/' self.make_url('job/TestJob/promotion/process/'
'TestPromotion/doDelete')) 'TestPromotion/doDelete'))
self.assertEqual( self.assertEqual(
@ -202,7 +202,7 @@ class JenkinsCreatePromotionTest(JenkinsPromotionsTestBase):
self.j.create_promotion(u'Test Promotion', 'Test Job', self.config_xml) self.j.create_promotion(u'Test Promotion', 'Test Job', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('job/Test%20Job/promotion/' self.make_url('job/Test%20Job/promotion/'
'createProcess?name=Test%20Promotion')) 'createProcess?name=Test%20Promotion'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -218,7 +218,7 @@ class JenkinsCreatePromotionTest(JenkinsPromotionsTestBase):
self.j.create_promotion(u'TestPromotion', 'TestJob', self.j.create_promotion(u'TestPromotion', 'TestJob',
self.config_xml) self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/promotion/process/' self.make_url('job/TestJob/promotion/process/'
'TestPromotion/api/json?tree=name')) 'TestPromotion/api/json?tree=name'))
self.assertEqual( self.assertEqual(
@ -238,11 +238,11 @@ class JenkinsCreatePromotionTest(JenkinsPromotionsTestBase):
self.j.create_promotion(u'TestPromotion', 'TestJob', self.j.create_promotion(u'TestPromotion', 'TestJob',
self.config_xml) self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('job/TestJob/promotion/process/' self.make_url('job/TestJob/promotion/process/'
'TestPromotion/api/json?tree=name')) 'TestPromotion/api/json?tree=name'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('job/TestJob/promotion/' self.make_url('job/TestJob/promotion/'
'createProcess?name=TestPromotion')) 'createProcess?name=TestPromotion'))
self.assertEqual( self.assertEqual(
@ -263,7 +263,7 @@ class JenkinsReconfigPromotionTest(JenkinsPromotionsTestBase):
self.j.reconfig_promotion(u'Test Promotion', u'Test Job', self.j.reconfig_promotion(u'Test Promotion', u'Test Job',
self.config_xml) self.config_xml)
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/promotion/process/' self.make_url('job/Test%20Job/promotion/process/'
'Test%20Promotion/config.xml')) 'Test%20Promotion/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -276,7 +276,7 @@ class JenkinsGetPromotionConfigTest(JenkinsPromotionsTestBase):
self.j.get_promotion_config(u'Test Promotion', u'Test Job') self.j.get_promotion_config(u'Test Promotion', u'Test Job')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('job/Test%20Job/promotion/process/' self.make_url('job/Test%20Job/promotion/process/'
'Test%20Promotion/config.xml')) 'Test%20Promotion/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -15,7 +15,7 @@ class JenkinsCancelQueueTest(JenkinsTestBase):
self.j.cancel_queue(52) self.j.cancel_queue(52)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('queue/cancelItem?id=52')) self.make_url('queue/cancelItem?id=52'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -28,7 +28,7 @@ class JenkinsCancelQueueTest(JenkinsTestBase):
self.j.cancel_queue(52) self.j.cancel_queue(52)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('queue/cancelItem?id=52')) self.make_url('queue/cancelItem?id=52'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -67,6 +67,6 @@ class JenkinsQueueInfoTest(JenkinsTestBase):
self.assertEqual(queue_info, queue_info_to_return['items']) self.assertEqual(queue_info, queue_info_to_return['items'])
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('queue/api/json?depth=0')) self.make_url('queue/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -16,10 +16,10 @@ class JenkinsQuietDownTest(JenkinsTestBase):
self.j.quiet_down() self.j.quiet_down()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('quietDown')) self.make_url('quietDown'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -34,10 +34,10 @@ class JenkinsQuietDownTest(JenkinsTestBase):
self.j.quiet_down() self.j.quiet_down()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('quietDown')) self.make_url('quietDown'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -54,6 +54,6 @@ class JenkinsQuietDownTest(JenkinsTestBase):
self.j.quiet_down() self.j.quiet_down()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('quietDown')) self.make_url('quietDown'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -12,7 +12,7 @@ class JenkinsScriptTest(JenkinsTestBase):
self.j.run_script(u'println(\"Hello World!\")') self.j.run_script(u'println(\"Hello World!\")')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('scriptText')) self.make_url('scriptText'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -21,7 +21,7 @@ class JenkinsScriptTest(JenkinsTestBase):
self.j.run_script(u'if (a == b && c ==d) { println(\"Yes\")}') self.j.run_script(u'if (a == b && c ==d) { println(\"Yes\")}')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('scriptText')) self.make_url('scriptText'))
self.assertIn(quote('&&'), jenkins_mock.call_args[0][0].data.decode('utf8')) self.assertIn(quote('&&'), jenkins_mock.call_args[0][0].data.decode('utf8'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -33,7 +33,7 @@ class JenkinsScriptTest(JenkinsTestBase):
j = jenkins.Jenkins(self.make_url(''), 'test', 'test') j = jenkins.Jenkins(self.make_url(''), 'test', 'test')
j.install_plugin("jabber") j.install_plugin("jabber")
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('scriptText')) self.make_url('scriptText'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -1,57 +1,46 @@
from mock import patch, Mock from mock import patch
import six
import jenkins import jenkins
from tests.base import JenkinsTestBase from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
class JenkinsVersionTest(JenkinsTestBase): class JenkinsVersionTest(JenkinsTestBase):
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_some_version(self, urlopen_mock): def test_some_version(self, session_send_mock):
mock_response = Mock() session_send_mock.return_value = build_response_mock(
if six.PY2: 200, headers={'X-Jenkins': 'Version42', 'Content-Length': 0})
config = {'info.return_value.getheader.return_value': 'Version42'}
if six.PY3:
config = {'getheader.return_value': 'Version42'}
mock_response.configure_mock(**config)
urlopen_mock.side_effect = [mock_response]
self.assertEqual(self.j.get_version(), 'Version42') self.assertEqual(self.j.get_version(), 'Version42')
self._check_requests(urlopen_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, urlopen_mock): def test_raise_HTTPError(self, session_send_mock):
urlopen_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url(''), build_response_mock(404, reason="Not Found"), # crumb
code=503, build_response_mock(499, reason="Unhandled Error"), # request
msg="internal server error", ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_version() self.j.get_version()
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}/]'.format(self.base_url))
self._check_requests(urlopen_mock.call_args_list)
@patch('jenkins.urlopen') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_BadStatusLine(self, urlopen_mock): def test_raise_BadStatusLine(self, session_send_mock):
urlopen_mock.side_effect = jenkins.BadStatusLine('not a valid status line') session_send_mock.side_effect = jenkins.BadStatusLine('not a valid status line')
with self.assertRaises(jenkins.BadHTTPException) as context_manager: with self.assertRaises(jenkins.BadHTTPException) as context_manager:
self.j.get_version() self.j.get_version()
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]'.format(self.base_url)) 'Error communicating with server[{0}/]'.format(self.base_url))
self._check_requests(urlopen_mock.call_args_list)
@patch('jenkins.urlopen', return_value=None) @patch('jenkins.requests.Session.send', autospec=True)
def test_return_empty_response(self, urlopen_mock): def test_return_empty_response(self, session_send_mock):
session_send_mock.return_value = build_response_mock(0)
with self.assertRaises(jenkins.EmptyResponseException) as context_manager: with self.assertRaises(jenkins.EmptyResponseException) as context_manager:
self.j.get_version() self.j.get_version()
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
'Error communicating with server[{0}/]:' 'Error communicating with server[{0}/]:'
' empty response'.format(self.base_url)) ' empty response'.format(self.base_url))
self._check_requests(urlopen_mock.call_args_list)

View File

@ -24,7 +24,7 @@ class JenkinsGetViewNameTest(JenkinsViewsTestBase):
self.assertEqual(view_name, 'Test View') self.assertEqual(view_name, 'Test View')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('view/Test%20View/api/json?tree=name')) self.make_url('view/Test%20View/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -36,7 +36,7 @@ class JenkinsGetViewNameTest(JenkinsViewsTestBase):
self.assertEqual(view_name, None) self.assertEqual(view_name, None)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('view/TestView/api/json?tree=name')) self.make_url('view/TestView/api/json?tree=name'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -48,7 +48,7 @@ class JenkinsGetViewNameTest(JenkinsViewsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_view_name(u'TestView') self.j.get_view_name(u'TestView')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('view/TestView/api/json?tree=name')) self.make_url('view/TestView/api/json?tree=name'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -94,7 +94,7 @@ class JenkinsGetViewsTest(JenkinsViewsTestBase):
self.assertEqual(view_info, views) self.assertEqual(view_info, views)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('api/json')) self.make_url('api/json'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -111,7 +111,7 @@ class JenkinsDeleteViewTest(JenkinsViewsTestBase):
self.j.delete_view(u'Test View') self.j.delete_view(u'Test View')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('view/Test%20View/doDelete')) self.make_url('view/Test%20View/doDelete'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -126,7 +126,7 @@ class JenkinsDeleteViewTest(JenkinsViewsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.delete_view(u'TestView') self.j.delete_view(u'TestView')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('view/TestView/doDelete')) self.make_url('view/TestView/doDelete'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -147,7 +147,7 @@ class JenkinsCreateViewTest(JenkinsViewsTestBase):
self.j.create_view(u'Test View', self.config_xml) self.j.create_view(u'Test View', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('createView?name=Test%20View')) self.make_url('createView?name=Test%20View'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -161,7 +161,7 @@ class JenkinsCreateViewTest(JenkinsViewsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_view(u'TestView', self.config_xml) self.j.create_view(u'TestView', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('view/TestView/api/json?tree=name')) self.make_url('view/TestView/api/json?tree=name'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -179,10 +179,10 @@ class JenkinsCreateViewTest(JenkinsViewsTestBase):
with self.assertRaises(jenkins.JenkinsException) as context_manager: with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.create_view(u'TestView', self.config_xml) self.j.create_view(u'TestView', self.config_xml)
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[0][0][0].get_full_url(), jenkins_mock.call_args_list[0][0][0].url,
self.make_url('view/TestView/api/json?tree=name')) self.make_url('view/TestView/api/json?tree=name'))
self.assertEqual( self.assertEqual(
jenkins_mock.call_args_list[1][0][0].get_full_url(), jenkins_mock.call_args_list[1][0][0].url,
self.make_url('createView?name=TestView')) self.make_url('createView?name=TestView'))
self.assertEqual( self.assertEqual(
str(context_manager.exception), str(context_manager.exception),
@ -201,7 +201,7 @@ class JenkinsReconfigViewTest(JenkinsViewsTestBase):
self.j.reconfig_view(u'Test View', self.config_xml) self.j.reconfig_view(u'Test View', self.config_xml)
self.assertEqual(jenkins_mock.call_args[0][0].get_full_url(), self.assertEqual(jenkins_mock.call_args[0][0].url,
self.make_url('view/Test%20View/config.xml')) self.make_url('view/Test%20View/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@ -213,6 +213,6 @@ class JenkinsGetViewConfigTest(JenkinsViewsTestBase):
self.j.get_view_config(u'Test View') self.j.get_view_config(u'Test View')
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('view/Test%20View/config.xml')) self.make_url('view/Test%20View/config.xml'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)

View File

@ -3,6 +3,7 @@ from mock import patch
import jenkins import jenkins
from tests.base import JenkinsTestBase from tests.base import JenkinsTestBase
from tests.helper import build_response_mock
class JenkinsWhoamiTest(JenkinsTestBase): class JenkinsWhoamiTest(JenkinsTestBase):
@ -29,22 +30,19 @@ 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].get_full_url(), jenkins_mock.call_args[0][0].url,
self.make_url('me/api/json')) self.make_url('me/api/json'))
self._check_requests(jenkins_mock.call_args_list) self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open') @patch('jenkins.requests.Session.send', autospec=True)
def test_raise_HTTPError(self, jenkins_mock): def test_raise_HTTPError(self, session_send_mock):
jenkins_mock.side_effect = jenkins.HTTPError( session_send_mock.side_effect = iter([
self.make_url('me/api/json'), build_response_mock(404, reason="Not Found"), # crumb
code=401, build_response_mock(401, reason="Basic Auth Failed"), # request
msg='basic auth failed', ])
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException): with self.assertRaises(jenkins.JenkinsException):
self.j.get_whoami() self.j.get_whoami()
self.assertEqual( self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(), session_send_mock.call_args_list[1][0][1].url,
self.make_url('me/api/json')) self.make_url('me/api/json'))
self._check_requests(jenkins_mock.call_args_list)