Files
python-jenkins/tests/test_build.py
grahamlyons 106048dd87 Fix error thrown in presence of placeholder tasks
When there are placeholder tasks in an executor for a node then there is no
build number yet assigned and attempting to access that key in the dictionary
will fail.

This fix filters out any tasks which are instances of that class before
proceeding.

Change-Id: Ie5b237c3e6023c1822f91e5982ec84f1a363130c
Closes-Bug: #1659787
2017-02-09 16:30:52 +00:00

457 lines
16 KiB
Python

import json
from mock import patch
import jenkins
from tests.base import JenkinsTestBase
class JenkinsBuildConsoleTest(JenkinsTestBase):
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_simple(self, jenkins_mock):
jenkins_mock.return_value = "build console output..."
build_info = self.j.get_build_console_output(u'Test Job', number=52)
self.assertEqual(build_info, jenkins_mock.return_value)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/Test%20Job/52/consoleText'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_in_folder(self, jenkins_mock):
jenkins_mock.return_value = "build console output..."
build_info = self.j.get_build_console_output(u'a Folder/Test Job', number=52)
self.assertEqual(build_info, jenkins_mock.return_value)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/a%20Folder/job/Test%20Job/52/consoleText'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_none(self, jenkins_mock):
jenkins_mock.return_value = None
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_console_output(u'TestJob', number=52)
self.assertEqual(
str(context_manager.exception),
'job[TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_in_folder_return_none(self, jenkins_mock):
jenkins_mock.return_value = None
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_console_output(u'A Folder/TestJob', number=52)
self.assertEqual(
str(context_manager.exception),
'job[A Folder/TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_invalid_json(self, jenkins_mock):
jenkins_mock.return_value = 'Invalid JSON'
console_output = self.j.get_build_console_output(u'TestJob', number=52)
self.assertEqual(console_output, jenkins_mock.return_value)
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_raise_HTTPError(self, jenkins_mock):
jenkins_mock.side_effect = jenkins.HTTPError(
self.make_url('job/TestJob/52/consoleText'),
code=401,
msg="basic auth failed",
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_console_output(u'TestJob', number=52)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/TestJob/52/consoleText'))
self.assertEqual(
str(context_manager.exception),
'job[TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_in_folder_raise_HTTPError(self, jenkins_mock):
jenkins_mock.side_effect = jenkins.HTTPError(
self.make_url('job/a%20Folder/job/TestJob/52/consoleText'),
code=401,
msg="basic auth failed",
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_console_output(u'a Folder/TestJob', number=52)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/a%20Folder/job/TestJob/52/consoleText'))
self.assertEqual(
str(context_manager.exception),
'job[a Folder/TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsBuildInfoTest(JenkinsTestBase):
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_simple(self, jenkins_mock):
build_info_to_return = {
u'building': False,
u'msg': u'test',
u'revision': 66,
u'user': u'unknown'
}
jenkins_mock.return_value = json.dumps(build_info_to_return)
build_info = self.j.get_build_info(u'Test Job', number=52)
self.assertEqual(build_info, build_info_to_return)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/Test%20Job/52/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_in_folder(self, jenkins_mock):
build_info_to_return = {
u'building': False,
u'msg': u'test',
u'revision': 66,
u'user': u'unknown'
}
jenkins_mock.return_value = json.dumps(build_info_to_return)
build_info = self.j.get_build_info(u'a Folder/Test Job', number=52)
self.assertEqual(build_info, build_info_to_return)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/a%20Folder/job/Test%20Job/52/api/json?depth=0'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_none(self, jenkins_mock):
jenkins_mock.return_value = None
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_info(u'TestJob', number=52)
self.assertEqual(
str(context_manager.exception),
'job[TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_return_invalid_json(self, jenkins_mock):
jenkins_mock.return_value = 'Invalid JSON'
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_info(u'TestJob', number=52)
self.assertEqual(
str(context_manager.exception),
'Could not parse JSON info for job[TestJob] number[52]')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_raise_HTTPError(self, jenkins_mock):
jenkins_mock.side_effect = jenkins.HTTPError(
self.make_url('job/TestJob/api/json?depth=0'),
code=401,
msg="basic auth failed",
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_info(u'TestJob', number=52)
self.assertEqual(
str(context_manager.exception),
'job[TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_in_folder_raise_HTTPError(self, jenkins_mock):
jenkins_mock.side_effect = jenkins.HTTPError(
self.make_url('job/a%20Folder/job/TestJob/api/json?depth=0'),
code=401,
msg="basic auth failed",
hdrs=[],
fp=None)
with self.assertRaises(jenkins.JenkinsException) as context_manager:
self.j.get_build_info(u'a Folder/TestJob', number=52)
self.assertEqual(
str(context_manager.exception),
'job[a Folder/TestJob] number[52] does not exist')
self._check_requests(jenkins_mock.call_args_list)
class JenkinsStopBuildTest(JenkinsTestBase):
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_simple(self, jenkins_mock):
self.j.stop_build(u'Test Job', number=52)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/Test%20Job/52/stop'))
self._check_requests(jenkins_mock.call_args_list)
@patch.object(jenkins.Jenkins, 'jenkins_open')
def test_in_folder(self, jenkins_mock):
self.j.stop_build(u'a Folder/Test Job', number=52)
self.assertEqual(
jenkins_mock.call_args[0][0].get_full_url(),
self.make_url('job/a%20Folder/job/Test%20Job/52/stop'))
self._check_requests(jenkins_mock.call_args_list)
class JenkinsListRunningBuildsTest(JenkinsTestBase):
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_with_builds_master(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "master", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
build = {
"actions": [
{
"parameters": [
{
"name": "FOO",
"value": "foo"
},
{
"name": "BAR",
"value": "bar"
}
]
},
{
"causes": [
{
"shortDescription": "Started by user foo",
"userId": "foo",
"userName": "Foo Bar"
}
]
}
],
"artifacts": [],
"building": True,
"description": None,
"duration": 0,
"estimatedDuration": 20148,
"executor": {},
"fullDisplayName": "test #1",
"id": "2015-09-14_20-25-42",
"keepLog": False,
"number": 1,
"result": None,
"timestamp": 1442262342729,
"url": self.make_url('job/test/1/'),
"builtOn": "",
"changeSet": {
"items": [],
"kind": None
},
"culprits": []
}
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 0,
"progress": -1
},
{
"currentExecutable": build,
"currentWorkUnit": {},
"idle": False,
"likelyStuck": False,
"number": 1,
"progress": 14
}
],
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([{'name': 'test',
'number': 1,
'node': '(master)',
'executor': 1,
'url': self.make_url('job/test/1/')}], builds)
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_with_builds_non_master(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "foo-slave", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
build = {
"actions": [
{
"parameters": [
{
"name": "FOO",
"value": "foo"
},
{
"name": "BAR",
"value": "bar"
}
]
},
{
"causes": [
{
"shortDescription": "Started by user foo",
"userId": "foo",
"userName": "Foo Bar"
}
]
}
],
"artifacts": [],
"building": True,
"description": None,
"duration": 0,
"estimatedDuration": 20148,
"executor": {},
"fullDisplayName": "test #1",
"id": "2015-09-14_20-25-42",
"keepLog": False,
"number": 15,
"result": None,
"timestamp": 1442262342729,
"url": self.make_url("job/test/15/"),
"builtOn": "",
"changeSet": {
"items": [],
"kind": None
},
"culprits": []
}
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 1,
"progress": -1
},
{
"currentExecutable": build,
"currentWorkUnit": {},
"idle": False,
"likelyStuck": False,
"number": 0,
"progress": 14
}
],
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([{'name': 'test',
'number': 15,
'node': 'foo-slave',
'executor': 0,
'url': self.make_url('job/test/15/')}], builds)
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_with_no_builds(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "master", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 0,
"progress": -1
}
]
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([], builds)
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_broken_slave(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "foo-slave", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
def side_effect(*args, **kwargs):
if 'depth' in kwargs and kwargs['depth'] > 0:
raise jenkins.JenkinsException(
"Error in request. Possibly authentication failed"
"[500]: Server Error")
else:
return {"success": True}
node_info_mock.side_effect = side_effect
builds = self.j.get_running_builds()
# Should treat the slave as not running any builds
self.assertEqual([], builds)
@patch.object(jenkins.Jenkins, 'get_node_info')
@patch.object(jenkins.Jenkins, 'get_nodes')
def test_placeholder_task_in_queue(self, nodes_mock, node_info_mock):
nodes_to_return = [{
'name': "foo-slave", 'offline': False
}]
nodes_mock.return_value = nodes_to_return
node_info_to_return = {
"executors": [
{
"currentExecutable": None,
"currentWorkUnit": None,
"idle": True,
"likelyStuck": False,
"number": 1,
"progress": -1
},
{
'currentExecutable': {
'_class': (
'org.jenkinsci.plugins.workflow.support.steps.'
'ExecutorStepExecution$PlaceholderTask$'
'PlaceholderExecutable'
)
},
'currentWorkUnit': {},
'idle': False,
'likelyStuck': False,
'number': 1,
'progress': 0
}
],
}
node_info_mock.return_value = node_info_to_return
builds = self.j.get_running_builds()
self.assertEqual([], builds)