0d7b59f5d2
When the server has an URL path such as http://example.org/ci/, the
get_running_builds() would fail to extract the job name from the
executor informations. It most probably fails when using CloudBees
folder as well.
Relax the regex used to detect the job name by changing match() with
search().
Update JenkinsListRunningBuildsTest so it craft the URLs based on the
test scenario (make_url) instead of hardcoding them. That would have
caught the bug. See 2aa1a5f1
which introduced the scenarios.
Signed-off-by: Antoine Musso <hashar@free.fr>
Change-Id: I1b69adf121ee74e3336ac9bd1d4d55797fb72de5
420 lines
15 KiB
Python
420 lines
15 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)
|