From 570a143c74d092efaf9bc68a3bae9b15804f4a63 Mon Sep 17 00:00:00 2001 From: JP Sullivan Date: Thu, 19 Nov 2020 09:54:18 +0000 Subject: [PATCH] Allow build number to be a string When retreiving data from builds, the build number can have a string portion. This is for matrix jobs that define a label to retrieve one sub-build of the matrix job. The URL structure is: https:///job/>job_name>//label=/ Allowing a string for build number allows for it to be specifed as, e.g.: 1/label=amd64 And whilst being somewhat a workaround, works without introducing complexity and modifying function calls for extra parameters. Change-Id: Ic409df6e20e85d6a417c6490472b3729f1f20cd2 --- jenkins/__init__.py | 62 ++++++++--------- tests/test_build.py | 166 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 159 insertions(+), 69 deletions(-) diff --git a/jenkins/__init__.py b/jenkins/__init__.py index 620ce14..5a4dfd3 100755 --- a/jenkins/__init__.py +++ b/jenkins/__init__.py @@ -117,14 +117,14 @@ RENAME_JOB = '%(from_folder_url)sjob/%(from_short_name)s/doRename?newName=%(to_s BUILD_JOB = '%(folder_url)sjob/%(short_name)s/build' STOP_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/stop' BUILD_WITH_PARAMS_JOB = '%(folder_url)sjob/%(short_name)s/buildWithParameters' -BUILD_INFO = '%(folder_url)sjob/%(short_name)s/%(number)d/api/json?depth=%(depth)s' -BUILD_CONSOLE_OUTPUT = '%(folder_url)sjob/%(short_name)s/%(number)d/consoleText' -BUILD_ENV_VARS = '%(folder_url)sjob/%(short_name)s/%(number)d/injectedEnvVars/api/json' + \ +BUILD_INFO = '%(folder_url)sjob/%(short_name)s/%(number)s/api/json?depth=%(depth)s' +BUILD_CONSOLE_OUTPUT = '%(folder_url)sjob/%(short_name)s/%(number)s/consoleText' +BUILD_ENV_VARS = '%(folder_url)sjob/%(short_name)s/%(number)s/injectedEnvVars/api/json' + \ '?depth=%(depth)s' -BUILD_TEST_REPORT = '%(folder_url)sjob/%(short_name)s/%(number)d/testReport/api/json' + \ +BUILD_TEST_REPORT = '%(folder_url)sjob/%(short_name)s/%(number)s/testReport/api/json' + \ '?depth=%(depth)s' -BUILD_ARTIFACT = '%(folder_url)sjob/%(short_name)s/%(number)d/artifact/%(artifact)s' -BUILD_STAGES = '%(folder_url)sjob/%(short_name)s/%(number)d/wfapi/describe/' +BUILD_ARTIFACT = '%(folder_url)sjob/%(short_name)s/%(number)s/artifact/%(artifact)s' +BUILD_STAGES = '%(folder_url)sjob/%(short_name)s/%(number)s/wfapi/describe/' DELETE_BUILD = '%(folder_url)sjob/%(short_name)s/%(number)s/doDelete' WIPEOUT_JOB_WORKSPACE = '%(folder_url)sjob/%(short_name)s/doWipeOutWorkspace' NODE_LIST = 'computer/api/json?depth=%(depth)s' @@ -633,7 +633,7 @@ class Jenkins(object): '''Get build information dictionary. :param name: Job name, ``str`` - :param number: Build number, ``int`` + :param number: Build number, ``str`` (also accepts ``int``) :param depth: JSON depth, ``int`` :returns: dictionary of build information, ``dict`` @@ -654,22 +654,20 @@ class Jenkins(object): if response: return json.loads(response) else: - raise JenkinsException('job[%s] number[%d] does not exist' + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except (req_exc.HTTPError, NotFoundException): - raise JenkinsException('job[%s] number[%d] does not exist' + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except ValueError: - raise JenkinsException( - 'Could not parse JSON info for job[%s] number[%d]' - % (name, number) - ) + raise JenkinsException('Could not parse JSON info for job[%s] number[%s]' + % (name, number)) def get_build_env_vars(self, name, number, depth=0): '''Get build environment variables. :param name: Job name, ``str`` - :param number: Build number, ``int`` + :param number: Build number, ``str`` (also accepts ``int``) :param depth: JSON depth, ``int`` :returns: dictionary of build env vars, ``dict`` or None for workflow jobs, or if InjectEnvVars plugin not installed @@ -681,12 +679,12 @@ class Jenkins(object): if response: return json.loads(response) else: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except req_exc.HTTPError: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except ValueError: raise JenkinsException( - 'Could not parse JSON info for job[%s] number[%d]' % (name, number)) + 'Could not parse JSON info for job[%s] number[%s]' % (name, number)) except NotFoundException: # This can happen on workflow jobs, or if InjectEnvVars plugin not installed return None @@ -695,7 +693,7 @@ class Jenkins(object): '''Get test results report. :param name: Job name, ``str`` - :param number: Build number, ``int`` + :param number: Build number, ``str`` (also accepts ``int``) :returns: dictionary of test report results, ``dict`` or None if there is no Test Report ''' folder_url, short_name = self._get_job_folder(name) @@ -705,12 +703,12 @@ class Jenkins(object): if response: return json.loads(response) else: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except req_exc.HTTPError: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except ValueError: raise JenkinsException( - 'Could not parse JSON info for job[%s] number[%d]' % (name, number)) + 'Could not parse JSON info for job[%s] number[%s]' % (name, number)) except NotFoundException: # This can happen if the test report wasn't generated for any reason return None @@ -719,7 +717,7 @@ class Jenkins(object): """Get artifacts from job :param name: Job name, ``str`` - :param number: Build number, ``int`` + :param number: Build number, ``str`` (also accepts ``int``) :param artifact: Artifact relative path, ``str`` :returns: artifact to download, ``dict`` """ @@ -732,12 +730,12 @@ class Jenkins(object): if response: return json.loads(response) else: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except requests.exceptions.HTTPError: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except ValueError: raise JenkinsException( - 'Could not parse JSON info for job[%s] number[%d]' % (name, number)) + 'Could not parse JSON info for job[%s] number[%s]' % (name, number)) except NotFoundException: # This can happen if the artifact is not found return None @@ -746,7 +744,7 @@ class Jenkins(object): """Get stages info from job :param name: Job name, ``str`` - :param number: Build number, ``int`` + :param number: Build number, ``str`` (also accepts ``int``) :returns: dictionary of stages in the job, ``dict`` """ folder_url, short_name = self._get_job_folder(name) @@ -758,12 +756,12 @@ class Jenkins(object): if response: return json.loads(response) else: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except requests.exceptions.HTTPError: - raise JenkinsException('job[%s] number[%d] does not exist' % (name, number)) + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except ValueError: raise JenkinsException( - 'Could not parse JSON info for job[%s] number[%d]' % (name, number)) + 'Could not parse JSON info for job[%s] number[%s]' % (name, number)) except NotFoundException: # This can happen if this isn't a stages/pipeline job return None @@ -1707,7 +1705,7 @@ class Jenkins(object): '''Get build console text. :param name: Job name, ``str`` - :param number: Build number, ``int`` + :param number: Build number, ``str`` (also accepts ``int``) :returns: Build console output, ``str`` ''' folder_url, short_name = self._get_job_folder(name) @@ -1718,10 +1716,10 @@ class Jenkins(object): if response: return response else: - raise JenkinsException('job[%s] number[%d] does not exist' + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) except (req_exc.HTTPError, NotFoundException): - raise JenkinsException('job[%s] number[%d] does not exist' + raise JenkinsException('job[%s] number[%s] does not exist' % (name, number)) def _get_job_folder(self, name): diff --git a/tests/test_build.py b/tests/test_build.py index ea3e5b4..acd3a58 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -14,7 +14,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase): 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) + build_info = self.j.get_build_console_output(u'Test Job', number='52') self.assertEqual(build_info, jenkins_mock.return_value) self.assertEqual( @@ -26,7 +26,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase): 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) + 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( @@ -34,11 +34,24 @@ class JenkinsBuildConsoleTest(JenkinsTestBase): 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_matrix(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/label=matrix') + + self.assertEqual(build_info, jenkins_mock.return_value) + self.assertEqual( + jenkins_mock.call_args[0][0].url, + self.make_url('job/a%20Folder/job/Test%20Job/52/label=matrix/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: + # Test with a number for a printing case, to ensure it works self.j.get_build_console_output(u'TestJob', number=52) self.assertEqual( str(context_manager.exception), @@ -50,17 +63,28 @@ class JenkinsBuildConsoleTest(JenkinsTestBase): 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.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_matrix_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/label=matrix') + self.assertEqual( + str(context_manager.exception), + 'job[A Folder/TestJob] number[52/label=matrix] 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) + console_output = self.j.get_build_console_output(u'TestJob', number='52') self.assertEqual(console_output, jenkins_mock.return_value) @patch('jenkins.requests.Session.send') @@ -71,7 +95,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase): ]) 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( session_send_mock.call_args_list[1][0][0].url, self.make_url('job/TestJob/52/consoleText')) @@ -87,6 +111,7 @@ class JenkinsBuildConsoleTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: + # Test with a number for a printing case, to ensure it works self.j.get_build_console_output(u'a Folder/TestJob', number=52) self.assertEqual( session_send_mock.call_args_list[1][0][0].url, @@ -108,7 +133,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase): } jenkins_mock.return_value = json.dumps(build_info_to_return) - build_info = self.j.get_build_info(u'Test Job', number=52) + build_info = self.j.get_build_info(u'Test Job', number='52') self.assertEqual(build_info, build_info_to_return) self.assertEqual( @@ -126,7 +151,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase): } jenkins_mock.return_value = json.dumps(build_info_to_return) - build_info = self.j.get_build_info(u'a Folder/Test Job', number=52) + build_info = self.j.get_build_info(u'a Folder/Test Job', number='52') self.assertEqual(build_info, build_info_to_return) self.assertEqual( @@ -134,12 +159,30 @@ class JenkinsBuildInfoTest(JenkinsTestBase): 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_matrix(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/label=matrix') + + self.assertEqual(build_info, build_info_to_return) + self.assertEqual( + jenkins_mock.call_args[0][0].url, + self.make_url('job/a%20Folder/job/Test%20Job/52/label=matrix/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.j.get_build_info(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'job[TestJob] number[52] does not exist') @@ -150,6 +193,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase): jenkins_mock.return_value = 'Invalid JSON' with self.assertRaises(jenkins.JenkinsException) as context_manager: + # Test with a number for a printing case, to ensure it works self.j.get_build_info(u'TestJob', number=52) self.assertEqual( str(context_manager.exception), @@ -164,7 +208,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase): ]) 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( str(context_manager.exception), 'job[TestJob] number[52] does not exist') @@ -177,7 +221,7 @@ class JenkinsBuildInfoTest(JenkinsTestBase): ]) 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( str(context_manager.exception), 'job[a Folder/TestJob] number[52] does not exist') @@ -187,7 +231,7 @@ 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.j.stop_build(u'Test Job', number='52') self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -197,7 +241,7 @@ class JenkinsStopBuildTest(JenkinsTestBase): @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.j.stop_build(u'a Folder/Test Job', number='52') self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -209,7 +253,7 @@ class JenkinsDeleteBuildTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_simple(self, jenkins_mock): - self.j.delete_build(u'Test Job', number=52) + self.j.delete_build(u'Test Job', number='52') self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -219,7 +263,7 @@ class JenkinsDeleteBuildTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_in_folder(self, jenkins_mock): - self.j.delete_build(u'a Folder/Test Job', number=52) + self.j.delete_build(u'a Folder/Test Job', number='52') self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -496,7 +540,7 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_simple(self, jenkins_mock): jenkins_mock.return_value = '{}' - ret = self.j.get_build_env_vars(u'Test Job', number=52, depth=1) + ret = self.j.get_build_env_vars(u'Test Job', number='52', depth=1) self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -506,6 +550,7 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_in_folder(self, jenkins_mock): jenkins_mock.return_value = '{}' + # Test with a number to ensure it works as well as string ret = self.j.get_build_env_vars(u'a Folder/Test Job', number=52, depth=1) self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( @@ -513,13 +558,24 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): self.make_url('job/a%20Folder/job/Test%20Job/52/injectedEnvVars/api/json?depth=1')) self._check_requests(jenkins_mock.call_args_list) + @patch.object(jenkins.Jenkins, 'jenkins_open') + def test_matrix(self, jenkins_mock): + jenkins_mock.return_value = '{}' + ret = self.j.get_build_env_vars(u'a Folder/Test Job', number='52/index=matrix', depth=1) + self.assertEqual(ret, json.loads(jenkins_mock.return_value)) + self.assertEqual( + jenkins_mock.call_args[0][0].url, + self.make_url( + 'job/a%20Folder/job/Test%20Job/52/index=matrix/injectedEnvVars/api/json?depth=1')) + self._check_requests(jenkins_mock.call_args_list) + @patch('jenkins.requests.Session.send', autospec=True) def test_return_none(self, session_send_mock): session_send_mock.side_effect = iter([ build_response_mock(404, reason="Not Found"), # crumb build_response_mock(404, reason="Not Found"), # request ]) - ret = self.j.get_build_env_vars(u'TestJob', number=52) + ret = self.j.get_build_env_vars(u'TestJob', number='52') self.assertIsNone(ret) @patch.object(jenkins.Jenkins, 'jenkins_open') @@ -527,7 +583,7 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): jenkins_mock.return_value = None with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_env_vars(u'TestJob', number=52) + self.j.get_build_env_vars(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'job[TestJob] number[52] does not exist') @@ -538,7 +594,7 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): jenkins_mock.return_value = 'Invalid JSON' with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_env_vars(u'TestJob', number=52) + self.j.get_build_env_vars(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Could not parse JSON info for job[TestJob] number[52]') @@ -552,6 +608,7 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: + # Test with a number for a printing case, to ensure it works self.j.get_build_env_vars(u'TestJob', number=52) self.assertEqual( str(context_manager.exception), @@ -565,7 +622,7 @@ class JenkinsBuildEnvVarUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_env_vars(u'a Folder/TestJob', number=52) + self.j.get_build_env_vars(u'a Folder/TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Error in request. Possibly authentication failed [401]: Not Authorised') @@ -576,7 +633,7 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_simple(self, jenkins_mock): jenkins_mock.return_value = '{}' - ret = self.j.get_build_test_report(u'Test Job', number=52, depth=1) + ret = self.j.get_build_test_report(u'Test Job', number='52', depth=1) self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -586,6 +643,7 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_in_folder(self, jenkins_mock): jenkins_mock.return_value = '{}' + # Test with a number to ensure it works as well as string ret = self.j.get_build_test_report(u'a Folder/Test Job', number=52, depth=1) self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( @@ -593,13 +651,24 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): self.make_url('job/a%20Folder/job/Test%20Job/52/testReport/api/json?depth=1')) self._check_requests(jenkins_mock.call_args_list) + @patch.object(jenkins.Jenkins, 'jenkins_open') + def test_matrix(self, jenkins_mock): + jenkins_mock.return_value = '{}' + ret = self.j.get_build_test_report(u'a Folder/Test Job', number='52/index=matrix', depth=1) + self.assertEqual(ret, json.loads(jenkins_mock.return_value)) + self.assertEqual( + jenkins_mock.call_args[0][0].url, + self.make_url( + 'job/a%20Folder/job/Test%20Job/52/index=matrix/testReport/api/json?depth=1')) + self._check_requests(jenkins_mock.call_args_list) + @patch('jenkins.requests.Session.send', autospec=True) def test_return_none(self, session_send_mock): session_send_mock.side_effect = iter([ build_response_mock(404, reason="Not Found"), # crumb build_response_mock(404, reason="Not Found"), # request ]) - ret = self.j.get_build_test_report(u'TestJob', number=52) + ret = self.j.get_build_test_report(u'TestJob', number='52') self.assertIsNone(ret) @patch.object(jenkins.Jenkins, 'jenkins_open') @@ -607,7 +676,7 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): jenkins_mock.return_value = None with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_test_report(u'TestJob', number=52) + self.j.get_build_test_report(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'job[TestJob] number[52] does not exist') @@ -618,7 +687,7 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): jenkins_mock.return_value = 'Invalid JSON' with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_test_report(u'TestJob', number=52) + self.j.get_build_test_report(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Could not parse JSON info for job[TestJob] number[52]') @@ -632,7 +701,7 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_test_report(u'TestJob', number=52) + self.j.get_build_test_report(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Error in request. Possibly authentication failed [401]: Not Authorised') @@ -645,6 +714,7 @@ class JenkinsBuildTestReportUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: + # Test with a number for a printing case, to ensure it works self.j.get_build_test_report(u'a Folder/TestJob', number=52) self.assertEqual( str(context_manager.exception), @@ -656,7 +726,7 @@ class JenkinsBuildArtifactUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_simple(self, jenkins_mock): jenkins_mock.return_value = '{}' - ret = self.j.get_build_artifact(u'Test Job', number=52, artifact="filename") + ret = self.j.get_build_artifact(u'Test Job', number='52', artifact="filename") self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -666,20 +736,31 @@ class JenkinsBuildArtifactUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_in_folder(self, jenkins_mock): jenkins_mock.return_value = '{}' - ret = self.j.get_build_artifact(u'a Folder/Test Job', number=52, artifact="file name") + ret = self.j.get_build_artifact(u'a Folder/Test Job', number='52', artifact="file name") self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( jenkins_mock.call_args[0][0].url, self.make_url('job/a%20Folder/job/Test%20Job/52/artifact/file%20name')) self._check_requests(jenkins_mock.call_args_list) + @patch.object(jenkins.Jenkins, 'jenkins_open') + def test_matrix(self, jenkins_mock): + jenkins_mock.return_value = '{}' + ret = self.j.get_build_artifact(u'a Folder/Test Job', number='52/index=matrix', + artifact="file name") + self.assertEqual(ret, json.loads(jenkins_mock.return_value)) + self.assertEqual( + jenkins_mock.call_args[0][0].url, + self.make_url('job/a%20Folder/job/Test%20Job/52/index=matrix/artifact/file%20name')) + self._check_requests(jenkins_mock.call_args_list) + @patch('jenkins.requests.Session.send', autospec=True) def test_return_none(self, session_send_mock): session_send_mock.side_effect = iter([ build_response_mock(404, reason="Not Found"), # crumb build_response_mock(404, reason="Not Found"), # request ]) - ret = self.j.get_build_artifact(u'TestJob', number=52, artifact="filename") + ret = self.j.get_build_artifact(u'TestJob', number='52', artifact="filename") self.assertIsNone(ret) @patch.object(jenkins.Jenkins, 'jenkins_open') @@ -687,7 +768,7 @@ class JenkinsBuildArtifactUrlTest(JenkinsTestBase): jenkins_mock.return_value = None with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_artifact(u'TestJob', number=52, artifact="filename") + self.j.get_build_artifact(u'TestJob', number='52', artifact="filename") self.assertEqual( str(context_manager.exception), 'job[TestJob] number[52] does not exist') @@ -698,7 +779,7 @@ class JenkinsBuildArtifactUrlTest(JenkinsTestBase): jenkins_mock.return_value = 'Invalid JSON' with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_artifact(u'TestJob', number=52, artifact="filename") + self.j.get_build_artifact(u'TestJob', number='52', artifact="filename") self.assertEqual( str(context_manager.exception), 'Could not parse JSON info for job[TestJob] number[52]') @@ -712,7 +793,7 @@ class JenkinsBuildArtifactUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_artifact(u'TestJob', number=52, artifact="filename") + self.j.get_build_artifact(u'TestJob', number='52', artifact="filename") self.assertEqual( str(context_manager.exception), 'Error in request. Possibly authentication failed [401]: Not Authorised') @@ -725,7 +806,7 @@ class JenkinsBuildArtifactUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_artifact(u'a Folder/TestJob', number=52, artifact="filename") + self.j.get_build_artifact(u'a Folder/TestJob', number='52', artifact="filename") self.assertEqual( str(context_manager.exception), 'Error in request. Possibly authentication failed [401]: Not Authorised') @@ -736,17 +817,27 @@ class JenkinsBuildStagesUrlTest(JenkinsTestBase): @patch.object(jenkins.Jenkins, 'jenkins_open') def test_simple(self, jenkins_mock): jenkins_mock.return_value = '{}' - ret = self.j.get_build_stages(u'Test Job', number=52) + ret = self.j.get_build_stages(u'Test Job', number='52') self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( jenkins_mock.call_args[0][0].url, self.make_url('job/Test%20Job/52/wfapi/describe/')) self._check_requests(jenkins_mock.call_args_list) + @patch.object(jenkins.Jenkins, 'jenkins_open') + def test_matrix(self, jenkins_mock): + jenkins_mock.return_value = '{}' + ret = self.j.get_build_stages(u'a Folder/Test Job', number='52/index=matrix') + self.assertEqual(ret, json.loads(jenkins_mock.return_value)) + self.assertEqual( + jenkins_mock.call_args[0][0].url, + self.make_url('job/a%20Folder/job/Test%20Job/52/index=matrix/wfapi/describe/')) + 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 = '{}' - ret = self.j.get_build_stages(u'a Folder/Test Job', number=52) + ret = self.j.get_build_stages(u'a Folder/Test Job', number='52') self.assertEqual(ret, json.loads(jenkins_mock.return_value)) self.assertEqual( jenkins_mock.call_args[0][0].url, @@ -759,7 +850,7 @@ class JenkinsBuildStagesUrlTest(JenkinsTestBase): build_response_mock(404, reason="Not Found"), # crumb build_response_mock(404, reason="Not Found"), # request ]) - ret = self.j.get_build_stages(u'TestJob', number=52) + ret = self.j.get_build_stages(u'TestJob', number='52') self.assertIsNone(ret) @patch.object(jenkins.Jenkins, 'jenkins_open') @@ -767,6 +858,7 @@ class JenkinsBuildStagesUrlTest(JenkinsTestBase): jenkins_mock.return_value = None with self.assertRaises(jenkins.JenkinsException) as context_manager: + # Test with a number for a printing case, to ensure it works self.j.get_build_stages(u'TestJob', number=52) self.assertEqual( str(context_manager.exception), @@ -778,7 +870,7 @@ class JenkinsBuildStagesUrlTest(JenkinsTestBase): jenkins_mock.return_value = 'Invalid JSON' with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_stages(u'TestJob', number=52) + self.j.get_build_stages(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Could not parse JSON info for job[TestJob] number[52]') @@ -792,7 +884,7 @@ class JenkinsBuildStagesUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_stages(u'TestJob', number=52) + self.j.get_build_stages(u'TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Error in request. Possibly authentication failed [401]: Not Authorised') @@ -805,7 +897,7 @@ class JenkinsBuildStagesUrlTest(JenkinsTestBase): ]) with self.assertRaises(jenkins.JenkinsException) as context_manager: - self.j.get_build_stages(u'a Folder/TestJob', number=52) + self.j.get_build_stages(u'a Folder/TestJob', number='52') self.assertEqual( str(context_manager.exception), 'Error in request. Possibly authentication failed [401]: Not Authorised')