Speed up job existence tests by fetching less info

Most methods are asserting that a job exists by calling get_job_info().
Unfortunately that might trigger on the server side a parse of the full
job history to gather the lastSuccessful, lastFailure build numbers.
Since Jenkins is heavily file based, the process is rather long on jobs
having thousands and thousands of build.

Since we only care about checking whether the job exists, introduce
job_exists() which is light on the server side.  To throw exception,
this also introduce the wrapper assert_job_exists() which can futher
customize the exception messages.

Updates all constructs such as:

    if not self.job_exists(job_name):
	raise JenkinsException(<some message> % (job_name))

To:

    self.assert_job_exists(to_name, <some message>)

That speed up operations tremendously whenever the targetted jobs are
very long.

Added coverage test.

Change-Id: I946dbb7a08a8bb172a369af3b2aedc07e3cea9e6
This commit is contained in:
Antoine Musso
2014-04-22 16:25:59 +02:00
parent 5d7ecd43e0
commit c5ccb8560c
2 changed files with 42 additions and 14 deletions

View File

@@ -348,11 +348,10 @@ class Jenkins(object):
:param from_name: Name of Jenkins job to copy from, ``str``
:param to_name: Name of Jenkins job to copy to, ``str``
'''
self.get_job_info(from_name)
self.assert_job_exists(from_name)
self.jenkins_open(Request(
self.server + COPY_JOB % locals(), ''))
if not self.job_exists(to_name):
raise JenkinsException('create[%s] failed' % (to_name))
self.assert_job_exists(to_name, 'create[%s] failed')
def rename_job(self, name, new_name):
'''
@@ -361,11 +360,10 @@ class Jenkins(object):
:param name: Name of Jenkins job to rename, ``str``
:param new_name: New Jenkins job name, ``str``
'''
self.get_job_info(name)
self.assert_job_exists(name)
self.jenkins_open(Request(
self.server + RENAME_JOB % locals(), ''))
if not self.job_exists(new_name):
raise JenkinsException('rename[%s] failed' % (new_name))
self.assert_job_exists(new_name, 'rename[%s] failed')
def delete_job(self, name):
'''
@@ -373,7 +371,7 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str``
'''
self.get_job_info(name)
self.assert_job_exists(name)
self.jenkins_open(Request(
self.server + DELETE_JOB % locals(), ''))
if self.job_exists(name):
@@ -385,7 +383,7 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str``
'''
self.get_job_info(name)
self.assert_job_exists(name)
self.jenkins_open(Request(
self.server + ENABLE_JOB % locals(), ''))
@@ -395,7 +393,7 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str``
'''
self.get_job_info(name)
self.assert_job_exists(name)
self.jenkins_open(Request(
self.server + DISABLE_JOB % locals(), ''))
@@ -407,6 +405,17 @@ class Jenkins(object):
if self.get_job_name(name) == name:
return True
def assert_job_exists(self, name,
exception_message='job[%s] does not exist'):
'''
:param name: Name of Jenkins job, ``str``
:param exception_message: Message to use for the exception. Formatted
with ``name``
:throws: :class:`JenkinsException` whenever the job does not exist
'''
if not self.job_exists(name):
raise JenkinsException(exception_message % name)
def create_job(self, name, config_xml):
'''
Create a new Jenkins job
@@ -420,8 +429,7 @@ class Jenkins(object):
headers = {'Content-Type': 'text/xml'}
self.jenkins_open(Request(
self.server + CREATE_JOB % locals(), config_xml, headers))
if not self.job_exists(name):
raise JenkinsException('create[%s] failed' % (name))
self.assert_job_exists(name, 'create[%s] failed')
def get_job_config(self, name):
'''
@@ -442,7 +450,7 @@ class Jenkins(object):
:param name: Name of Jenkins job, ``str``
:param config_xml: New XML configuration, ``str``
'''
self.get_job_info(name)
self.assert_job_exists(name)
headers = {'Content-Type': 'text/xml'}
reconfig_url = self.server + CONFIG_JOB % locals()
self.jenkins_open(Request(reconfig_url, config_xml, headers))
@@ -475,8 +483,7 @@ class Jenkins(object):
:param parameters: parameters for job, or ``None``, ``dict``
:param token: Jenkins API token
'''
if not self.job_exists(name):
raise JenkinsException('no such job[%s]' % (name))
self.assert_job_exists(name, 'no such job[%s]')
return self.jenkins_open(Request(
self.build_job_url(name, parameters, token)))

View File

@@ -132,6 +132,27 @@ class JenkinsTest(unittest.TestCase):
jenkins_mock.call_args[0][0].get_full_url(),
'http://example.com/job/TestJob')
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_assert_job_exists__job_missing(self, jenkins_mock):
jenkins_mock.side_effect = [
None,
]
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
with self.assertRaises(jenkins.JenkinsException) as context_manager:
j.assert_job_exists('NonExistent')
self.assertEqual(
str(context_manager.exception),
'job[NonExistent] does not exist')
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_assert_job_exists__job_exists(self, jenkins_mock):
jenkins_mock.side_effect = [
json.dumps({'name': 'ExistingJob'}),
]
j = jenkins.Jenkins('http://example.com/', 'test', 'test')
j.assert_job_exists('ExistingJob')
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_create_job(self, jenkins_mock):
"""