diff --git a/tests/test_cli/test_clone_tag.py b/tests/test_cli/test_clone_tag.py index 95f99f79..72a86848 100644 --- a/tests/test_cli/test_clone_tag.py +++ b/tests/test_cli/test_clone_tag.py @@ -44,7 +44,9 @@ clone-tag will create the destination tag if it does not already exist args, stderr=self.format_error_message( "This command takes two arguments: "), - activate_session=None) + activate_session=None, + exit_code=2 + ) self.activate_session.assert_not_called() def test_handle_clone_tag_not_admin(self): @@ -55,9 +57,10 @@ clone-tag will create the destination tag if it does not already exist self.options, self.session, args, - stderr=self.format_error_message( - "This action requires tag or admin privileges"), - activate_session=None) + stderr=self.format_error_message("This action requires tag or admin privileges"), + activate_session=None, + exit_code=2 + ) self.activate_session.assert_called_once() self.session.hasPerm.assert_has_calls([call('admin'), call('tag')]) @@ -68,9 +71,9 @@ clone-tag will create the destination tag if it does not already exist self.options, self.session, args, - stderr=self.format_error_message( - "Source and destination tags must be different."), - activate_session=None) + stderr=self.format_error_message("Source and destination tags must be different."), + activate_session=None, + exit_code=2) self.activate_session.assert_called_once() def test_handle_clone_tag_invalid_batch(self): @@ -80,9 +83,9 @@ clone-tag will create the destination tag if it does not already exist self.options, self.session, args, - stderr=self.format_error_message( - "batch size must be bigger than zero"), - activate_session=None) + stderr=self.format_error_message("batch size must be bigger than zero"), + activate_session=None, + exit_code=2) self.activate_session.assert_called_once() def test_handle_clone_tag_no_srctag(self): @@ -94,17 +97,15 @@ clone-tag will create the destination tag if it does not already exist self.session, args, stderr=self.format_error_message("No such src-tag: src-tag"), - activate_session=None) + activate_session=None, + exit_code=2) self.activate_session.assert_called_once() - self.activate_session.getTag.has_called([call('src-tag'), - call('dst-tag')]) + self.activate_session.getTag.has_called([call('src-tag'), call('dst-tag')]) def test_handle_clone_tag_locked(self): args = ['src-tag', 'dst-tag'] - self.session.getTag.side_effect = [{'id': 1, - 'locked': True}, - {'id': 2, - 'locked': False}] + self.session.getTag.side_effect = [{'id': 1, 'locked': True}, + {'id': 2, 'locked': False}] self.assert_system_exit( handle_clone_tag, self.options, @@ -113,13 +114,12 @@ clone-tag will create the destination tag if it does not already exist stderr=self.format_error_message( "Error: You are attempting to clone from or to a tag which is locked.\n" "Please use --force if this is what you really want to do."), - activate_session=None) + activate_session=None, + exit_code=2) self.activate_session.assert_called_once() - self.activate_session.getTag.has_called([call('src-tag'), - call('dst-tag')]) + self.activate_session.getTag.has_called([call('src-tag'), call('dst-tag')]) - self.activate_session.getTag.has_called([call('src-tag'), - call('dst-tag')]) + self.activate_session.getTag.has_called([call('src-tag'), call('dst-tag')]) @mock.patch('sys.stdout', new_callable=six.StringIO) def test_handle_clone_tag_new_dsttag(self, stdout): diff --git a/tests/test_cli/test_disable_channel.py b/tests/test_cli/test_disable_channel.py index c34b87a7..a0aeaf79 100644 --- a/tests/test_cli/test_disable_channel.py +++ b/tests/test_cli/test_disable_channel.py @@ -15,6 +15,10 @@ class TestDisableChannel(utils.CliTestCase): maxDiff = None def setUp(self): + self.options = mock.MagicMock() + self.options.quiet = False + self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s disable-channel [options] [ ...] (Specify the --help global option for a list of other help options) @@ -33,70 +37,62 @@ class TestDisableChannel(utils.CliTestCase): m._result = (result,) return m - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_disable_channel(self, activate_session_mock, stdout, stderr): + def test_handle_disable_channel_no_such_channel(self): """Test disable-channel function""" - options = mock.MagicMock() - session = mock.MagicMock() - - mcall = session.multicall.return_value.__enter__.return_value - + mcall = self.session.multicall.return_value.__enter__.return_value mcall.getChannel.return_value = self.__vm(None) arguments = ['test-channel'] - with self.assertRaises(SystemExit) as ex: - handle_disable_channel(options, session, arguments) - self.assertExitCode(ex, 1) - activate_session_mock.assert_called_once() - session.multicall.assert_called_once() - session.disableChannel.assert_not_called() expect = '' for host in arguments: expect += "No such channel: %s\n" % host stderr_exp = "No changes made. Please correct the command line.\n" - self.assert_console_message(stdout, expect) - self.assert_console_message(stderr, stderr_exp) + self.assert_system_exit( + handle_disable_channel, + self.options, self.session, arguments, + stdout=expect, + stderr=stderr_exp, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once() + self.session.multicall.assert_called_once() + self.session.disableChannel.assert_not_called() - # reset session mocks - activate_session_mock.reset_mock() - session.disableChannel.reset_mock() - session.multicall.reset_mock() - mcall = session.multicall.return_value.__enter__.return_value + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_disable_channel_valid(self, stdout): + """Test disable-channel function""" + mcall = self.session.multicall.return_value.__enter__.return_value mcall.getChannel.return_value = self.__vm(self.channelinfo) arguments = ['test-channel', '--comment', 'enable channel test'] - handle_disable_channel(options, session, arguments) - activate_session_mock.assert_called_once() - self.assertEqual(2, session.multicall.call_count) + handle_disable_channel(self.options, self.session, arguments) + self.activate_session_mock.assert_called_once() + self.assertEqual(2, self.session.multicall.call_count) self.assert_console_message(stdout, '') - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_disable_host_no_argument(self, activate_session_mock, stdout): + def test_handle_disable_host_no_argument(self): """Test disable-channel function without arguments""" - options = mock.MagicMock() - session = mock.MagicMock() - - session.getChannel.return_value = None - session.multicall.return_value = [[None]] - session.disableChannel.return_value = True + self.session.getChannel.return_value = None + self.session.multicall.return_value = [[None]] + self.session.disableChannel.return_value = True expected = self.format_error_message("At least one channel must be specified") self.assert_system_exit( handle_disable_channel, - options, - session, + self.options, + self.session, [], stderr=expected, - activate_session=None) + activate_session=None, + exit_code=2 + ) - activate_session_mock.assert_not_called() - session.getChannel.assert_not_called() - session.multicall.assert_not_called() - session.disableChannel.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.getChannel.assert_not_called() + self.session.multicall.assert_not_called() + self.session.disableChannel.assert_not_called() def test_handle_disable_channel_help(self): """Test disable-channel help message""" diff --git a/tests/test_cli/test_disable_host.py b/tests/test_cli/test_disable_host.py index dec5afb5..1dbc154e 100644 --- a/tests/test_cli/test_disable_host.py +++ b/tests/test_cli/test_disable_host.py @@ -10,33 +10,22 @@ from . import utils class TestDisableHost(utils.CliTestCase): - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.options = mock.MagicMock() + self.options.quiet = False + self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s disable-host [options] [ ...] (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) - - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_disable_host( - self, - activate_session_mock, - stdout, - stderr): + def test_handle_disable_host_no_such_host(self): """Test %s function""" % handle_disable_host.__name__ - arguments = [] - options = mock.MagicMock() - session = mock.MagicMock() - - session.getHost.return_value = None - session.disableHost.return_value = True - session.editHost.return_value = True + self.session.getHost.return_value = None + self.session.disableHost.return_value = True + self.session.editHost.return_value = True # # session.multiCall returns: @@ -55,70 +44,66 @@ class TestDisableHost(utils.CliTestCase): # 'name': 'kbuilder02' ...}] # - session.multiCall.return_value = [[None], [None]] - + self.session.multiCall.return_value = [[None], [None]] arguments = ['host1', 'host2'] - with self.assertRaises(SystemExit) as ex: - handle_disable_host(options, session, arguments) - self.assertExitCode(ex, 1) - activate_session_mock.assert_called_once() - session.getHost.assert_has_calls([call('host1'), call('host2')]) - session.multiCall.assert_called_once() - session.disableHost.assert_not_called() - session.editHost.assert_not_called() expect = '' for host in arguments: expect += "No such host: %s\n" % host - self.assert_console_message(stdout, expect) - self.assert_console_message(stderr, "No changes made. Please correct the command line.\n") + stderr_exp = "No changes made. Please correct the command line.\n" + self.assert_system_exit( + handle_disable_host, + self.options, self.session, arguments, + stdout=expect, + stderr=stderr_exp, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once() + self.session.getHost.assert_has_calls([call('host1'), call('host2')]) + self.session.multiCall.assert_called_once() + self.session.disableHost.assert_not_called() + self.session.editHost.assert_not_called() - # reset session mocks - activate_session_mock.reset_mock() - session.multiCall.reset_mock() - session.disableHost.reset_mock() - session.editHost.reset_mock() - - session.multiCall.return_value = [ + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_disable_host_valid(self, stdout): + self.session.multiCall.return_value = [ [{'id': 1, 'name': 'host1'}], [{'id': 2, 'name': 'host2'}] ] arguments = ['host1', 'host2', '--comment', 'disable host test'] - handle_disable_host(options, session, arguments) - activate_session_mock.assert_called_once() - session.getHost.assert_has_calls([call('host1'), call('host2')]) - self.assertEqual(2, session.multiCall.call_count) - session.disableHost.assert_has_calls([call('host1'), call('host2')]) - session.editHost.assert_has_calls( + handle_disable_host(self.options, self.session, arguments) + self.activate_session_mock.assert_called_once() + self.session.getHost.assert_has_calls([call('host1'), call('host2')]) + self.assertEqual(2, self.session.multiCall.call_count) + self.session.disableHost.assert_has_calls([call('host1'), call('host2')]) + self.session.editHost.assert_has_calls( [call('host1', comment='disable host test'), call('host2', comment='disable host test')]) self.assert_console_message(stdout, '') - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_disable_host_no_argument(self, activate_session_mock, stdout): + def test_handle_disable_host_no_argument(self): """Test %s function without arguments""" % handle_disable_host.__name__ - options = mock.MagicMock() - session = mock.MagicMock() - - session.getHost.return_value = None - session.multiCall.return_value = [[None]] - session.disableHost.return_value = True - session.editHost.return_value = True + self.session.getHost.return_value = None + self.session.multiCall.return_value = [[None]] + self.session.disableHost.return_value = True + self.session.editHost.return_value = True expected = self.format_error_message("At least one host must be specified") self.assert_system_exit( handle_disable_host, - options, - session, + self.options, + self.session, [], stderr=expected, - activate_session=None) + activate_session=None, + exit_code=2 + ) - activate_session_mock.assert_not_called() - session.getHost.assert_not_called() - session.multiCall.assert_not_called() - session.disableHost.assert_not_called() - session.editHost.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.getHost.assert_not_called() + self.session.multiCall.assert_not_called() + self.session.disableHost.assert_not_called() + self.session.editHost.assert_not_called() def test_handle_disable_host_help(self): """Test %s help message""" % handle_disable_host.__name__ diff --git a/tests/test_cli/test_disable_user.py b/tests/test_cli/test_disable_user.py index 2e02ee64..ff54eecb 100644 --- a/tests/test_cli/test_disable_user.py +++ b/tests/test_cli/test_disable_user.py @@ -13,49 +13,53 @@ class TestDisableUser(utils.CliTestCase): maxDiff = None def setUp(self): + self.options = mock.MagicMock() + self.options.quiet = False + self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.username = 'user' self.error_format = """Usage: %s disable-user (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_disable_user( - self, - activate_session_mock, - stdout): + def test_handle_disable_user_no_argument(self): """Test handle_disable_user function""" - session = mock.MagicMock() - options = mock.MagicMock() - username = 'user' - - # Case 1. no argument error expected = self.format_error_message( "You must specify the username of the user to disable") self.assert_system_exit( handle_disable_user, - options, - session, + self.options, + self.session, [], stderr=expected, - activate_session=None) + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() - # Case 2. Too many argument error + def test_handle_disable_user_many_arguments(self): + """Test handle_disable_user function""" expected = self.format_error_message( "This command only accepts one argument (username)") self.assert_system_exit( handle_disable_user, - options, - session, + self.options, + self.session, ['user-1', 'user-2', 'user-3'], stderr=expected, - activate_session=None) + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() - # Case 3. Disable user test - handle_disable_user(options, session, [username]) - session.disableUser.assert_called_with(username) - activate_session_mock.assert_called_with(session, options) + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_disable_user_valid(self, stdout): + handle_disable_user(self.options, self.session, [self.username]) + self.session.disableUser.assert_called_with(self.username) + self.activate_session_mock.assert_called_with(self.session, self.options) + self.assert_console_message(stdout, '') def test_handle_disable_user_help(self): self.assert_help( diff --git a/tests/test_cli/test_download_build.py b/tests/test_cli/test_download_build.py index 3202cff8..3512b408 100644 --- a/tests/test_cli/test_download_build.py +++ b/tests/test_cli/test_download_build.py @@ -14,6 +14,11 @@ class TestDownloadBuild(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.error_format = """Usage: %s download-build [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) self.build_templ = { 'package_name': 'bash', @@ -37,19 +42,46 @@ class TestDownloadBuild(utils.CliTestCase): 'size': 7030, 'nvr': 'test-rpm-1.1-11' } + self.listbuilds = [{'build_id': 1, + 'epoch': 17, + 'extra': None, + 'name': 'test-build', + 'nvr': 'test-build-1-11.f35', + 'owner_id': 1, + 'owner_name': 'testuser', + 'package_id': 4, + 'package_name': 'test-build', + 'release': '11.f35', + 'state': 1, + 'task_id': 3, + 'version': '1', }] self.sigkey = 'testkey' self.tag = 'test-tag' - @mock.patch('sys.stderr', new_callable=StringIO) - def test_download_build_without_option(self, stderr): - expected = "Usage: %s download-build [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: Please specify a package N-V-R or build ID\n" \ - % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_download_build(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + def test_download_build_without_argument(self): + expected = self.format_error_message("Please specify a package N-V-R or build ID") + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + [], + stderr=expected, + activate_session=None, + exit_code=2 + ) + + def test_download_build_more_arguments(self): + expected = self.format_error_message( + "Only a single package N-V-R or build ID may be specified") + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + ['1', '2'], + stderr=expected, + activate_session=None, + exit_code=2 + ) def __vm(self, result): m = koji.VirtualCall('mcall_method', [], {}) @@ -73,50 +105,86 @@ class TestDownloadBuild(utils.CliTestCase): self.assertEqual(rv, None) self.assert_console_message(stderr, expected) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_download_build_without_rpm(self, stderr): + def test_download_build_without_rpm(self): build_id = '1' expected = "No such rpm: %s\n" % build_id self.session.getRPM.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_download_build(self.options, self.session, ['--rpm', build_id]) - self.assertExitCode(ex, 1) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + ['--rpm', build_id], + stderr=expected, + activate_session=None, + exit_code=1 + ) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_download_build_no_build(self, stderr): + def test_download_build_no_build(self): build_id = '1' expected = "No such build: %s\n" % build_id self.session.getRPM.return_value = self.getrpminfo self.session.getBuild.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_download_build(self.options, self.session, [build_id]) - self.assertExitCode(ex, 1) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + [build_id], + stderr=expected, + activate_session=None, + exit_code=1 + ) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_download_build_latest_from_no_build(self, stderr): + def test_download_build_latest_from_no_build(self): nvr = self.build_templ['nvr'] expected = "%s has no builds of %s\n" % (self.tag, nvr) self.session.getRPM.return_value = self.getrpminfo self.session.listTagged.return_value = [] - with self.assertRaises(SystemExit) as ex: - anon_handle_download_build(self.options, self.session, [nvr, '--latestfrom', self.tag]) - self.assertExitCode(ex, 1) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + [nvr, '--latestfrom', self.tag], + stderr=expected, + activate_session=None, + exit_code=1 + ) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_download_build_latest_from_build_id(self, stderr): + def test_download_build_latest_from_build_id(self): build_id = '1' - expected = "Usage: %s download-build [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: --latestfrom not compatible with build IDs, " \ - "specify a package name.\n" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_download_build(self.options, self.session, [build_id, '--latestfrom', - self.tag]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + expected = self.format_error_message( + "--latestfrom not compatible with build IDs, specify a package name.") + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + [build_id, '--latestfrom', self.tag], + stderr=expected, + activate_session=None, + exit_code=2 + ) + + @mock.patch('sys.stdout', new_callable=StringIO) + @mock.patch('sys.stderr', new_callable=StringIO) + def test_download_task_id(self, stderr, stdout): + build_id = '1' + self.session.listBuilds.return_value = self.listbuilds + anon_handle_download_build(self.options, self.session, ['--task-id', build_id]) + self.assert_console_message(stdout, "") + self.assert_console_message(stderr, "") + + def test_download_no_asociated_build_task(self): + build_id = '1' + self.session.listBuilds.return_value = [] + self.assert_system_exit( + anon_handle_download_build, + self.options, + self.session, + ['--task-id', build_id], + stderr='No associated builds for task %s\n' % build_id, + stdout='', + activate_session=None, + exit_code=1 + ) def test_handle_add_volume_help(self): self.assert_help( diff --git a/tests/test_cli/test_edit_channel.py b/tests/test_cli/test_edit_channel.py index 017440f2..55f391e1 100644 --- a/tests/test_cli/test_edit_channel.py +++ b/tests/test_cli/test_edit_channel.py @@ -4,7 +4,6 @@ from __future__ import absolute_import import unittest import mock -import six import koji from koji_cli.commands import handle_edit_channel @@ -25,6 +24,12 @@ class TestEditChannel(utils.CliTestCase): 'description': self.description, } self.maxDiff = None + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-channel [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) def tearDown(self): mock.patch.stopall() @@ -43,82 +48,90 @@ Options: --comment=COMMENT Comment of channel """ % self.progname) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_channel_without_args(self, activate_session_mock, stderr): - with self.assertRaises(SystemExit) as ex: - handle_edit_channel(self.options, self.session, []) - self.assertExitCode(ex, 2) - actual = stderr.getvalue() - expected_stderr = """Usage: %s edit-channel [options] -(Specify the --help global option for a list of other help options) + def test_handle_edit_channel_without_args(self): + expected = self.format_error_message("Incorrect number of arguments") + self.assert_system_exit( + handle_edit_channel, + self.options, + self.session, + [], + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() + self.session.getChannel.assert_not_called() + self.session.editChannel.assert_not_called() + self.session.getKojiVersion.assert_not_called() -%s: error: Incorrect number of arguments -""" % (self.progname, self.progname) - self.assertMultiLineEqual(actual, expected_stderr) - activate_session_mock.assert_not_called() - - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_channel(self, activate_session_mock): + def test_handle_edit_channel(self): handle_edit_channel(self.options, self.session, [self.channel_old, '--name', self.channel_new, '--description', self.description]) - activate_session_mock.assert_called_once_with(self.session, self.options) + self.activate_session_mock.assert_called_once_with(self.session, self.options) self.session.editChannel.assert_called_once_with(self.channel_old, name=self.channel_new, description=self.description) + self.session.getChannel.assert_called_once_with(self.channel_old) + self.session.getKojiVersion.assert_not_called() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_channel_older_hub(self, activate_session_mock, stderr): + def test_handle_edit_channel_older_hub(self): expected_api = 'Invalid method: editChannel' expected = 'editChannel is available on hub from Koji 1.26 version, your version ' \ 'is 1.25.1\n' self.session.getKojiVersion.return_value = '1.25.1' self.session.editChannel.side_effect = koji.GenericError(expected_api) - with self.assertRaises(SystemExit) as ex: - handle_edit_channel(self.options, self.session, - [self.channel_old, '--name', self.channel_new, - '--description', self.description]) - self.assertExitCode(ex, 1) - actual = stderr.getvalue() - self.assertMultiLineEqual(actual, expected) - activate_session_mock.assert_called_once_with(self.session, self.options) + self.assert_system_exit( + handle_edit_channel, + self.options, + self.session, + [self.channel_old, '--name', self.channel_new, '--description', self.description], + stderr=expected, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) self.session.editChannel.assert_called_once_with(self.channel_old, name=self.channel_new, description=self.description) + self.session.getChannel.assert_called_once_with(self.channel_old) + self.session.getKojiVersion.assert_called_once_with() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_channel_non_exist_channel(self, activate_session_mock, stderr): + def test_handle_edit_channel_non_exist_channel(self): expected = 'No such channel: %s\n' % self.channel_old channel_info = None self.session.getChannel.return_value = channel_info - with self.assertRaises(SystemExit) as ex: - handle_edit_channel(self.options, self.session, - [self.channel_old, '--name', self.channel_new, - '--description', self.description]) - self.assertExitCode(ex, 1) - actual = stderr.getvalue() - self.assertMultiLineEqual(actual, expected) - activate_session_mock.assert_called_once_with(self.session, self.options) + self.assert_system_exit( + handle_edit_channel, + self.options, + self.session, + [self.channel_old, '--name', self.channel_new, '--description', self.description], + stderr=expected, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) self.session.editChannel.assert_not_called() + self.session.getChannel.assert_called_once_with(self.channel_old) + self.session.getKojiVersion.assert_not_called() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_channel_non_result(self, activate_session_mock, stderr): + def test_handle_edit_channel_non_result(self): expected = 'No changes made, please correct the command line\n' self.session.getChannel.return_value = self.channel_info self.session.editChannel.return_value = None - with self.assertRaises(SystemExit) as ex: - handle_edit_channel(self.options, self.session, - [self.channel_old, '--name', self.channel_new, - '--description', self.description]) - self.assertExitCode(ex, 1) - actual = stderr.getvalue() - self.assertMultiLineEqual(actual, expected) - activate_session_mock.assert_called_once_with(self.session, self.options) + self.assert_system_exit( + handle_edit_channel, + self.options, + self.session, + [self.channel_old, '--name', self.channel_new, '--description', self.description], + stderr=expected, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) self.session.editChannel.assert_called_once_with(self.channel_old, name=self.channel_new, description=self.description) + self.session.getChannel.assert_called_once_with(self.channel_old) + self.session.getKojiVersion.assert_not_called() if __name__ == '__main__': diff --git a/tests/test_cli/test_edit_external_repo.py b/tests/test_cli/test_edit_external_repo.py index c0d2b321..10a8f1e2 100644 --- a/tests/test_cli/test_edit_external_repo.py +++ b/tests/test_cli/test_edit_external_repo.py @@ -17,20 +17,14 @@ class TestEditExternalRepo(utils.CliTestCase): def setUp(self): self.options = mock.MagicMock() self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s edit-external-repo [options] (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_external_repo_error( - self, - activate_session_mock, - stderr, - stdout): + def test_handle_edit_external_repo_error(self): """Test handle_edit_external_repo function""" # [(expected, args),...] items = [ @@ -54,6 +48,13 @@ class TestEditExternalRepo(utils.CliTestCase): stderr=self.format_error_message(expected), activate_session=None) + self.activate_session_mock.assert_not_called() + self.session.editExternalRepo.assert_not_called() + self.session.editTagExternalRepo.assert_not_called() + + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) + def test_handle_edit_external_repo_ext_repo_only(self, stderr, stdout): # edit ext-repo only handle_edit_external_repo(self.options, self.session, ['ext_repo', '--name', 'newname', '--url', 'https://newurl']) @@ -62,9 +63,12 @@ class TestEditExternalRepo(utils.CliTestCase): self.session.editExternalRepo.assert_called_once_with('ext_repo', name='newname', url='https://newurl') self.session.editTagExternalRepo.assert_not_called() + self.activate_session_mock.assert_called_once_with(self.session, self.options) + @mock.patch('sys.stdout', new_callable=six.StringIO) + @mock.patch('sys.stderr', new_callable=six.StringIO) + def test_handle_edit_external_repo_tag_repo_only(self, stderr, stdout): # edit tag-repo only - self.session.reset_mock() handle_edit_external_repo(self.options, self.session, ['ext_repo', '-t', 'tag', '-p', '0', '-m', 'koji', '-a', 'i386']) self.assert_console_message(stdout, "") @@ -75,6 +79,7 @@ class TestEditExternalRepo(utils.CliTestCase): priority=0, merge_mode='koji', arches='i386') + self.activate_session_mock.assert_called_once_with(self.session, self.options) def test_handle_edit_external_repo_help(self): self.assert_help( diff --git a/tests/test_cli/test_edit_host.py b/tests/test_cli/test_edit_host.py index b30549c3..ce98e9c9 100644 --- a/tests/test_cli/test_edit_host.py +++ b/tests/test_cli/test_edit_host.py @@ -1,134 +1,121 @@ from __future__ import absolute_import import mock -import os import six -import sys import unittest +import koji from mock import call from koji_cli.commands import handle_edit_host from . import utils -class TestEditHost(utils.CliTestCase): - # Show long diffs in error output... - maxDiff = None +class TestEditHost(utils.CliTestCase): + def setUp(self): + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-host [ ...] [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) + self.host = 'host' + self.arches = 'arch1 arch2' + self.capacity = 0.22 + self.description = 'description' + self.comment = 'comment' @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_host(self, activate_session_mock, stdout): - host = 'host' + def test_handle_edit_host(self, stdout): host_info = mock.ANY - arches = 'arch1 arch2' - capacity = 0.22 - description = 'description' - comment = 'comment' - args = [host] - args.append('--arches=' + arches) - args.append('--capacity=' + str(capacity)) - args.append('--description=' + description) - args.append('--comment=' + comment) - kwargs = {'arches': arches, - 'capacity': capacity, - 'description': description, - 'comment': comment} - options = mock.MagicMock() + args = [self.host] + args.append('--arches=' + self.arches) + args.append('--capacity=' + str(self.capacity)) + args.append('--description=' + self.description) + args.append('--comment=' + self.comment) + kwargs = {'arches': self.arches, + 'capacity': self.capacity, + 'description': self.description, + 'comment': self.comment} - # Mock out the xmlrpc server - session = mock.MagicMock() - - session.multiCall.side_effect = [[[host_info]], [[True]]] + self.session.multiCall.side_effect = [[[host_info]], [[True]]] # Run it and check immediate output # args: host, --arches='arch1 arch2', --capacity=0.22, # --description=description, --comment=comment # expected: success - rv = handle_edit_host(options, session, args) + rv = handle_edit_host(self.options, self.session, args) actual = stdout.getvalue() expected = 'Edited host\n' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - session.getHost.assert_called_once_with(host) - session.editHost.assert_called_once_with(host, **kwargs) - self.assertEqual(session.multiCall.call_count, 2) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getHost.assert_called_once_with(self.host) + self.session.editHost.assert_called_once_with(self.host, **kwargs) + self.assertEqual(self.session.multiCall.call_count, 2) self.assertNotEqual(rv, 1) @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_host_failed(self, activate_session_mock, stdout): - host = 'host' + def test_handle_edit_host_failed(self, stdout): host_info = mock.ANY - arches = 'arch1 arch2' - capacity = 0.22 - description = 'description' - comment = 'comment' - args = [host] - args.append('--arches=' + arches) - args.append('--capacity=' + str(capacity)) - args.append('--description=' + description) - args.append('--comment=' + comment) - kwargs = {'arches': arches, - 'capacity': capacity, - 'description': description, - 'comment': comment} - options = mock.MagicMock() + args = [self.host] + args.append('--arches=' + self.arches) + args.append('--capacity=' + str(self.capacity)) + args.append('--description=' + self.description) + args.append('--comment=' + self.comment) + kwargs = {'arches': self.arches, + 'capacity': self.capacity, + 'description': self.description, + 'comment': self.comment} - # Mock out the xmlrpc server - session = mock.MagicMock() - - session.multiCall.side_effect = [[[host_info]], [[False]]] + self.session.multiCall.side_effect = [[[host_info]], [[False]]] # Run it and check immediate output # args: host, --arches='arch1 arch2', --capacity=0.22, # --description=description, --comment=comment # expected: failed - session.editHost == False - rv = handle_edit_host(options, session, args) + rv = handle_edit_host(self.options, self.session, args) actual = stdout.getvalue() expected = 'No changes made to host\n' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - session.getHost.assert_called_once_with(host) - session.editHost.assert_called_once_with(host, **kwargs) - self.assertEqual(session.multiCall.call_count, 2) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getHost.assert_called_once_with(self.host) + self.session.editHost.assert_called_once_with(self.host, **kwargs) + self.assertEqual(self.session.multiCall.call_count, 2) self.assertNotEqual(rv, 1) @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_multi_host(self, activate_session_mock, stdout): + def test_handle_edit_multi_host(self, stdout): hosts = ['host1', 'host2'] host_infos = [mock.ANY, mock.ANY] - arches = 'arch1 arch2' - capacity = 0.22 - description = 'description' - comment = 'comment' args = hosts - args.append('--arches=' + arches) - args.append('--capacity=' + str(capacity)) - args.append('--description=' + description) - args.append('--comment=' + comment) - kwargs = {'arches': arches, - 'capacity': capacity, - 'description': description, - 'comment': comment} - options = mock.MagicMock() + args.append('--arches=' + self.arches) + args.append('--capacity=' + str(self.capacity)) + args.append('--description=' + self.description) + args.append('--comment=' + self.comment) + kwargs = {'arches': self.arches, + 'capacity': self.capacity, + 'description': self.description, + 'comment': self.comment} - # Mock out the xmlrpc server - session = mock.MagicMock() - - session.multiCall.side_effect = [[[info] - for info in host_infos], [[True], [True]]] + self.session.multiCall.side_effect = [[[info] + for info in host_infos], [[True], [True]]] # Run it and check immediate output # args: host1, host2, --arches='arch1 arch2', --capacity=0.22, # --description=description, --comment=comment # expected: success - rv = handle_edit_host(options, session, args) + rv = handle_edit_host(self.options, self.session, args) actual = stdout.getvalue() expected = 'Edited host1\nEdited host2\n' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - self.assertEqual(session.mock_calls, + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getHost.assert_has_calls([call(hosts[0]), call(hosts[1])]) + self.session.editHost.assert_has_calls( + [call(hosts[0], **kwargs), call(hosts[1], **kwargs)]) + self.assertEqual(self.session.mock_calls, [call.getHost(hosts[0]), call.getHost(hosts[1]), call.multiCall(strict=True), @@ -139,79 +126,60 @@ class TestEditHost(utils.CliTestCase): call.multiCall(strict=True)]) self.assertNotEqual(rv, 1) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_host_no_arg( - self, activate_session_mock, stderr, stdout): - args = [] - options = mock.MagicMock() - # Mock out the xmlrpc server - session = mock.MagicMock() - progname = os.path.basename(sys.argv[0]) or 'koji' - - # Mock out the xmlrpc server - session = mock.MagicMock() + def test_handle_edit_host_no_arg(self): # Run it and check immediate output # args: _empty_ # expected: failed - should specify host - with self.assertRaises(SystemExit) as ex: - handle_edit_host(options, session, args) - self.assertExitCode(ex, 2) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = '' - expected_stderr = """Usage: %s edit-host [ ...] [options] -(Specify the --help global option for a list of other help options) - -%s: error: Please specify a hostname -""" % (progname, progname) - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) + expected = self.format_error_message("Please specify a hostname") + self.assert_system_exit( + handle_edit_host, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) # Finally, assert that things were called as we expected. - activate_session_mock.assert_not_called() - session.getHost.assert_not_called() - session.editHost.assert_not_called() - session.multiCall.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.getHost.assert_not_called() + self.session.editHost.assert_not_called() + self.session.multiCall.assert_not_called() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_host_no_host(self, activate_session_mock, stderr): - host = 'host' + def test_handle_edit_host_no_host(self): host_info = None - arches = 'arch1 arch2' - capacity = 0.22 - description = 'description' - comment = 'comment' - args = [host] - args.append('--arches=' + arches) - args.append('--capacity=' + str(capacity)) - args.append('--description=' + description) - args.append('--comment=' + comment) - options = mock.MagicMock() + args = [self.host] + args.append('--arches=' + self.arches) + args.append('--capacity=' + str(self.capacity)) + args.append('--description=' + self.description) + args.append('--comment=' + self.comment) - # Mock out the xmlrpc server - session = mock.MagicMock() - - session.multiCall.return_value = [[host_info]] + self.session.multiCall.return_value = [[host_info]] # Run it and check immediate output # args: host, --arches='arch1 arch2', --capacity=0.22, # --description=description, --comment=comment # expected: failed -- getHost() == None - with self.assertRaises(SystemExit) as ex: - handle_edit_host(options, session, args) - self.assertExitCode(ex, 1) - actual = stderr.getvalue() expected = """No such host: %s No changes made, please correct the command line -""" % host - self.assertMultiLineEqual(actual, expected) +""" % self.host + self.assert_system_exit( + handle_edit_host, + self.options, + self.session, + args, + stdout='', + stderr=expected, + activate_session=None, + exit_code=1 + ) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - session.getHost.assert_called_once_with(host) - session.editHost.assert_not_called() - self.assertEqual(session.multiCall.call_count, 1) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getHost.assert_called_once_with(self.host) + self.session.editHost.assert_not_called() + self.assertEqual(self.session.multiCall.call_count, 1) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_cli/test_edit_notification.py b/tests/test_cli/test_edit_notification.py index 8bc92a38..21b8cc01 100644 --- a/tests/test_cli/test_edit_notification.py +++ b/tests/test_cli/test_edit_notification.py @@ -1,8 +1,6 @@ from __future__ import absolute_import import koji import mock -import unittest -from six.moves import StringIO from koji_cli.commands import handle_edit_notification from . import utils @@ -14,108 +12,150 @@ class TestEditNotification(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-notification [options] +(Specify the --help global option for a list of other help options) +%s: error: {message} +""" % (self.progname, self.progname) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_notification(self, activate_session_mock): + def test_handle_edit_notification(self): self.session.getPackageID.return_value = 1234 self.session.getTagID.return_value = 4321 self.session.getBuildNotification.return_value = {'id': 2345} handle_edit_notification(self.options, self.session, - ['--package', 'pkg_a', '--tag', 'tag_a', '--success-only', '2345']) + ['--package', 'pkg_a', '--tag', 'tag_a', + '--success-only', '2345']) + self.session.getBuildNotification.assert_called_once_with(2345) self.session.getPackageID.assert_called_once_with('pkg_a') self.session.getTagID.assert_called_once_with('tag_a', strict=True) self.session.updateNotification.assert_called_once_with(2345, 1234, 4321, True) + self.activate_session_mock.assert_called_once_with(self.session, self.options) - - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_notification_no_pkg(self, activate_session_mock): + def test_handle_edit_notification_no_pkg(self): self.session.getBuildNotification.return_value = \ {'id': 2345, 'package_id': 135, 'success_only': False} - handle_edit_notification(self.options, self.session, - ['--tag', '*', '2345']) + handle_edit_notification(self.options, self.session, ['--tag', '*', '2345']) self.session.getPackageID.assert_not_called() self.session.getTagID.assert_not_called() self.session.updateNotification.assert_called_once_with(2345, 135, None, False) self.session.getBuildNotification.assert_called_once_with(2345) + self.activate_session_mock.assert_called_once_with(self.session, self.options) - - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_notification_no_tag(self, activate_session_mock): + def test_handle_edit_notification_no_tag(self): self.session.getBuildNotification.return_value = \ {'id': 2345, 'tag_id': 135, 'success_only': True} handle_edit_notification(self.options, self.session, - ['--package', '*', '--no-success-only', '2345']) + ['--package', '*', '--no-success-only', '2345']) self.session.getPackageID.assert_not_called() self.session.getTagID.assert_not_called() self.session.updateNotification.assert_called_once_with(2345, None, 135, False) self.session.getBuildNotification.assert_called_once_with(2345) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + def test_handle_edit_notification_bogus(self): + expected = self.format_error_message("Notification ID has to be numeric") + self.assert_system_exit( + handle_edit_notification, + self.options, + self.session, + ['bogus'], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.session.updateNotification.assert_not_called() + self.session.getPackageID.assert_not_called() + self.session.getTagID.assert_not_called() + self.session.getBuildNotification.assert_not_called() + self.activate_session_mock.assert_not_called() - @mock.patch('sys.exit') - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_edit_notification_bogus(self, sys_stderr, sys_exit): - sys_exit.side_effect = SystemExit() - - with self.assertRaises(SystemExit): - handle_edit_notification(self.options, self.session, ['bogus']) + def test_handle_edit_notification_no_id(self): + expected = self.format_error_message("Only argument is notification ID") + self.assert_system_exit( + handle_edit_notification, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) self.session.updateNotification.assert_not_called() + self.session.getPackageID.assert_not_called() + self.session.getTagID.assert_not_called() + self.session.getBuildNotification.assert_not_called() + self.activate_session_mock.assert_not_called() - - @mock.patch('sys.exit') - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_edit_notification_no_id(self, sys_stderr, sys_exit): - sys_exit.side_effect = SystemExit() - - with self.assertRaises(SystemExit): - handle_edit_notification(self.options, self.session, []) + def test_handle_edit_notification_no_opts(self): + expected = self.format_error_message("Command need at least one option") + self.assert_system_exit( + handle_edit_notification, + self.options, + self.session, + ['123'], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) self.session.updateNotification.assert_not_called() + self.session.getPackageID.assert_not_called() + self.session.getTagID.assert_not_called() + self.session.getBuildNotification.assert_not_called() + self.activate_session_mock.assert_not_called() - - @mock.patch('sys.exit') - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_edit_notification_no_opts(self, sys_stderr, sys_exit): - sys_exit.side_effect = SystemExit() - - with self.assertRaises(SystemExit): - handle_edit_notification(self.options, self.session, ['123']) - - self.session.updateNotification.assert_not_called() - - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_edit_notification_non_exist_tag(self, stderr): + def test_handle_edit_notification_non_exist_tag(self): tag = 'test-tag' - expected = "Usage: %s edit-notification [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such tag: %s\n" % (self.progname, self.progname, tag) + expected = self.format_error_message("No such tag: %s" % tag) self.session.getBuildNotification.return_value = \ {'id': 2345, 'package_id': 135, 'success_only': False} self.session.getTagID.side_effect = koji.GenericError - with self.assertRaises(SystemExit) as ex: - handle_edit_notification(self.options, self.session, ['--tag', tag, '2345']) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_edit_notification, + self.options, + self.session, + ['--tag', tag, '2345'], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.session.getPackageID.assert_not_called() + self.session.getTagID.assert_called_once_with(tag, strict=True) + self.session.getBuildNotification.assert_called_once_with(2345) + self.session.updateNotification.assert_not_called() + self.activate_session_mock.assert_called_once_with(self.session, self.options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_edit_notification_non_exist_pkg(self, stderr): + def test_handle_edit_notification_non_exist_pkg(self): pkg = 'test-pkg' - expected = "Usage: %s edit-notification [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such package: %s\n" % (self.progname, self.progname, pkg) + expected = self.format_error_message("No such package: %s" % pkg) self.session.getBuildNotification.return_value = \ {'id': 2345, 'package_id': 135, 'success_only': False} self.session.getPackageID.return_value = None - - with self.assertRaises(SystemExit) as ex: - handle_edit_notification(self.options, self.session, ['--package', pkg, '2345']) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_edit_notification, + self.options, + self.session, + ['--package', pkg, '2345'], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.session.getPackageID.assert_called_once_with(pkg) + self.session.getTagID.assert_not_called() + self.session.getBuildNotification.assert_called_once_with(2345) + self.session.updateNotification.assert_not_called() + self.activate_session_mock.assert_called_once_with(self.session, self.options) diff --git a/tests/test_cli/test_edit_permission.py b/tests/test_cli/test_edit_permission.py index b2465746..82c0e8ee 100644 --- a/tests/test_cli/test_edit_permission.py +++ b/tests/test_cli/test_edit_permission.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import mock import koji +import six from koji_cli.commands import handle_edit_permission from . import utils @@ -26,8 +27,7 @@ class TestEditPermission(utils.CliTestCase): self.description = 'test-description' def test_handle_edit_permission_argument_error(self): - expected = self.format_error_message( - "Please specify a permission and a description") + expected = self.format_error_message("Please specify a permission and a description") for args in [[], [self.perm]]: self.assert_system_exit( handle_edit_permission, @@ -37,9 +37,13 @@ class TestEditPermission(utils.CliTestCase): stderr=expected, activate_session=None) self.activate_session_mock.assert_not_called() - self.session.grantPermission.assert_not_called() + self.session.editPermission.assert_not_called() - def test_handle_edit_permission_with_new_and_description(self): + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_edit_permission_with_new_and_description(self, stdout): handle_edit_permission(self.options, self.session, [self.perm, self.description]) + actual = stdout.getvalue() + expected = '' + self.assertMultiLineEqual(actual, expected) self.session.editPermission.assert_called_once_with(self.perm, self.description) self.activate_session_mock.assert_called_once_with(self.session, self.options) diff --git a/tests/test_cli/test_edit_tag.py b/tests/test_cli/test_edit_tag.py index 6fe5ce8f..19e302d4 100644 --- a/tests/test_cli/test_edit_tag.py +++ b/tests/test_cli/test_edit_tag.py @@ -1,118 +1,106 @@ from __future__ import absolute_import import mock -import os import six -import sys +import koji from koji_cli.commands import handle_edit_tag from . import utils -progname = os.path.basename(sys.argv[0]) or 'koji' - class TestEditTag(utils.CliTestCase): - # Show long diffs in error output... - maxDiff = None + + def setUp(self): + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-tag [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) + self.tag = 'tag' + self.arches = 'arch1 arch2' + self.perm = 'perm' + self.locked = True + self.rename = 'tag2' + self.maven_support = True + self.maven_include_all = True + self.extra = {'extraA': 'A', 'extraB': True} + self.remove_extra = ['extraC', 'extraD'] @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_tag(self, activate_session_mock, stdout): - tag = 'tag' - arches = 'arch1 arch2' - perm = 'perm' - locked = True - rename = 'tag2' - maven_support = True - maven_include_all = True - extra = {'extraA': 'A', 'extraB': True} - remove_extra = ['extraC', 'extraD'] - args = [tag] - args.append('--arches=' + arches) - args.append('--perm=' + perm) + def test_handle_edit_tag_1(self, stdout): + args = [self.tag] + args.append('--arches=' + self.arches) + args.append('--perm=' + self.perm) args.append('--lock') - args.append('--rename=' + rename) + args.append('--rename=' + self.rename) args.append('--maven-support') args.append('--include-all') - for k, x in six.iteritems(extra): + for k, x in six.iteritems(self.extra): args.append('-x') args.append(k + '=' + str(x)) - for r in remove_extra: + for r in self.remove_extra: args.append('-r') args.append(r) - opts = {'arches': arches, - 'perm': perm, - 'locked': locked, - 'name': rename, - 'maven_support': maven_support, - 'maven_include_all': maven_include_all, - 'extra': extra, + opts = {'arches': self.arches, + 'perm': self.perm, + 'locked': self.locked, + 'name': self.rename, + 'maven_support': self.maven_support, + 'maven_include_all': self.maven_include_all, + 'extra': self.extra, 'block_extra': [], - 'remove_extra': remove_extra} - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() + 'remove_extra': self.remove_extra} # Run it and check immediate output # args: tag --arches='arch1 arch2' --perm --lock # --rename=tag2 --maven-support --include-all # -x extraA=A -x extraB=True -r extraC -r extraD # expected: success - rv = handle_edit_tag(options, session, args) + rv = handle_edit_tag(self.options, self.session, args) actual = stdout.getvalue() expected = '' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - session.editTag2.assert_called_once_with(tag, **opts) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.editTag2.assert_called_once_with(self.tag, **opts) self.assertEqual(rv, None) - stdout.seek(0) - stdout.truncate() - session.reset_mock() - activate_session_mock.reset_mock() - args = [tag] + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_edit_tag_2(self, stdout): + args = [self.tag] args.append('--no-perm') args.append('--unlock') args.append('--no-maven-support') args.append('--no-include-all') opts = {'perm': None, - 'locked': not locked, - 'maven_support': not maven_support, + 'locked': not self.locked, + 'maven_support': not self.maven_support, 'block_extra': [], 'remove_extra': [], - 'maven_include_all': not maven_include_all} + 'maven_include_all': not self.maven_include_all} # Run it and check immediate output # args: tag --no-perm --unlock --no-maven-support --no-include-all # expected: success - rv = handle_edit_tag(options, session, args) + rv = handle_edit_tag(self.options, self.session, args) actual = stdout.getvalue() expected = '' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - session.editTag2.assert_called_once_with(tag, **opts) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.editTag2.assert_called_once_with(self.tag, **opts) self.assertEqual(rv, None) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_tag_help(self, activate_session_mock, stderr, stdout): - args = ['--help'] - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() - + def test_handle_edit_tag_help(self): # Run it and check immediate output # args: --help # expected: failed, help info shows - with self.assertRaises(SystemExit) as ex: - handle_edit_tag(options, session, args) - self.assertExitCode(ex, 0) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = """Usage: %s edit-tag [options] + self.assert_help( + handle_edit_tag, + """Usage: %s edit-tag [options] (Specify the --help global option for a list of other help options) Options: @@ -135,40 +123,54 @@ Options: Remove tag extra option -b key, --block-extra=key Block inherited tag extra option -""" % progname - expected_stderr = '' - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) +""" % self.progname) + # Finally, assert that things were called as we expected. - activate_session_mock.assert_not_called() - session.editTag2.assert_not_called() - - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_tag_no_arg(self, activate_session_mock, stderr, stdout): - args = [] - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() + self.activate_session_mock.assert_not_called() + self.session.editTag2.assert_not_called() + def test_handle_edit_tag_no_arg(self): # Run it and check immediate output # args: --help # expected: failed, help info shows - with self.assertRaises(SystemExit) as ex: - handle_edit_tag(options, session, args) - self.assertExitCode(ex, 2) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = '' - expected_stderr = """Usage: %(progname)s edit-tag [options] -(Specify the --help global option for a list of other help options) - -%(progname)s: error: Please specify a name for the tag -""" % {'progname': progname} - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) + expected = self.format_error_message("Please specify a name for the tag") + self.assert_system_exit( + handle_edit_tag, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) # Finally, assert that things were called as we expected. - activate_session_mock.assert_not_called() - session.editTag2.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.editTag2.assert_not_called() + + def test_handle_edit_tag_duplicate_extra(self): + args = [self.tag] + for k, x in six.iteritems(self.extra): + args.append('-x') + args.append(k + '=' + str(x)) + # duplicate item in dict extra + args.append('-x') + args.append('extraA=duplicateA') + + # Run it and check immediate output + # args: tag -x extraA=A -x extraB=True -x extraA=duplicateA + # expected: failed + expected = self.format_error_message("Duplicate extra key: extraA") + self.assert_system_exit( + handle_edit_tag, + self.options, + self.session, + args, + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + # Finally, assert that things were called as we expected. + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.editTag2.assert_not_called() diff --git a/tests/test_cli/test_edit_tag_inheritance.py b/tests/test_cli/test_edit_tag_inheritance.py index 1de9266d..c2e345f0 100644 --- a/tests/test_cli/test_edit_tag_inheritance.py +++ b/tests/test_cli/test_edit_tag_inheritance.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import mock -from six.moves import StringIO +from mock import call import koji from koji_cli.commands import handle_edit_tag_inheritance @@ -14,36 +14,25 @@ class TestEditTagInheritance(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-tag-inheritance [options] +(Specify the --help global option for a list of other help options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_tag_inheritance_without_option(self, stderr): - expected = "Usage: %s edit-tag-inheritance [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: This command takes at least one argument: " \ - "a tag name or ID\n" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - handle_edit_tag_inheritance(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_tag_inheritance_non_exist_tag(self, stderr): - tag = 'test-tag' - parent_tag = 'parent-test-tag' - priority = '99' - expected = "Usage: %s edit-tag-inheritance [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such tag: %s\n" % (self.progname, self.progname, tag) - self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - handle_edit_tag_inheritance(self.options, self.session, - [tag, parent_tag, priority]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_tag_inheritance_non_exist_parent_tag(self, stderr): - side_effect_result = [{'arches': 'x86_64', +%s: error: {message} +""" % (self.progname, self.progname) + self.tag = 'test-tag' + self.parent_tag = 'parent-test-tag' + self.priority = '99' + self.new_priority = '15' + self.tag_inheritance = {'child_id': 1, + 'intransitive': False, + 'maxdepth': None, + 'name': self.tag, + 'noconfig': False, + 'parent_id': 2, + 'pkg_filter': '', + 'priority': self.priority} + self.child_tag_info = {'arches': 'x86_64', 'extra': {}, 'id': 1, 'locked': False, @@ -51,17 +40,230 @@ class TestEditTagInheritance(utils.CliTestCase): 'maven_support': False, 'name': 'test-tag', 'perm': None, - 'perm_id': None}, - None] - tag = 'test-tag' - parent_tag = 'parent-test-tag' - priority = '99' - expected = "Usage: %s edit-tag-inheritance [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such tag: %s\n" % (self.progname, self.progname, parent_tag) - self.session.getTag.side_effect = side_effect_result - with self.assertRaises(SystemExit) as ex: - handle_edit_tag_inheritance(self.options, self.session, - [tag, parent_tag, priority]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + 'perm_id': None} + self.parent_tag_info = {'arches': 'x86_64', + 'extra': {}, + 'id': 2, + 'locked': False, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'parent-test-tag', + 'perm': None, + 'perm_id': None} + + def test_edit_tag_inheritance_without_option(self): + expected = self.format_error_message( + "This command takes at least one argument: a tag name or ID") + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() + self.session.getTag.assert_not_called() + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_non_exist_tag(self): + self.session.getTag.return_value = None + expected = self.format_error_message("No such tag: %s" % self.tag) + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.tag) + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_non_exist_parent_tag(self): + self.session.getTag.side_effect = [self.child_tag_info, None] + expected = self.format_error_message("No such tag: %s" % self.parent_tag) + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_more_arguments(self): + expected = self.format_error_message( + "This command takes at most three argument: a tag name or ID, " + "a parent tag name or ID, and a priority") + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + ['arg1', 'arg2', 'arg3', 'arg4'], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() + self.session.getTag.assert_not_called() + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_non_exist_inheritance(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.return_value = [] + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='', + stderr='No inheritance link found to remove. Please check your arguments\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_multi_inheritance_without_parent(self): + self.session.getTag.return_value = self.child_tag_info + self.session.getInheritanceData.return_value = [self.tag_inheritance, self.tag_inheritance] + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag], + stdout='Multiple matches for tag.\n', + stderr='Please specify a parent on the command line.\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.tag) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_multi_inheritance_without_priority(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.return_value = [self.tag_inheritance, self.tag_inheritance] + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag], + stdout='Multiple matches for tag.\n', + stderr='Please specify a priority on the command line.\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_multi_inheritance(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.return_value = [self.tag_inheritance, self.tag_inheritance] + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='Multiple matches for tag.\n', + stderr='Error: Key constraints may be broken. Exiting.\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_already_active_inheritance(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.side_effect = [[self.tag_inheritance], + [self.tag_inheritance]] + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority, '--priority', self.priority], + stdout='', + stderr='Error: There is already an active inheritance with that priority on %s, ' + 'please specify a different priority with --priority.\n' % self.tag, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_has_calls([call(1), call(1)]) + self.session.setInheritanceData.assert_not_called() + + def test_edit_tag_inheritance_valid_maxdepth_digit(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.side_effect = [[self.tag_inheritance], + [self.tag_inheritance]] + handle_edit_tag_inheritance(self.options, self.session, + ['--priority', self.new_priority, '--maxdepth', '123', + '--intransitive', '--noconfig', '--pkg-filter', + self.tag, self.parent_tag]) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.parent_tag) + self.session.getInheritanceData.assert_has_calls([call(1), call(1)]) + self.session.setInheritanceData.assert_called_once_with( + 1, [{'child_id': 1, 'intransitive': True, 'maxdepth': 123, 'name': self.tag, + 'noconfig': True, 'parent_id': 2, 'pkg_filter': self.tag, + 'priority': int(self.new_priority)}]) + + def test_edit_tag_inheritance_valid_maxdepth_none(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.side_effect = [[self.tag_inheritance], + [self.tag_inheritance]] + handle_edit_tag_inheritance(self.options, self.session, + ['--priority', self.new_priority, '--maxdepth', "None", + '--intransitive', '--noconfig', '--pkg-filter', + self.tag, self.parent_tag]) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.parent_tag) + self.session.getInheritanceData.assert_has_calls([call(1), call(1)]) + self.session.setInheritanceData.assert_called_once_with( + 1, [{'child_id': 1, 'intransitive': True, 'maxdepth': None, 'name': self.tag, + 'noconfig': True, 'parent_id': 2, 'pkg_filter': self.tag, + 'priority': int(self.new_priority)}]) + + def test_edit_tag_inheritance_valid_maxdepth_invalid(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.side_effect = [[self.tag_inheritance], + [self.tag_inheritance]] + self.assert_system_exit( + handle_edit_tag_inheritance, + self.options, + self.session, + ['--priority', self.new_priority, '--maxdepth', 'wrong-maxdepth', '--intransitive', + '--noconfig', '--pkg-filter', self.tag, self.parent_tag], + stdout='', + stderr='Invalid maxdepth: wrong-maxdepth\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.parent_tag) + self.session.getInheritanceData.assert_has_calls([call(1), call(1)]) + self.session.setInheritanceData.assert_not_called() diff --git a/tests/test_cli/test_edit_target.py b/tests/test_cli/test_edit_target.py index d8760c66..d3d5557a 100644 --- a/tests/test_cli/test_edit_target.py +++ b/tests/test_cli/test_edit_target.py @@ -16,6 +16,12 @@ class TestEditTarget(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-target [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) self.build_target_info = {'build_tag': 444, 'build_tag_name': 'test-tag', 'dest_tag': 445, @@ -30,132 +36,157 @@ class TestEditTarget(utils.CliTestCase): 'extra': {}, 'id': 1, 'name': 'new-build-tag'} + self.target = 'test-target' + self.dest_tag = 'test-dest-tag' + self.new_target_name = 'new-test-target' + self.new_dest_tag = 'new-dest-tag' + self.new_build_tag = 'new-build-tag' - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_target_without_option(self, stderr): - expected = "Usage: %s edit-target [options] \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: Please specify a build target\n" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - handle_edit_target(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - - def test_edit_target_non_exist_target(self): - target = 'test-target' - expected = "No such build target: %s" % target - self.session.getBuildTarget.return_value = None - with self.assertRaises(koji.GenericError) as cm: - handle_edit_target(self.options, self.session, [target]) - self.assertEqual(expected, str(cm.exception)) + def test_edit_target_without_option(self): + expected = self.format_error_message("Please specify a build target") + self.assert_system_exit( + handle_edit_target, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() + self.session.getBuildTarget.assert_not_called() self.session.getTag.assert_not_called() self.session.editBuildTarget.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_target_non_exist_dest_tag(self, stderr): - target = 'test-target' - dest_tag = 'test-dest-tag' - expected = "No such destination tag: %s\n" % dest_tag + def test_edit_target_non_exist_target(self): + expected = "No such build target: %s" % self.target + self.session.getBuildTarget.return_value = None + with self.assertRaises(koji.GenericError) as cm: + handle_edit_target(self.options, self.session, [self.target]) + self.assertEqual(expected, str(cm.exception)) + self.session.getBuildTarget.assert_called_once_with(self.target) + self.session.getTag.assert_not_called() + self.session.editBuildTarget.assert_not_called() + self.activate_session_mock.assert_called_with(self.session, self.options) + + def test_edit_target_non_exist_dest_tag(self): self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - handle_edit_target(self.options, self.session, ['--dest-tag', dest_tag, target]) - self.assertExitCode(ex, 1) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_edit_target, + self.options, + self.session, + ['--dest-tag', self.dest_tag, self.target], + stdout='', + stderr="No such destination tag: %s\n" % self.dest_tag, + activate_session=None, + exit_code=1 + ) + self.session.getBuildTarget.assert_called_once_with(self.target) + self.session.getTag.assert_called_once_with(self.dest_tag) self.session.editBuildTarget.assert_not_called() + self.activate_session_mock.assert_called_with(self.session, self.options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_target_without_perms(self, stderr): + def test_edit_target_without_perms(self): side_effect_result = [False, False] - - target = 'test-target' self.session.hasPerm.side_effect = side_effect_result - with self.assertRaises(SystemExit) as ex: - handle_edit_target(self.options, self.session, [target]) - self.assertExitCode(ex, 2) - expected_msg = """Usage: %s edit-target [options] -(Specify the --help global option for a list of other help options) - -%s: error: This action requires target or admin privileges -""" % (self.progname, self.progname) - self.assert_console_message(stderr, expected_msg) + expected = self.format_error_message("This action requires target or admin privileges") + self.assert_system_exit( + handle_edit_target, + self.options, + self.session, + [self.target], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) self.session.editBuildTarget.assert_not_called() + self.session.getTag.assert_not_called() self.session.getBuildTarget.assert_not_called() + self.activate_session_mock.assert_called_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) def test_edit_target_new_name(self, stdout): - target = 'test-target' - new_target_name = 'new-test-target' self.session.getBuildTarget.return_value = self.build_target_info - rv = handle_edit_target(self.options, self.session, ['--rename', new_target_name, target]) + rv = handle_edit_target(self.options, self.session, ['--rename', self.new_target_name, + self.target]) self.assertEqual(rv, None) expected_msg = '' self.assert_console_message(stdout, expected_msg) self.session.getTag.assert_not_called() - self.session.getBuildTarget.assert_called_once_with(target) + self.session.getBuildTarget.assert_called_once_with(self.target) self.session.editBuildTarget.assert_called_once_with( - self.build_target_info['orig_name'], new_target_name, + self.build_target_info['orig_name'], self.new_target_name, self.build_target_info['build_tag_name'], self.build_target_info['dest_tag_name']) + self.activate_session_mock.assert_called_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) def test_edit_target_dest_tag(self, stdout): - target = 'test-target' - new_dest_tag = 'new-dest-tag' self.session.getBuildTarget.return_value = self.build_target_info self.session.getTag.return_value = self.dest_tag_info - rv = handle_edit_target(self.options, self.session, ['--dest-tag', new_dest_tag, target]) + rv = handle_edit_target(self.options, self.session, ['--dest-tag', self.new_dest_tag, + self.target]) self.assertEqual(rv, None) expected_msg = '' self.assert_console_message(stdout, expected_msg) - self.session.getTag.assert_called_once_with(new_dest_tag) - self.session.getBuildTarget.assert_called_once_with(target) + self.session.getTag.assert_called_once_with(self.new_dest_tag) + self.session.getBuildTarget.assert_called_once_with(self.target) self.session.editBuildTarget.assert_called_once_with( self.build_target_info['orig_name'], self.build_target_info['name'], self.build_target_info['build_tag_name'], self.build_target_info['dest_tag_name']) + self.activate_session_mock.assert_called_with(self.session, self.options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_target_non_exist_build_tag(self, stderr): - target = 'test-target' - new_build_tag = 'new-build-tag' + def test_edit_target_non_exist_build_tag(self): self.session.getBuildTarget.return_value = self.build_target_info self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - handle_edit_target(self.options, self.session, ['--build-tag', new_build_tag, target]) - self.assertExitCode(ex, 1) - expected_msg = "No such tag: %s\n" % new_build_tag - self.assert_console_message(stderr, expected_msg) - self.session.getTag.assert_called_once_with(new_build_tag) - self.session.getBuildTarget.assert_called_once_with(target) + self.assert_system_exit( + handle_edit_target, + self.options, + self.session, + ['--build-tag', self.new_build_tag, self.target], + stdout='', + stderr="No such tag: %s\n" % self.new_build_tag, + activate_session=None, + exit_code=1 + ) + self.session.getTag.assert_called_once_with(self.new_build_tag) + self.session.getBuildTarget.assert_called_once_with(self.target) self.session.editBuildTarget.assert_not_called() + self.activate_session_mock.assert_called_with(self.session, self.options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_edit_target_tag_arch_none(self, stderr): - target = 'test-target' - new_build_tag = 'new-build-tag' + def test_edit_target_tag_arch_none(self): build_tag_info = copy.deepcopy(self.build_tag_info) build_tag_info['arches'] = '' self.session.getBuildTarget.return_value = self.build_target_info self.session.getTag.return_value = build_tag_info - with self.assertRaises(SystemExit) as ex: - handle_edit_target(self.options, self.session, ['--build-tag', new_build_tag, target]) - self.assertExitCode(ex, 1) - expected_msg = "Build tag has no arches: %s\n" % new_build_tag - self.assert_console_message(stderr, expected_msg) - self.session.getTag.assert_called_once_with(new_build_tag) - self.session.getBuildTarget.assert_called_once_with(target) + self.assert_system_exit( + handle_edit_target, + self.options, + self.session, + ['--build-tag', self.new_build_tag, self.target], + stdout='', + stderr="Build tag has no arches: %s\n" % self.new_build_tag, + activate_session=None, + exit_code=1 + ) + self.session.getTag.assert_called_once_with(self.new_build_tag) + self.session.getBuildTarget.assert_called_once_with(self.target) self.session.editBuildTarget.assert_not_called() + self.activate_session_mock.assert_called_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) def test_edit_target_build_tag_valid(self, stdout): - target = 'test-target' - new_build_tag = 'new-build-tag' self.session.getBuildTarget.return_value = self.build_target_info self.session.getTag.return_value = self.build_tag_info - rv = handle_edit_target(self.options, self.session, ['--build-tag', new_build_tag, target]) + rv = handle_edit_target(self.options, self.session, ['--build-tag', self.new_build_tag, + self.target]) self.assertEqual(rv, None) expected_msg = '' self.assert_console_message(stdout, expected_msg) - self.session.getTag.assert_called_once_with(new_build_tag) - self.session.getBuildTarget.assert_called_once_with(target) + self.session.getTag.assert_called_once_with(self.new_build_tag) + self.session.getBuildTarget.assert_called_once_with(self.target) self.session.editBuildTarget.assert_called_once_with( self.build_target_info['orig_name'], self.build_target_info['name'], self.build_target_info['build_tag_name'], self.build_target_info['dest_tag_name']) + self.activate_session_mock.assert_called_with(self.session, self.options) diff --git a/tests/test_cli/test_edit_user.py b/tests/test_cli/test_edit_user.py index 734334ae..0b5784a5 100644 --- a/tests/test_cli/test_edit_user.py +++ b/tests/test_cli/test_edit_user.py @@ -1,76 +1,61 @@ from __future__ import absolute_import import unittest -import os -import sys import six import mock +import koji from koji_cli.commands import handle_edit_user from . import utils -progname = os.path.basename(sys.argv[0]) or 'koji' - class TestEditUser(utils.CliTestCase): - # Show long diffs in error output... - maxDiff = None + def setUp(self): + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s edit-user [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) + self.user = 'user' + self.rename = 'user2' @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_user(self, activate_session_mock, stdout): - user = 'user' - rename = 'user2' - args = [user] - args.append('--rename=' + rename) + def test_handle_edit_user(self, stdout): + args = [self.user] + args.append('--rename=' + self.rename) args.append('--add-krb=addedkrb') args.append('--remove-krb=removedkrb') args.append('--edit-krb=oldkrb=newkrb') - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() # Run it and check immediate output # args: user --rename=user --krb=krb # expected: success - rv = handle_edit_user(options, session, args) + rv = handle_edit_user(self.options, self.session, args) actual = stdout.getvalue() expected = '' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - activate_session_mock.assert_called_once_with(session, options) - session.editUser.assert_called_once_with(user, rename, - [{'new': 'newkrb', 'old': 'oldkrb'}, - {'new': 'addedkrb', 'old': None}, - {'new': None, 'old': 'removedkrb'}]) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.editUser.assert_called_once_with(self.user, self.rename, + [{'new': 'newkrb', 'old': 'oldkrb'}, + {'new': 'addedkrb', 'old': None}, + {'new': None, 'old': 'removedkrb'}]) self.assertEqual(rv, None) - stdout.seek(0) - stdout.truncate() - session.reset_mock() - activate_session_mock.reset_mock() - - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_user_help(self, activate_session_mock, stderr, stdout): - args = ['--help'] - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() - + def test_handle_edit_user_help(self): # Run it and check immediate output # args: --help # expected: failed, help info shows - with self.assertRaises(SystemExit) as cm: - handle_edit_user(options, session, args) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = """Usage: %s edit-user [options] + self.assert_help( + handle_edit_user, + """Usage: %s edit-user [options] (Specify the --help global option for a list of other help options) Options: @@ -79,74 +64,49 @@ Options: --edit-krb=OLD=NEW Change kerberos principal of the user --add-krb=KRB Add kerberos principal of the user --remove-krb=KRB Remove kerberos principal of the user -""" % progname - expected_stderr = '' - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) +""" % self.progname) # Finally, assert that things were called as we expected. - activate_session_mock.assert_not_called() - session.editUser.assert_not_called() - self.assertEqual(cm.exception.code, 0) - - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_user_no_arg(self, activate_session_mock, stderr, stdout): - args = [] - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() + self.activate_session_mock.assert_not_called() + self.session.editUser.assert_not_called() + def test_handle_edit_user_no_arg(self): # Run it and check immediate output # args: --help # expected: failed, help info shows - with self.assertRaises(SystemExit) as ex: - handle_edit_user(options, session, args) - self.assertExitCode(ex, 2) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = '' - expected_stderr = """Usage: %(progname)s edit-user [options] -(Specify the --help global option for a list of other help options) - -%(progname)s: error: You must specify the username of the user to edit -""" % {'progname': progname} - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) + expected = self.format_error_message("You must specify the username of the user to edit") + self.assert_system_exit( + handle_edit_user, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) # Finally, assert that things were called as we expected. - activate_session_mock.assert_not_called() - session.editUser.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.editUser.assert_not_called() - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_edit_user_more_arg(self, activate_session_mock, stderr, stdout): + def test_handle_edit_user_more_arg(self): args = ['user', 'user2'] - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() - # Run it and check immediate output # args: --help # expected: failed, help info shows - with self.assertRaises(SystemExit) as ex: - handle_edit_user(options, session, args) - self.assertExitCode(ex, 2) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = '' - expected_stderr = """Usage: %(progname)s edit-user [options] -(Specify the --help global option for a list of other help options) - -%(progname)s: error: This command only accepts one argument (username) -""" % {'progname': progname} - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) + expected = self.format_error_message("This command only accepts one argument (username)") + self.assert_system_exit( + handle_edit_user, + self.options, + self.session, + args, + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) # Finally, assert that things were called as we expected. - activate_session_mock.assert_not_called() - session.editUser.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.editUser.assert_not_called() if __name__ == '__main__': diff --git a/tests/test_cli/test_enable_channel.py b/tests/test_cli/test_enable_channel.py index 9b1274b9..2c985e2b 100644 --- a/tests/test_cli/test_enable_channel.py +++ b/tests/test_cli/test_enable_channel.py @@ -4,8 +4,8 @@ import unittest import mock import six - import koji + from koji_cli.commands import handle_enable_channel from . import utils @@ -15,6 +15,11 @@ class TestEnableChannel(utils.CliTestCase): maxDiff = None def setUp(self): + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s enable-channel [options] [ ...] (Specify the --help global option for a list of other help options) @@ -33,70 +38,61 @@ class TestEnableChannel(utils.CliTestCase): m._result = (result,) return m - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_enable_channel(self, activate_session_mock, stdout, stderr): + def test_handle_enable_channel_no_such_channel(self): """Test enable-channel function""" - options = mock.MagicMock() - session = mock.MagicMock() - - mcall = session.multicall.return_value.__enter__.return_value + mcall = self.session.multicall.return_value.__enter__.return_value mcall.getChannel.return_value = self.__vm(None) arguments = ['channel1', 'channel2'] - with self.assertRaises(SystemExit) as ex: - handle_enable_channel(options, session, arguments) - self.assertExitCode(ex, 1) - activate_session_mock.assert_called_once() - session.multicall.assert_called_once() - session.enableChannel.assert_not_called() expect = '' for host in arguments: expect += "No such channel: %s\n" % host stderr_exp = "No changes made. Please correct the command line.\n" - self.assert_console_message(stdout, expect) - self.assert_console_message(stderr, stderr_exp) - - # reset session mocks - activate_session_mock.reset_mock() - session.multicall.reset_mock() - session.enableChannel.reset_mock() - mcall = session.multicall.return_value.__enter__.return_value + self.assert_system_exit( + handle_enable_channel, + self.options, + self.session, + arguments, + stdout=expect, + stderr=stderr_exp, + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once() + self.session.multicall.assert_called_once() + self.session.enableChannel.assert_not_called() + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_enable_channel(self, stdout): + mcall = self.session.multicall.return_value.__enter__.return_value mcall.getChannel.return_value = self.__vm(self.channelinfo) arguments = ['channel1', 'channel2', '--comment', 'enable channel test'] - handle_enable_channel(options, session, arguments) - activate_session_mock.assert_called_once() - self.assertEqual(2, session.multicall.call_count) + handle_enable_channel(self.options, self.session, arguments) + self.activate_session_mock.assert_called_once() + self.assertEqual(2, self.session.multicall.call_count) self.assert_console_message(stdout, '') - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_enable_host_no_argument(self, activate_session_mock, stdout): + def test_handle_enable_host_no_argument(self): """Test enable-channel function without arguments""" - options = mock.MagicMock() - session = mock.MagicMock() - - session.getChannel.return_value = None - session.multicall.return_value = [[None]] - session.enableChannel.return_value = True + self.session.getChannel.return_value = None + self.session.multicall.return_value = [[None]] + self.session.enableChannel.return_value = True expected = self.format_error_message("At least one channel must be specified") self.assert_system_exit( handle_enable_channel, - options, - session, + self.options, + self.session, [], stderr=expected, activate_session=None) - activate_session_mock.assert_not_called() - session.getChannel.assert_not_called() - session.multicall.assert_not_called() - session.enableChannel.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.getChannel.assert_not_called() + self.session.multicall.assert_not_called() + self.session.enableChannel.assert_not_called() def test_handle_enable_channel_help(self): """Test enable-channel help message""" diff --git a/tests/test_cli/test_enable_host.py b/tests/test_cli/test_enable_host.py index 4ce6afbf..276f692f 100644 --- a/tests/test_cli/test_enable_host.py +++ b/tests/test_cli/test_enable_host.py @@ -2,6 +2,7 @@ from __future__ import absolute_import import mock import six import unittest +import koji from mock import call from koji_cli.commands import handle_enable_host @@ -9,33 +10,24 @@ from . import utils class TestEnableHost(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s enable-host [options] [ ...] (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_enable_host( - self, - activate_session_mock, - stdout, - stderr): + def test_handle_enable_host_no_such_host(self): """Test %s function""" % handle_enable_host.__name__ - arguments = [] - options = mock.MagicMock() - session = mock.MagicMock() - session.getHost.return_value = None - session.enableHost.return_value = True - session.editHost.return_value = True + self.session.getHost.return_value = None + self.session.enableHost.return_value = True + self.session.editHost.return_value = True # # session.multiCall returns: @@ -54,71 +46,66 @@ class TestEnableHost(utils.CliTestCase): # 'name': 'kbuilder02' ...}] # - session.multiCall.return_value = [[None], [None]] + self.session.multiCall.return_value = [[None], [None]] arguments = ['host1', 'host2'] - with self.assertRaises(SystemExit) as ex: - handle_enable_host(options, session, arguments) - self.assertExitCode(ex, 1) - activate_session_mock.assert_called_once() - session.getHost.assert_has_calls([call('host1'), call('host2')]) - session.multiCall.assert_called_once() - session.enableHost.assert_not_called() - session.editHost.assert_not_called() expect = '' for host in arguments: expect += "No such host: %s\n" % host stderr_exp = "No changes made. Please correct the command line.\n" - self.assert_console_message(stdout, expect) - self.assert_console_message(stderr, stderr_exp) + self.assert_system_exit( + handle_enable_host, + self.options, + self.session, + arguments, + stdout=expect, + stderr=stderr_exp, + activate_session=None, + exit_code=1 + ) + self.session.getHost.assert_has_calls([call('host1'), call('host2')]) + self.session.multiCall.assert_called_once() + self.session.enableHost.assert_not_called() + self.session.editHost.assert_not_called() - # reset session mocks - activate_session_mock.reset_mock() - session.multiCall.reset_mock() - session.disableHost.reset_mock() - session.editHost.reset_mock() - - session.multiCall.return_value = [ + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_handle_enable_host_valid(self, stdout): + self.session.multiCall.return_value = [ [{'id': 1, 'name': 'host1'}], [{'id': 2, 'name': 'host2'}] ] arguments = ['host1', 'host2', '--comment', 'disable host test'] - handle_enable_host(options, session, arguments) - activate_session_mock.assert_called_once() - session.getHost.assert_has_calls([call('host1'), call('host2')]) - self.assertEqual(2, session.multiCall.call_count) - session.enableHost.assert_has_calls([call('host1'), call('host2')]) - session.editHost.assert_has_calls( + handle_enable_host(self.options, self.session, arguments) + self.activate_session_mock.assert_called_once() + self.session.getHost.assert_has_calls([call('host1'), call('host2')]) + self.assertEqual(2, self.session.multiCall.call_count) + self.session.enableHost.assert_has_calls([call('host1'), call('host2')]) + self.session.editHost.assert_has_calls( [call('host1', comment='disable host test'), call('host2', comment='disable host test')]) self.assert_console_message(stdout, '') - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_enable_host_no_argument(self, activate_session_mock, stdout): + def test_handle_enable_host_no_argument(self): """Test %s function without arguments""" % handle_enable_host.__name__ - options = mock.MagicMock() - session = mock.MagicMock() - - session.getHost.return_value = None - session.multiCall.return_value = [[None]] - session.enableHost.return_value = True - session.editHost.return_value = True + self.session.getHost.return_value = None + self.session.multiCall.return_value = [[None]] + self.session.enableHost.return_value = True + self.session.editHost.return_value = True expected = self.format_error_message("At least one host must be specified") self.assert_system_exit( handle_enable_host, - options, - session, + self.options, + self.session, [], stderr=expected, activate_session=None) - activate_session_mock.assert_not_called() - session.getHost.assert_not_called() - session.multiCall.assert_not_called() - session.enableHost.assert_not_called() - session.editHost.assert_not_called() + self.activate_session_mock.assert_not_called() + self.session.getHost.assert_not_called() + self.session.multiCall.assert_not_called() + self.session.enableHost.assert_not_called() + self.session.editHost.assert_not_called() def test_handle_enable_host_help(self): """Test %s help message""" % handle_enable_host.__name__ diff --git a/tests/test_cli/test_enable_user.py b/tests/test_cli/test_enable_user.py index faf75990..58ce95cd 100644 --- a/tests/test_cli/test_enable_user.py +++ b/tests/test_cli/test_enable_user.py @@ -1,61 +1,58 @@ from __future__ import absolute_import import mock -import six import unittest +import koji from koji_cli.commands import handle_enable_user from . import utils class TestEnableUser(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s enable-user (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) + self.username = 'user' - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_enable_user( - self, - activate_session_mock, - stdout): + def test_handle_enable_user_no_argument(self): """Test handle_enable_user function""" - session = mock.MagicMock() - options = mock.MagicMock() - username = 'user' - - # Case 1. no argument error - expected = self.format_error_message( - "You must specify the username of the user to enable") + expected = self.format_error_message("You must specify the username of the user to enable") self.assert_system_exit( handle_enable_user, - options, - session, + self.options, + self.session, [], stderr=expected, activate_session=None) + self.activate_session_mock.assert_not_called() + self.session.enableUser.assert_not_called() - # Case 2. Too many argument error - expected = self.format_error_message( - "This command only accepts one argument (username)") + def test_handle_enable_user_to_many_arguments(self): + """Test handle_enable_user function""" + expected = self.format_error_message("This command only accepts one argument (username)") self.assert_system_exit( handle_enable_user, - options, - session, + self.options, + self.session, ['user-1', 'user-2', 'user-3'], stderr=expected, activate_session=None) + self.activate_session_mock.assert_not_called() + self.session.enableUser.assert_not_called() - # Case 3. Enable user test - handle_enable_user(options, session, [username]) - session.enableUser.assert_called_with(username) - activate_session_mock.assert_called_with(session, options) + def test_handle_enable_user_valid(self): + """Test handle_enable_user function""" + handle_enable_user(self.options, self.session, [self.username]) + self.session.enableUser.assert_called_with(self.username) + self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.enableUser.assert_called_with(self.username) def test_handle_enable_user_help(self): self.assert_help( diff --git a/tests/test_cli/test_free_task.py b/tests/test_cli/test_free_task.py index 49bceef9..705afb6b 100644 --- a/tests/test_cli/test_free_task.py +++ b/tests/test_cli/test_free_task.py @@ -10,7 +10,7 @@ class TestFreeTask(utils.CliTestCase): def setUp(self): self.options = mock.MagicMock() - self.options.maxDiff = None + self.maxDiff = None self.session = mock.MagicMock() self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s free-task [options] [ ...] @@ -19,30 +19,37 @@ class TestFreeTask(utils.CliTestCase): %s: error: {message} """ % (self.progname, self.progname) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_free_task_without_arg(self, stderr): + def test_free_task_without_arg(self): expected = self.format_error_message('please specify at least one task_id') - with self.assertRaises(SystemExit) as ex: - handle_free_task(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - self.activate_session_mock.assert_called_with(self.session, self.options) + self.assert_system_exit( + handle_free_task, + self.options, self.session, [], + stdout='', + stderr=expected, + exit_code=2, + activate_session=None) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.freeTask.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_free_task_id_string_chars(self, stderr): + def test_free_task_id_string_chars(self): expected = self.format_error_message('task_id must be an integer') - with self.assertRaises(SystemExit) as ex: - handle_free_task(self.options, self.session, ['1abc']) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - self.activate_session_mock.assert_called_with(self.session, self.options) + self.assert_system_exit( + handle_free_task, + self.options, self.session, ['1abc'], + stdout='', + stderr=expected, + exit_code=2, + activate_session=None) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.freeTask.assert_not_called() @mock.patch('sys.stdout', new_callable=StringIO) def test_free_task_valid(self, stdout): self.session.freeTask.side_effect = [True, True, True] handle_free_task(self.options, self.session, ['1', '2', '3']) self.assert_console_message(stdout, '') - self.activate_session_mock.assert_called_with(self.session, self.options) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.freeTask.assert_has_calls([mock.call(1), mock.call(2), mock.call(3)]) def test_handle_free_task_help(self): self.assert_help( diff --git a/tests/test_cli/test_grant_cg_access.py b/tests/test_cli/test_grant_cg_access.py index 2b63d897..ed71eb3e 100644 --- a/tests/test_cli/test_grant_cg_access.py +++ b/tests/test_cli/test_grant_cg_access.py @@ -1,6 +1,5 @@ from __future__ import absolute_import import mock -import six import unittest from koji_cli.commands import handle_grant_cg_access @@ -9,57 +8,60 @@ from . import utils class TestGrantCGAccess(utils.CliTestCase): - # Show long diffs in error output... - maxDiff = None - def setUp(self): self.error_format = """Usage: %s grant-cg-access (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) + self.maxDiff = None + self.options = mock.MagicMock() + self.options.quiet = False + self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.cg = 'cg' + self.user = 'user' - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_grant_cg_access( - self, - activate_session_mock, - stdout): + def test_handle_grant_cg_access_arg_error(self): """Test handle_grant_cg_access function""" - session = mock.MagicMock() - options = mock.MagicMock() - cg = 'cg' - user = 'user' - - # Case 1. argument error - expected = self.format_error_message( - "Please specify a user and content generator") - for args in [[], [user]]: + expected = self.format_error_message("Please specify a user and content generator") + for args in [[], [self.user]]: self.assert_system_exit( handle_grant_cg_access, - options, - session, + self.options, + self.session, args, stderr=expected, - activate_session=None) + activate_session=None, + exit_code=2) + self.activate_session_mock.assert_not_called() + self.session.grantCGAccess.assert_not_called() - # Case 2. user not exists - expected = self.format_error_message( - "No such user: %s" % user) - session.getUser.return_value = None + def test_handle_grant_cg_access_non_exist_user(self): + """Test handle_grant_cg_access function""" + expected = self.format_error_message("No such user: %s" % self.user) + self.session.getUser.return_value = None self.assert_system_exit( handle_grant_cg_access, - options, - session, - [user, cg], - stderr=expected) + self.options, + self.session, + [self.user, self.cg], + stderr=expected, + exit_code=2, + activate_session=None) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getUser.assert_called_once_with(self.user) + self.session.grantCGAccess.assert_not_called() - # Case 3. grant permission with --new + def test_handle_grant_cg_access_valid(self): + """Test handle_grant_cg_access function""" cg = 'content-generator' - session.getUser.return_value = {'id': 101, 'name': user} - handle_grant_cg_access(options, session, [user, cg, '--new']) - calls = [mock.call(user, cg, create=True)] - session.grantCGAccess.assert_has_calls(calls) + self.session.getUser.return_value = {'id': 101, 'name': self.user} + handle_grant_cg_access(self.options, self.session, [self.user, cg, '--new']) + calls = [mock.call(self.user, cg, create=True)] + self.session.grantCGAccess.assert_has_calls(calls) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getUser.assert_called_once_with(self.user) def test_handle_grant_cg_access_help(self): self.assert_help( diff --git a/tests/test_cli/test_hello.py b/tests/test_cli/test_hello.py index dcf840ac..a054b9bb 100644 --- a/tests/test_cli/test_hello.py +++ b/tests/test_cli/test_hello.py @@ -27,74 +27,76 @@ class TestPrintUnicode(utils.CliTestCase): class TestHello(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None + self.options = mock.MagicMock() + self.options.quiet = False + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s moshimoshi [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) self.huburl = "https://%s.local/%shub" % (self.progname, self.progname) @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.commands._printable_unicode') - @mock.patch('koji_cli.commands.activate_session') - def test_handle_moshimoshi( - self, - activate_session_mock, - print_unicode_mock, - stderr, - stdout): + def test_handle_moshimoshi(self, print_unicode_mock, stdout): """Test handle_moshimoshi function""" user = {'name': self.progname, 'krb_principal': '%s@localhost' % self.progname} cert = '/etc/pki/user.cert' - options = mock.MagicMock() - # Mock out the xmlrpc server session = mock.MagicMock(baseurl=self.huburl, authtype=None) + # Mock out the xmlrpc server session.getLoggedInUser.return_value = None session.krb_principal = user['krb_principal'] print_unicode_mock.return_value = "Hello" - expect = """Usage: %s moshimoshi [options] -(Specify the --help global option for a list of other help options) - -%s: error: This command takes no arguments -""" % (self.progname, self.progname) - self.assert_system_exit( handle_moshimoshi, - options, - session, - ['argument'], - stderr=expect, - activate_session=None) + self.options, session, ['argument'], + stderr=self.format_error_message('This command takes no arguments'), + activate_session=None, + exit_code=2) + self.activate_session_mock.assert_not_called() + session.getLoggedInUser.assert_not_called() + # annonymous user + message = "Not authenticated\n" + "Hello, anonymous user!" + hubinfo = "You are using the hub at %s" % self.huburl + handle_moshimoshi(self.options, session, []) + self.assert_console_message(stdout, "{0}\n\n{1}\n".format(message, hubinfo)) + self.activate_session_mock.assert_called_once_with(session, self.options) + session.getLoggedInUser.assert_called_once_with() + self.activate_session_mock.reset_mock() + session.getLoggedInUser.reset_mock() + + # valid authentication auth_tests = { koji.AUTHTYPE_NORMAL: 'Authenticated via password', koji.AUTHTYPE_GSSAPI: 'Authenticated via GSSAPI', koji.AUTHTYPE_KERB: 'Authenticated via Kerberos principal %s' % user['krb_principal'], koji.AUTHTYPE_SSL: 'Authenticated via client certificate %s' % - cert + cert } - - message = "Not authenticated\n" + "Hello, anonymous user!" hubinfo = "You are using the hub at %s" % self.huburl - handle_moshimoshi(options, session, []) - self.assert_console_message( - stdout, "{0}\n\n{1}\n".format(message, hubinfo)) - session.getLoggedInUser.return_value = user message = "Hello, %s!" % self.progname - options.cert = cert + self.options.cert = cert for authtype, authinfo in auth_tests.items(): session.authtype = authtype print_unicode_mock.reset_mock() print_unicode_mock.return_value = "Hello" - handle_moshimoshi(options, session, []) + handle_moshimoshi(self.options, session, []) print_unicode_mock.assert_called_once() self.assert_console_message( stdout, "{0}\n\n{1}\n{2}\n".format(message, hubinfo, authinfo)) + mock_call_activate = mock.call(session, self.options) + self.activate_session_mock.assert_has_calls([mock_call_activate, mock_call_activate, + mock_call_activate, mock_call_activate]) + session.getLoggedInUser.assert_has_calls([mock.call(), mock.call(), mock.call(), + mock.call()]) def test_handle_moshimoshi_help(self): self.assert_help( diff --git a/tests/test_cli/test_hostinfo.py b/tests/test_cli/test_hostinfo.py index 6132e54e..37dabf2e 100644 --- a/tests/test_cli/test_hostinfo.py +++ b/tests/test_cli/test_hostinfo.py @@ -4,6 +4,7 @@ import os import time import locale from six.moves import StringIO +import copy import koji from koji_cli.commands import anon_handle_hostinfo @@ -13,6 +14,7 @@ from . import utils class TestHostinfo(utils.CliTestCase): def setUp(self): # force locale to compare 'expect' value + self.maxDiff = None locale.setlocale(locale.LC_ALL, ('en_US', 'UTF-8')) self.options = mock.MagicMock() self.options.debug = False @@ -23,16 +25,22 @@ class TestHostinfo(utils.CliTestCase): time.tzset() self.hostinfo = {'arches': 'x86_64', 'capacity': 2.0, - 'comment': None, - 'description': None, 'enabled': True, 'id': 1, 'name': 'kojibuilder', 'ready': True, 'task_load': 0.0, - 'user_id': 2} + 'user_id': 2, + 'comment': 'test-comment', + 'description': 'test-description'} self.last_update = 1615875554.862938 self.list_channels = [{'id': 1, 'name': 'default'}, {'id': 2, 'name': 'createrepo'}] + self.error_format = """Usage: %s hostinfo [options] [ ...] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() def tearDown(self): locale.resetlocale() @@ -42,16 +50,18 @@ class TestHostinfo(utils.CliTestCase): os.environ['TZ'] = self.original_timezone time.tzset() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_hostinfo_without_option(self, stderr): - expected = "Usage: %s hostinfo [options] [ ...]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: Please specify a host\n" % (self.progname, self.progname) + def test_hostinfo_without_option(self): self.session.getChannel.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_hostinfo(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_hostinfo, + self.options, self.session, [], + stderr=self.format_error_message('Please specify a host'), + exit_code=2, + activate_session=None) + self.session.getHost.assert_not_called() + self.session.getLastHostUpdate.assert_not_called() + self.session.listChannels.assert_not_called() + self.ensure_connection_mock.assert_not_called() @mock.patch('sys.stdout', new_callable=StringIO) def test_hostinfo_valid(self, stdout): @@ -60,8 +70,8 @@ ID: 1 Arches: x86_64 Capacity: 2.0 Task Load: 0.00 -Description: -Comment: +Description: test-description +Comment: test-comment Enabled: yes Ready: yes Last Update: Tue, 16 Mar 2021 06:19:14 UTC @@ -78,11 +88,13 @@ None self.session.getHost.assert_called_once_with(self.hostinfo['name']) self.session.getLastHostUpdate.assert_called_once_with(self.hostinfo['id'], ts=True) self.session.listChannels.assert_called_once_with(hostID=self.hostinfo['id']) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) self.assertEqual(self.session.listBuildroots.call_count, 3) - @mock.patch('sys.stderr', new_callable=StringIO) - @mock.patch('sys.stdout', new_callable=StringIO) - def test_hostinfo_more_hosts_with_non_exit_host(self, stdout, stderr): + def test_hostinfo_more_hosts_with_non_exit_host(self): + hostinfo = copy.deepcopy(self.hostinfo) + hostinfo['description'] = None + hostinfo['comment'] = None hostname = 'kojibuilder' non_exist_hostname = 'testhost' expected_stdout = """Name: kojibuilder @@ -99,28 +111,58 @@ Channels: default createrepo Active Buildroots: None """ - expected_error = "No such host: %s\n\n" % non_exist_hostname - self.session.getHost.side_effect = [None, self.hostinfo] + self.session.getHost.side_effect = [None, hostinfo] self.session.getLastHostUpdate.return_value = self.last_update self.session.listChannels.return_value = self.list_channels self.session.listBuildroots.return_value = [] - with self.assertRaises(SystemExit) as ex: - anon_handle_hostinfo(self.options, self.session, [non_exist_hostname, hostname]) - self.assertExitCode(ex, 1) - self.assert_console_message(stdout, expected_stdout) - self.assert_console_message(stderr, expected_error) + self.assert_system_exit( + anon_handle_hostinfo, + self.options, self.session, [non_exist_hostname, hostname], + stderr="No such host: %s\n\n" % non_exist_hostname, + stdout=expected_stdout, + exit_code=1, + activate_session=None) self.assertEqual(self.session.getHost.call_count, 2) self.session.getLastHostUpdate.assert_called_once_with(self.hostinfo['id'], ts=True) self.session.listChannels.assert_called_once_with(hostID=self.hostinfo['id']) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) self.assertEqual(self.session.listBuildroots.call_count, 3) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_hostinfo_non_exist_host(self, stderr): - hostname = 'testhost' - expected = "No such host: %s\n\n" % hostname + def test_hostinfo_non_exist_host(self): + hostname = '1111' self.session.getHost.return_value = None self.session.getLastHostUpdate.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_hostinfo(self.options, self.session, [hostname]) - self.assertExitCode(ex, 1) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_hostinfo, + self.options, self.session, [hostname], + stderr="No such host: %s\n\n" % hostname, + stdout='', + exit_code=1, + activate_session=None) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_hostinfo_valid_param_error(self, stdout): + expected = """Name: kojibuilder +ID: 1 +Arches: x86_64 +Capacity: 2.0 +Task Load: 0.00 +Description: test-description +Comment: test-comment +Enabled: yes +Ready: yes +Last Update: Tue, 16 Mar 2021 06:19:14 UTC +Channels: default createrepo +Active Buildroots: +None +""" + self.session.getHost.return_value = self.hostinfo + self.session.getLastHostUpdate.side_effect = [koji.ParameterError, self.last_update] + self.session.listChannels.return_value = self.list_channels + rv = anon_handle_hostinfo(self.options, self.session, [self.hostinfo['name']]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getHost.assert_called_once_with(self.hostinfo['name']) + self.session.listChannels.assert_called_once_with(hostID=self.hostinfo['id']) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.assertEqual(self.session.listBuildroots.call_count, 3) diff --git a/tests/test_cli/test_image_build.py b/tests/test_cli/test_image_build.py index 313e679e..42e2e565 100644 --- a/tests/test_cli/test_image_build.py +++ b/tests/test_cli/test_image_build.py @@ -58,6 +58,7 @@ TASK_OPTIONS = { "wait": None, } + def mock_open(): """Return the right patch decorator for open""" if six.PY2: @@ -73,11 +74,8 @@ class Options(object): class TestBuildImageOz(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.task_options = Options(TASK_OPTIONS) self.session = mock.MagicMock() self.options = mock.MagicMock() @@ -190,37 +188,27 @@ class TestBuildImageOz(utils.CliTestCase): def test_build_image_oz_exception(self): self.session.getBuildTarget.return_value = {} with self.assertRaises(koji.GenericError) as cm: - _build_image_oz( - self.options, self.task_options, self.session, self.args) - self.assertEqual( - str(cm.exception), 'No such build target: %s' % self.args[2]) + _build_image_oz(self.options, self.task_options, self.session, self.args) + self.assertEqual(str(cm.exception), 'No such build target: %s' % self.args[2]) self.session.getBuildTarget.return_value = self.target_info self.session.getTag.return_value = {} with self.assertRaises(koji.GenericError) as cm: - _build_image_oz( - self.options, self.task_options, self.session, self.args) - self.assertEqual( - str(cm.exception), - 'No such destination tag: %s' % self.target_info['dest_tag_name']) + _build_image_oz(self.options, self.task_options, self.session, self.args) + self.assertEqual(str(cm.exception), + 'No such destination tag: %s' % self.target_info['dest_tag_name']) self.session.getTag.return_value = self.tag_info with self.assertRaises(koji.GenericError) as cm: self.task_options.ksurl = None self.task_options.scratch = False - _build_image_oz( - self.options, self.task_options, self.session, self.args) - self.assertEqual( - str(cm.exception), - 'Non-scratch builds must provide ksurl') + _build_image_oz(self.options, self.task_options, self.session, self.args) + self.assertEqual(str(cm.exception), 'Non-scratch builds must provide ksurl') class TestImageBuild(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.options = mock.MagicMock() self.session = mock.MagicMock() self.configparser = mock.patch('six.moves.configparser.ConfigParser').start() @@ -236,37 +224,37 @@ class TestImageBuild(utils.CliTestCase): def tearDown(self): mock.patch.stopall() - @mock.patch('koji_cli.commands._build_image_oz') - def test_handle_image_build_with_config(self, build_image_oz_mock): - """Test handle_image_build argument with --config cases""" - - # Case 1, config file not exist case + def test_handle_image_build_with_config_error(self): + """Test handle_image_build argument with --config, config error""" with self.assertRaises(koji.ConfigurationError) as cm: handle_image_build(self.options, self.session, ['--config', '/nonexistent-file-755684354']) self.assertEqual(cm.exception.args[0], "Config file /nonexistent-file-755684354 can't be opened.") + self.session.activate_session_mock.assert_not_called() - - # Case 2, no image-build section in config file + def test_handle_image_build_with_config_no_image_section(self): + """Test handle_image_build argument with --config, no image section""" expected = "single section called [%s] is required" % "image-build" self.configparser.return_value = ConfigParser() self.assert_system_exit( handle_image_build, - self.options, - self.session, - ['--config', - os.path.join(os.path.dirname(__file__), - 'data/image-build-config-empty.conf')], + self.options, self.session, ['--config', + os.path.join(os.path.dirname(__file__), + 'data/image-build-config-empty.conf')], stderr=self.format_error_message(expected), - activate_session=None) + activate_session=None, + exit_code=2) + self.session.activate_session_mock.assert_not_called() - config_file = os.path.join(os.path.dirname(__file__), - 'data/image-build-config.conf') - # Case 3, normal + @mock.patch('koji_cli.commands._build_image_oz') + def test_handle_image_build_with_config_valid_with_config(self, build_image_oz_mock): + """Test handle_image_build.""" + config_file = os.path.join(os.path.dirname(__file__), 'data/image-build-config.conf') + self.configparser.return_value = ConfigParser() handle_image_build( self.options, self.session, @@ -275,52 +263,53 @@ class TestImageBuild(utils.CliTestCase): args, kwargs = build_image_oz_mock.call_args TASK_OPTIONS['config'] = config_file self.assertDictEqual(TASK_OPTIONS, args[1].__dict__) + self.session.activate_session_mock.assert_not_called() - @mock.patch('koji_cli.commands.activate_session') - def test_handle_image_build_argument_error_without_config( - self, - activate_session_mock): - """Test handle_image_build argument errors, no --config cases""" - - # Case 1, empty argument error + def test_handle_image_build_argument_error_without_config_arg_error(self): + """Test handle_image_build argument errors, no --config, arguments error""" expected = "At least five arguments are required: a name, " + \ "a version, a build target, a URL to an " + \ "install tree, and 1 or more architectures." self.assert_system_exit( - handle_image_build, - self.options, - self.session, - [], - stderr=self.format_error_message(expected), - activate_session=None) + handle_image_build, + self.options, + self.session, + [], + stderr=self.format_error_message(expected), + activate_session=None, + exit_code=2) + self.session.activate_session_mock.assert_not_called() - # Case 2, not kickstart options (--ksurl, kickstart) + def test_handle_image_build_argument_error_without_config_without_kickstart_option(self): + """Test handle_image_build argument errors, no --config cases, + without kickstart option (--ksurl, kickstart)""" expected = "You must specify --kickstart" self.assert_system_exit( - handle_image_build, - self.options, - self.session, - ['name', 'version', 'target', 'install-tree-url', 'arch'], - stderr=self.format_error_message(expected), - activate_session=None) + handle_image_build, + self.options, + self.session, + ['name', 'version', 'target', 'install-tree-url', 'arch'], + stderr=self.format_error_message(expected), + activate_session=None, + exit_code=2) + self.session.activate_session_mock.assert_not_called() - # Case 3, no --distro + def test_handle_image_build_argument_error_without_config_without_distro_option(self): + """Test handle_image_build argument errors, no --config cases, without distro option""" expected = "You must specify --distro. Examples: Fedora-16, RHEL-6.4, " + \ "SL-6.4 or CentOS-6.4" self.assert_system_exit( - handle_image_build, - self.options, - self.session, - ['name', 'version', 'target', 'install-tree-url', 'arch', - '--kickstart', 'kickstart.ks'], - stderr=self.format_error_message(expected), - activate_session=None) - - # activate_session() should not be called - activate_session_mock.assert_not_called() + handle_image_build, + self.options, + self.session, + ['name', 'version', 'target', 'install-tree-url', 'arch', + '--kickstart', 'kickstart.ks'], + stderr=self.format_error_message(expected), + activate_session=None, + exit_code=2) def test_handle_image_build_help(self): """Test handle_image_build help message""" diff --git a/tests/test_cli/test_image_build_indirection.py b/tests/test_cli/test_image_build_indirection.py index 89a12cbc..0610c0f1 100644 --- a/tests/test_cli/test_image_build_indirection.py +++ b/tests/test_cli/test_image_build_indirection.py @@ -38,11 +38,8 @@ class Options(object): class TestBuildImageIndirection(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.task_id = 1001 self.weburl = 'https://web.url' self.options = mock.MagicMock() @@ -188,11 +185,8 @@ class TestBuildImageIndirection(utils.CliTestCase): class TestImageBuildIndirection(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.options = mock.MagicMock() self.session = mock.MagicMock() diff --git a/tests/test_cli/test_import.py b/tests/test_cli/test_import.py index a191813d..e91a5a76 100644 --- a/tests/test_cli/test_import.py +++ b/tests/test_cli/test_import.py @@ -8,18 +8,17 @@ import koji from koji_cli.commands import handle_import from . import utils + def md5_to_bytes(s): if six.PY2: return bytearray.fromhex(unicode(s)) else: return bytearray.fromhex(s) + class TestImport(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.huburl = "https://%s.local/%shub" % (self.progname, self.progname) self.md5 = '00112233445566778899aabbccddeeff' self.fake_srv_dir = '/path/to/server/import' @@ -133,7 +132,7 @@ class TestImport(utils.CliTestCase): @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.commands.activate_session') def __skip_import_test(self, options, session, arguments, activate_session_mock, - stderr, stdout, **kwargs): + stderr, stdout, **kwargs): expected = kwargs.get('expected', None) expected_warn = kwargs.get('expected_warn', None) rpm_header = kwargs.get('rpm_header', {}) diff --git a/tests/test_cli/test_import_archive.py b/tests/test_cli/test_import_archive.py index 15d2e368..9887df2e 100644 --- a/tests/test_cli/test_import_archive.py +++ b/tests/test_cli/test_import_archive.py @@ -1,7 +1,6 @@ from __future__ import absolute_import import mock -from six.moves import StringIO import koji from koji_cli.commands import handle_import_archive @@ -10,6 +9,7 @@ from . import utils class TestImportArchive(utils.CliTestCase): def setUp(self): + self.maxDiff = None self.options = mock.MagicMock() self.options.debug = False self.session = mock.MagicMock() @@ -23,120 +23,197 @@ class TestImportArchive(utils.CliTestCase): %s: error: {message} """ % (self.progname, self.progname) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_without_option(self, stderr): + def test_import_archive_without_option(self): expected = self.format_error_message( "You must specify a build ID or N-V-R and an archive to import") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, [], + stdout='', + stderr=expected, + exit_code=2, + activate_session=None) self.activate_session_mock.assert_not_called() + self.session.hasPerm.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_wrong_type(self, stderr): + def test_import_archive_wrong_type(self): archive_type = 'test-type' expected = self.format_error_message("Unsupported archive type: %s" % archive_type) - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, ['--type', archive_type, - self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=expected, + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_without_type(self, stderr): - expected = self.format_error_message("You must specify an archive type") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, [self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + + def test_import_archive_without_type(self): + self.assert_system_exit( + handle_import_archive, + self.options, self.session, [self.build_id, self.archive_path], + stdout='', + stderr=self.format_error_message("You must specify an archive type"), + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_maven_without_perm(self, stderr): + def test_import_archive_type_maven_without_perm(self): archive_type = 'maven' self.session.hasPerm.side_effect = [False, False] - expected = self.format_error_message("This action requires the maven-import privilege") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=self.format_error_message("This action requires the maven-import privilege"), + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('maven-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_maven_without_type_info(self, stderr): + def test_import_archive_type_maven_without_type_info(self): archive_type = 'maven' self.session.hasPerm.side_effect = [False, True] expected = self.format_error_message( "--type-info must point to a .pom file when importing Maven archives") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=expected, + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('maven-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_win_without_perm(self, stderr): + def test_import_archive_type_win_without_perm(self): archive_type = 'win' self.session.hasPerm.side_effect = [False, False] - expected = self.format_error_message("This action requires the win-import privilege") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=self.format_error_message("This action requires the win-import privilege"), + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('win-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_win_without_type_info(self, stderr): + def test_import_archive_type_win_without_type_info(self): archive_type = 'win' self.session.hasPerm.side_effect = [False, True] - expected = self.format_error_message("--type-info must be specified") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=self.format_error_message("--type-info must be specified"), + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('win-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_win_wrong_type_info(self, stderr): + def test_import_archive_type_win_wrong_type_info(self): archive_type = 'win' type_info = 'archive-type' self.session.hasPerm.side_effect = [False, True] expected = self.format_error_message( "--type-info must be in relpath:platforms[:flags] format") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, '--type-info', type_info, - self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, + ['--type', archive_type, '--type-info', type_info, self.build_id, self.archive_path], + stdout='', + stderr=expected, + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('win-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_image_without_perm(self, stderr): + def test_import_archive_type_image_without_perm(self): archive_type = 'image' self.session.hasPerm.side_effect = [False, False] - expected = self.format_error_message("This action requires the image-import privilege") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=self.format_error_message("This action requires the image-import privilege"), + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('image-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_import_archive_type_image_without_type_info(self, stderr): + def test_import_archive_type_image_without_type_info(self): archive_type = 'image' self.session.hasPerm.side_effect = [False, True] - expected = self.format_error_message("--type-info must be specified") - with self.assertRaises(SystemExit) as ex: - handle_import_archive(self.options, self.session, - ['--type', archive_type, self.build_id, self.archive_path]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + handle_import_archive, + self.options, self.session, ['--type', archive_type, self.build_id, self.archive_path], + stdout='', + stderr=self.format_error_message("--type-info must be specified"), + exit_code=2, + activate_session=None) self.activate_session_mock.assert_called_with(self.session, self.options) + self.session.hasPerm.assert_has_calls([mock.call('image-import'), mock.call('admin')]) + self.session.getBuild.assert_not_called() + self.session.createMavenBuild.assert_not_called() + self.session.createWinBuild.assert_not_called() + self.session.createImageBuild.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.importArchive.assert_not_called() diff --git a/tests/test_cli/test_import_cg.py b/tests/test_cli/test_import_cg.py index 8bd7c0c2..3854702f 100644 --- a/tests/test_cli/test_import_cg.py +++ b/tests/test_cli/test_import_cg.py @@ -12,18 +12,22 @@ import unittest class TestImportCG(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def mock_os_path_exists(self, filepath): if filepath in self.custom_os_path_exists: return self.custom_os_path_exists[filepath] return self.os_path_exists(filepath) def setUp(self): + self.maxDiff = None + self.options = mock.MagicMock() + self.session = mock.MagicMock() self.custom_os_path_exists = {} self.os_path_exists = os.path.exists + self.unique_path_mock = mock.patch('koji_cli.commands.unique_path').start() + self.running_in_bg = mock.patch('koji_cli.commands._running_in_bg').start() + self.running_in_bg.return_value = False + self.linked_upload_mock = mock.patch('koji_cli.commands.linked_upload').start() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.error_format = """Usage: %s import-cg [options] (Specify the --help global option for a list of other help options) @@ -32,24 +36,10 @@ class TestImportCG(utils.CliTestCase): @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.commands._progress_callback') - @mock.patch('koji_cli.commands.unique_path') - @mock.patch('koji_cli.commands._running_in_bg', return_value=False) - @mock.patch('koji_cli.commands.linked_upload') - @mock.patch('koji_cli.commands.activate_session') @mock.patch('koji.json') - def test_handle_import_cg( - self, - json_mock, - activate_session_mock, - linked_upload_mock, - running_in_bg_mock, - unique_path_mock, - progress_callback_mock, - stdout): + def test_handle_import_cg(self, json_mock, progress_callback_mock, stdout): """Test handle_import_cg function""" arguments = ['fake-metafile', '/path/to/files/'] - options = mock.MagicMock() - session = mock.MagicMock() expected = '' fake_srv_path = '/path/to/server/cli-import' @@ -82,51 +72,51 @@ class TestImportCG(utils.CliTestCase): return calls, expect json_mock.load.return_value = metadata - unique_path_mock.return_value = fake_srv_path + self.unique_path_mock.return_value = fake_srv_path # Case 1, running in fg, progress on with mock.patch(utils.get_builtin_open()): - handle_import_cg(options, session, arguments) + handle_import_cg(self.options, self.session, arguments) calls, expected = gen_value("Uploading %s\n", progress_callback_mock) self.assert_console_message(stdout, expected) - linked_upload_mock.assert_not_called() - session.uploadWrapper.assert_has_calls(calls) - session.CGImport.assert_called_with(metadata, fake_srv_path, None) + self.linked_upload_mock.assert_not_called() + self.session.uploadWrapper.assert_has_calls(calls) + self.session.CGImport.assert_called_with(metadata, fake_srv_path, None) # Case 2, running in fg, progress off with mock.patch(utils.get_builtin_open()): - handle_import_cg(options, session, arguments + ['--noprogress']) + handle_import_cg(self.options, self.session, arguments + ['--noprogress']) calls, expected = gen_value("Uploading %s", None) self.assert_console_message(stdout, expected) - linked_upload_mock.assert_not_called() - session.uploadWrapper.assert_has_calls(calls) - session.CGImport.assert_called_with(metadata, fake_srv_path, None) + self.linked_upload_mock.assert_not_called() + self.session.uploadWrapper.assert_has_calls(calls) + self.session.CGImport.assert_called_with(metadata, fake_srv_path, None) # reset mocks - linked_upload_mock.reset_mock() - session.uploadWrapper.reset_mock() - session.CGImport.reset_mock() + self.linked_upload_mock.reset_mock() + self.session.uploadWrapper.reset_mock() + self.session.CGImport.reset_mock() # Case 3, --test option with mock.patch(utils.get_builtin_open()): - handle_import_cg(options, session, arguments + ['--test']) + handle_import_cg(self.options, self.session, arguments + ['--test']) - linked_upload_mock.assert_not_called() - session.uploadWrapper.assert_not_called() - session.CGImport.assert_not_called() + self.linked_upload_mock.assert_not_called() + self.session.uploadWrapper.assert_not_called() + self.session.CGImport.assert_not_called() calls = [call("%(relpath)s/%(filename)s" % item, item['relpath']) for item in metadata['output']] # Case 4, --link option with mock.patch(utils.get_builtin_open()): - handle_import_cg(options, session, arguments + ['--link']) + handle_import_cg(self.options, self.session, arguments + ['--link']) - linked_upload_mock.assert_has_calls(calls) - session.uploadWrapper.assert_not_called() - session.CGImport.assert_called_with(metadata, fake_srv_path, None) + self.linked_upload_mock.assert_has_calls(calls) + self.session.uploadWrapper.assert_not_called() + self.session.CGImport.assert_called_with(metadata, fake_srv_path, None) # make sure there is no message on output self.assert_console_message(stdout, '') @@ -137,19 +127,12 @@ class TestImportCG(utils.CliTestCase): def test_handle_import_argument_test(self): """Test handle_import_cg function without arguments""" arguments = ['fake-metafile', '/path/to/files/'] - options = mock.MagicMock() - session = mock.MagicMock() # Case 1. empty argument - expected = self.format_error_message( - "Please specify metadata files directory") - self.assert_system_exit( handle_import_cg, - options, - session, - [], - stderr=expected, + self.options, self.session, [], + stderr=self.format_error_message("Please specify metadata files directory"), activate_session=None) # Case 2. JSON module does not exist @@ -173,26 +156,20 @@ class TestImportCG(utils.CliTestCase): # Case 3. metafile doesn't have output section json_mock.load.return_value = {} - expected = "Metadata contains no output\n" self.assert_system_exit( handle_import_cg, - options, - session, - arguments, - stderr=expected, + self.options, self.session, arguments, + stderr="Metadata contains no output\n", exit_code=1) # Case 4. path not exist file_path = '%(relpath)s/%(filename)s' % metadata['output'][1] json_mock.load.return_value = metadata - expected = self.format_error_message( - "No such file: %s" % file_path) self.assert_system_exit( handle_import_cg, - options, - session, - arguments, - stderr=expected) + self.options, self.session, arguments, + stderr=self.format_error_message("No such file: %s" % file_path), + exit_code=2) def test_handle_import_cg_help(self): """Test handle_import_cg help message""" diff --git a/tests/test_cli/test_import_comps.py b/tests/test_cli/test_import_comps.py index 432aa657..d28d6d22 100644 --- a/tests/test_cli/test_import_comps.py +++ b/tests/test_cli/test_import_comps.py @@ -5,6 +5,7 @@ import sys import unittest import json import pytest +import koji import mock import six @@ -24,19 +25,27 @@ from . import utils class TestImportComps(utils.CliTestCase): - # Show long diffs in error output... - maxDiff = None + def setUp(self): + self.maxDiff = None + self.options = mock.MagicMock() + self.options.debug = False + self.session = mock.MagicMock() + self.session.getAPIVersion.return_value = koji.API_VERSION + self.mock_activate_session = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s import-comps [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.commands.libcomps') - @mock.patch('koji_cli.commands.activate_session') @mock.patch('koji_cli.commands._import_comps') @mock.patch('koji_cli.commands._import_comps_alt') def test_handle_import_comps_libcomps( self, mock_import_comps_alt, mock_import_comps, - mock_activate_session, libcomps, stdout): filename = './data/comps-example.xml' @@ -45,39 +54,33 @@ class TestImportComps(utils.CliTestCase): force = None args = [filename, tag] kwargs = {'force': force} - options = mock.MagicMock() - # Mock out the xmlrpc server - session = mock.MagicMock() - session.getTag.return_value = tag_info + self.session.getTag.return_value = tag_info # Run it and check immediate output # args: ./data/comps-example.xml, tag # expected: success - rv = handle_import_comps(options, session, args) + rv = handle_import_comps(self.options, self.session, args) actual = stdout.getvalue() expected = '' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - mock_activate_session.assert_called_once_with(session, options) - session.getTag.assert_called_once_with(tag) - mock_import_comps.assert_called_once_with( - session, filename, tag, kwargs) + self.mock_activate_session.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(tag) + mock_import_comps.assert_called_once_with(self.session, filename, tag, kwargs) mock_import_comps_alt.assert_not_called() self.assertNotEqual(rv, 1) @mock.patch('sys.stdout', new_callable=six.StringIO) @mock.patch('koji_cli.commands.libcomps', new=None) @mock.patch('koji_cli.commands.yumcomps', create=True) - @mock.patch('koji_cli.commands.activate_session') @mock.patch('koji_cli.commands._import_comps') @mock.patch('koji_cli.commands._import_comps_alt') def test_handle_import_comps_yumcomps( self, mock_import_comps_alt, mock_import_comps, - mock_activate_session, yumcomps, stdout): filename = './data/comps-example.xml' @@ -86,140 +89,95 @@ class TestImportComps(utils.CliTestCase): force = True args = ['--force', filename, tag] local_options = {'force': force} - options = mock.MagicMock() - # Mock out the xmlrpc server - session = mock.MagicMock() - session.getTag.return_value = tag_info + self.session.getTag.return_value = tag_info # Run it and check immediate output # args: --force, ./data/comps-example.xml, tag # expected: success - rv = handle_import_comps(options, session, args) + rv = handle_import_comps(self.options, self.session, args) actual = stdout.getvalue() expected = '' self.assertMultiLineEqual(actual, expected) # Finally, assert that things were called as we expected. - mock_activate_session.assert_called_once_with(session, options) - session.getTag.assert_called_once_with(tag) + self.mock_activate_session.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(tag) mock_import_comps.assert_not_called() - mock_import_comps_alt.assert_called_once_with( - session, filename, tag, local_options) + mock_import_comps_alt.assert_called_once_with(self.session, filename, tag, local_options) self.assertNotEqual(rv, 1) - @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('koji_cli.commands.libcomps', new=None) @mock.patch('koji_cli.commands.yumcomps', new=None, create=True) - @mock.patch('koji_cli.commands.activate_session') @mock.patch('koji_cli.commands._import_comps') @mock.patch('koji_cli.commands._import_comps_alt') - def test_handle_import_comps_comps_na( - self, - mock_import_comps_alt, - mock_import_comps, - mock_activate_session, - stderr): + def test_handle_import_comps_comps_na(self, mock_import_comps_alt, mock_import_comps): filename = './data/comps-example.xml' tag = 'tag' tag_info = {'name': tag, 'id': 1} args = ['--force', filename, tag] - options = mock.MagicMock() - # Mock out the xmlrpc server - session = mock.MagicMock() - session.getTag.return_value = tag_info + self.session.getTag.return_value = tag_info # Run it and check immediate output # args: --force, ./data/comps-example.xml, tag # expected: failed, no comps available - with self.assertRaises(SystemExit) as ex: - handle_import_comps(options, session, args) - self.assertExitCode(ex, 1) - actual = stderr.getvalue() - expected = 'comps module not available\n' - self.assertMultiLineEqual(actual, expected) + self.assert_system_exit( + handle_import_comps, + self.options, self.session, args, + stderr='comps module not available\n', + exit_code=1, + activate_session=None) # Finally, assert that things were called as we expected. - mock_activate_session.assert_called_once_with(session, options) - session.getTag.assert_called_once_with(tag) + self.mock_activate_session.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(tag) mock_import_comps.assert_not_called() mock_import_comps_alt.assert_not_called() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') @mock.patch('koji_cli.commands._import_comps') @mock.patch('koji_cli.commands._import_comps_alt') - def test_handle_import_comps_tag_not_exists( - self, - mock_import_comps_alt, - mock_import_comps, - mock_activate_session, - stderr): + def test_handle_import_comps_tag_not_exists(self, mock_import_comps_alt, mock_import_comps): filename = './data/comps-example.xml' tag = 'tag' tag_info = None args = [filename, tag] - options = mock.MagicMock() - # Mock out the xmlrpc server - session = mock.MagicMock() - session.getTag.return_value = tag_info + self.session.getTag.return_value = tag_info # Run it and check immediate output # args: ./data/comps-example.xml, tag # expected: failed: tag does not exist - with self.assertRaises(SystemExit) as ex: - handle_import_comps(options, session, args) - self.assertExitCode(ex, 1) - actual = stderr.getvalue() - expected = 'No such tag: %s\n' % tag - self.assertMultiLineEqual(actual, expected) + self.assert_system_exit( + handle_import_comps, + self.options, self.session, args, + stderr='No such tag: %s\n' % tag, + exit_code=1, + activate_session=None) # Finally, assert that things were called as we expected. - mock_activate_session.assert_called_once_with(session, options) - session.getTag.assert_called_once_with(tag) + self.mock_activate_session.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(tag) mock_import_comps.assert_not_called() mock_import_comps_alt.assert_not_called() - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - @mock.patch('koji_cli.commands._import_comps') - @mock.patch('koji_cli.commands._import_comps_alt') - def test_handle_import_comps_help( - self, - mock_import_comps_alt, mock_import_comps, - mock_activate_session, - stderr, - stdout): + def test_handle_import_comps_empty_args(self): args = [] - progname = os.path.basename(sys.argv[0]) or 'koji' - options = mock.MagicMock() - - # Mock out the xmlrpc server - session = mock.MagicMock() # Run it and check immediate output - with self.assertRaises(SystemExit) as ex: - handle_import_comps(options, session, args) - self.assertExitCode(ex, 2) - actual_stdout = stdout.getvalue() - actual_stderr = stderr.getvalue() - expected_stdout = '' - expected_stderr = """Usage: %s import-comps [options] -(Specify the --help global option for a list of other help options) - -%s: error: Incorrect number of arguments -""" % (progname, progname) - self.assertMultiLineEqual(actual_stdout, expected_stdout) - self.assertMultiLineEqual(actual_stderr, expected_stderr) + self.assert_system_exit( + handle_import_comps, + self.options, self.session, args, + stdout='', + stderr=self.format_error_message('Incorrect number of arguments'), + exit_code=2, + activate_session=None) # Finally, assert that things were called as we expected. - mock_activate_session.assert_not_called() - session.getTag.assert_not_called() - session.getTagGroups.assert_not_called() - session.groupListAdd.assert_not_called() + self.mock_activate_session.assert_not_called() + self.session.getTag.assert_not_called() + self.session.getTagGroups.assert_not_called() + self.session.groupListAdd.assert_not_called() @mock.patch('sys.stdout', new_callable=six.StringIO) def _test_import_comps_libcomps(self, stdout): @@ -297,16 +255,13 @@ class TestImportComps(utils.CliTestCase): calls_file, stdout): tag = 'tag' - options = mock.MagicMock() - options.force = None - # Mock out the xmlrpc server - session = mock.MagicMock() + self.options.force = None # Run it and check immediate output # args: comps.xml, tag # expected: success - rv = method.__call__(session, comps_file, tag, options) + rv = method.__call__(self.session, comps_file, tag, self.options) expected = '' with open(stdout_file, 'rb') as f: expected = f.read().decode('ascii') @@ -317,10 +272,10 @@ class TestImportComps(utils.CliTestCase): for c in json.load(open(calls_file, 'rt')): expected.append(getattr(mock.call, c[0]).__call__(*c[1], **c[2])) - if hasattr(session, 'assertHasCalls'): - session.assertHasCalls(expected) + if hasattr(self.session, 'assertHasCalls'): + self.session.assertHasCalls(expected) else: - session.assert_has_calls(expected) + self.session.assert_has_calls(expected) self.assertNotEqual(rv, 1) diff --git a/tests/test_cli/test_import_sig.py b/tests/test_cli/test_import_sig.py index 477f45ec..12041fcb 100644 --- a/tests/test_cli/test_import_sig.py +++ b/tests/test_cli/test_import_sig.py @@ -16,10 +16,6 @@ import os class TestImportSIG(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def md5sum(self, message): md5 = hashlib.md5() md5.update(message.encode('utf-8')) @@ -31,6 +27,10 @@ class TestImportSIG(utils.CliTestCase): return self.os_path_exists(filepath) def setUp(self): + self.maxDiff = None + self.options = mock.MagicMock() + self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() self.custom_os_path_exists = {} self.os_path_exists = os.path.exists @@ -81,18 +81,15 @@ class TestImportSIG(utils.CliTestCase): @mock.patch('koji.rip_rpm_sighdr') @mock.patch('koji.get_sigpacket_key_id') @mock.patch('koji.get_header_fields') - @mock.patch('koji_cli.commands.activate_session') def test_handle_import_sig( self, - activate_session_mock, get_header_fields_mock, get_sigpacket_key_id_mock, rip_rpm_sighdr_mock, stdout, stderr): """Test handle_import_sig function""" arguments = ['/path/to/bash', '/path/to/less', '/path/to/sed'] - options = mock.MagicMock() - session = mock.MagicMock() + expected = '' fake_sigkey = '00112233445566778899aAbBcCdDeEfF' @@ -102,8 +99,7 @@ class TestImportSIG(utils.CliTestCase): self.custom_os_path_exists = dict((f, True) for f in arguments) # setup and start os.path.exists patch - os_path_exists_patch = mock.patch('os.path.exists', - new=self.mock_os_path_exists) + os_path_exists_patch = mock.patch('os.path.exists', new=self.mock_os_path_exists) os_path_exists_patch.start() # Case 1, Unsigned pkg test (without ----with-unsigned) @@ -114,12 +110,12 @@ class TestImportSIG(utils.CliTestCase): get_header_fields_mock.side_effect = copy.deepcopy(self.rpm_headers) # Run - handle_import_sig(options, session, arguments) + handle_import_sig(self.options, self.session, arguments) self.assert_console_message(stdout, expected) - activate_session_mock.assert_called_once() + self.activate_session_mock.assert_called_once() rip_rpm_sighdr_mock.assert_not_called() - session.getRPM.assert_not_called() + self.session.getRPM.assert_not_called() # Case 2, No RPM in system # result: import skipped @@ -136,14 +132,14 @@ class TestImportSIG(utils.CliTestCase): get_header_fields_mock.side_effect = copy.deepcopy(self.rpm_headers) get_sigpacket_key_id_mock.return_value = fake_sigkey - session.getRPM.return_value = {} + self.session.getRPM.return_value = {} # Run - handle_import_sig(options, session, arguments) + handle_import_sig(self.options, self.session, arguments) self.assert_console_message(stdout, expected) rip_rpm_sighdr_mock.assert_not_called() - session.queryRPMSigs.assert_not_called() + self.session.queryRPMSigs.assert_not_called() # Case 3, Find external repo RPM # result: import skipped @@ -159,14 +155,14 @@ class TestImportSIG(utils.CliTestCase): expected += "Skipping external rpm: %(name)s-%(version)s-%(release)s.%(arch)s@%(external_repo_name)s" % data + "\n" get_header_fields_mock.side_effect = rinfo - session.getRPM.side_effect = rinfo + self.session.getRPM.side_effect = rinfo # Run - handle_import_sig(options, session, arguments) + handle_import_sig(self.options, self.session, arguments) self.assert_console_message(stdout, expected) rip_rpm_sighdr_mock.assert_not_called() - session.queryRPMSigs.assert_not_called() + self.session.queryRPMSigs.assert_not_called() # Case 4, has previous RPM signature # result: import skipped @@ -196,12 +192,12 @@ class TestImportSIG(utils.CliTestCase): data['id'] = i + 1 get_header_fields_mock.side_effect = copy.deepcopy(rinfo) - session.getRPM.side_effect = rinfo + self.session.getRPM.side_effect = rinfo rip_rpm_sighdr_mock.side_effect = sighdr - session.queryRPMSigs.side_effect = sigRpm + self.session.queryRPMSigs.side_effect = sigRpm # Run - handle_import_sig(options, session, arguments) + handle_import_sig(self.options, self.session, arguments) self.assert_console_message(stdout, expected) self.assert_console_message(stderr, expected_warn) @@ -215,22 +211,22 @@ class TestImportSIG(utils.CliTestCase): expected += "Writing signed copy" + "\n" get_header_fields_mock.side_effect = copy.deepcopy(rinfo) - session.getRPM.side_effect = rinfo + self.session.getRPM.side_effect = rinfo rip_rpm_sighdr_mock.side_effect = sighdr - session.queryRPMSigs.side_effect = None - session.queryRPMSigs.return_value = [] + self.session.queryRPMSigs.side_effect = None + self.session.queryRPMSigs.return_value = [] # Run - handle_import_sig(options, session, arguments + ['--test']) + handle_import_sig(self.options, self.session, arguments + ['--test']) self.assert_console_message(stdout, expected) - session.addRPMSig.assert_not_called() - session.writeSignedRPM.assert_not_called() + self.session.addRPMSig.assert_not_called() + self.session.writeSignedRPM.assert_not_called() # Case 6, normal import # result: addRPMSig/writeSignedRPM should be called get_header_fields_mock.side_effect = copy.deepcopy(rinfo) - session.getRPM.side_effect = rinfo + self.session.getRPM.side_effect = rinfo rip_rpm_sighdr_mock.side_effect = sighdr add_sig_calls, write_sig_calls = [], [] @@ -239,36 +235,29 @@ class TestImportSIG(utils.CliTestCase): write_sig_calls.append(call(rinfo[i]['id'], fake_sigkey)) # Run - handle_import_sig(options, session, arguments) + handle_import_sig(self.options, self.session, arguments) self.assert_console_message(stdout, expected) - session.addRPMSig.assert_has_calls(add_sig_calls) - session.writeSignedRPM.assert_has_calls(write_sig_calls) + self.session.addRPMSig.assert_has_calls(add_sig_calls) + self.session.writeSignedRPM.assert_has_calls(write_sig_calls) # restore os.path.exists patch os_path_exists_patch.stop() - @mock.patch('sys.stderr', new_callable=six.StringIO) @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_handle_import_sig_sigkey_from_header_signed( - self, - activate_session_mock, - stdout, stderr): + def test_handle_import_sig_sigkey_from_header_signed(self, stdout): """Test sigkey computation from header-only signed rpm in handle_import_sig function""" data_path = os.path.abspath("tests/test_hub/data/rpms") arguments = [os.path.join(data_path, 'header-signed.rpm')] sigkey = '15f712be' - options = mock.MagicMock() - session = mock.MagicMock() expected = '' for pkg in arguments: expected += "Importing signature [key %s] from %s..." % (sigkey, pkg) + "\n" expected += "Writing signed copy" + "\n" - session.getRPM.side_effect = [ + self.session.getRPM.side_effect = [ { 'sourcepackage': 0, 'name': 'testpkg', @@ -279,43 +268,32 @@ class TestImportSIG(utils.CliTestCase): 'id': 1, } ] - session.queryRPMSigs.side_effect = None - session.queryRPMSigs.return_value = [] + self.session.queryRPMSigs.side_effect = None + self.session.queryRPMSigs.return_value = [] # Run - handle_import_sig(options, session, arguments + ['--test']) + handle_import_sig(self.options, self.session, arguments + ['--test']) self.assert_console_message(stdout, expected) - session.addRPMSig.assert_not_called() - session.writeSignedRPM.assert_not_called() + self.session.addRPMSig.assert_not_called() + self.session.writeSignedRPM.assert_not_called() def test_handle_import_sig_argument_test(self): """Test handle_import_sig function without arguments""" - options = mock.MagicMock() - session = mock.MagicMock() - # Case 1. empty argument - expected = self.format_error_message( - "At least one package must be specified") - self.assert_system_exit( handle_import_sig, - options, - session, - [], - stderr=expected, - activate_session=None) + self.options, self.session, [], + stderr=self.format_error_message("At least one package must be specified"), + activate_session=None, + exit_code=2) # Case 2. File not exists test arguments = ['/bin/ls', '/tmp', '/path/to/file1', '/path/to/file2'] - expected = self.format_error_message( - "No such file: %s" % arguments[2]) self.assert_system_exit( handle_import_sig, - options, - session, - arguments, - stderr=expected, + self.options, self.session, arguments, + stderr=self.format_error_message("No such file: %s" % arguments[2]), activate_session=None) def test_handle_import_sig_help(self): diff --git a/tests/test_cli/test_latest_build.py b/tests/test_cli/test_latest_build.py index 5e76541f..73baa989 100644 --- a/tests/test_cli/test_latest_build.py +++ b/tests/test_cli/test_latest_build.py @@ -3,7 +3,6 @@ from __future__ import absolute_import import unittest import mock -import six from koji_cli.commands import anon_handle_latest_build from . import utils @@ -15,6 +14,8 @@ class TestLatestBuild(utils.CliTestCase): self.maxDiff = None self.options = mock.MagicMock() self.session = mock.MagicMock() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.ensure_connection = mock.patch('koji_cli.commands.ensure_connection').start() self.tag_name = 'test-tag' self.pkg_name = 'test-pkg' self.expected_part_help = """Usage: %s latest-build [options] [ ...] @@ -28,58 +29,46 @@ More information on tags and build targets can be found in the documentation. https://docs.pagure.org/koji/HOWTO/#package-organization (Specify the --help global option for a list of other help options) -""" \ - % (self.progname, self.progname) +""" % (self.progname, self.progname) def tearDown(self): mock.patch.stopall() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - @mock.patch('koji_cli.commands.activate_session') - def test_handle_latest_build_without_args(self, activate_session_mock, - ensure_connection, stderr): - with self.assertRaises(SystemExit) as ex: - anon_handle_latest_build(self.options, self.session, []) - self.assertExitCode(ex, 2) - actual = stderr.getvalue() - expected_stderr = \ - self.expected_part_help + "%s: error: A tag name must be specified\n" % self.progname - self.assertMultiLineEqual(actual, expected_stderr) - activate_session_mock.assert_not_called() - ensure_connection.assert_not_called() + def test_handle_latest_build_without_args(self): + expected = "%s: error: A tag name must be specified\n" % self.progname + self.assert_system_exit( + anon_handle_latest_build, + self.options, self.session, [], + stdout='', + stderr=self.expected_part_help + expected, + exit_code=2, + activate_session=None) + self.activate_session_mock.assert_not_called() + self.ensure_connection.assert_not_called() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - @mock.patch('koji_cli.commands.activate_session') - def test_handle_latest_build_more_args(self, activate_session_mock, ensure_connection, stderr): - with self.assertRaises(SystemExit) as ex: - anon_handle_latest_build(self.options, self.session, [self.tag_name]) - self.assertExitCode(ex, 2) - actual = stderr.getvalue() - expected_stderr = \ - self.expected_part_help + "%s: error: A tag name and package name must " \ - "be specified\n" % self.progname - self.assertMultiLineEqual(actual, expected_stderr) - activate_session_mock.assert_not_called() - ensure_connection.called_once() + def test_handle_latest_build_more_args(self): + expected = "%s: error: A tag name and package name must be specified\n" % self.progname + self.assert_system_exit( + anon_handle_latest_build, + self.options, self.session, [self.tag_name], + stdout='', + stderr=self.expected_part_help + expected, + exit_code=2, + activate_session=None) + self.activate_session_mock.assert_not_called() + self.ensure_connection.called_once() - @mock.patch('sys.stderr', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - @mock.patch('koji_cli.commands.activate_session') - def test_handle_latest_build_all_and_pkg(self, activate_session_mock, ensure_connection, - stderr): - with self.assertRaises(SystemExit) as ex: - anon_handle_latest_build(self.options, self.session, - ['--all', self.tag_name, self.pkg_name]) - self.assertExitCode(ex, 2) - actual = stderr.getvalue() - expected_stderr = \ - self.expected_part_help + "%s: error: A package name may not be combined " \ - "with --all\n" % self.progname - self.assertMultiLineEqual(actual, expected_stderr) - activate_session_mock.assert_not_called() - ensure_connection.called_once() + def test_handle_latest_build_all_and_pkg(self): + expected = "%s: error: A package name may not be combined with --all\n" % self.progname + self.assert_system_exit( + anon_handle_latest_build, + self.options, self.session, ['--all', self.tag_name, self.pkg_name], + stdout='', + stderr=self.expected_part_help + expected, + exit_code=2, + activate_session=None) + self.activate_session_mock.assert_not_called() + self.ensure_connection.called_once() def test_handle_latest_build_help(self): self.assert_help( diff --git a/tests/test_cli/test_list_api.py b/tests/test_cli/test_list_api.py index 593eba3d..59606cf8 100644 --- a/tests/test_cli/test_list_api.py +++ b/tests/test_cli/test_list_api.py @@ -8,29 +8,21 @@ from . import utils class TestListApi(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.error_format = """Usage: %s list-api [options] [method_name ...] (Specify the --help global option for a list of other help options) %s: error: {message} """ % (self.progname, self.progname) + self.session = mock.MagicMock() + self.options = mock.MagicMock() + self.ensure_connection = mock.patch('koji_cli.commands.ensure_connection').start() @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_anon_handle_list_api( - self, - ensure_connection_mock, - stdout): + def test_anon_handle_list_api_all_method(self, stdout): """Test anon_handle_list_api function""" - session = mock.MagicMock() - options = mock.MagicMock() - - # Case 1. list all methods - session._listapi.return_value = [ + self.session._listapi.return_value = [ { 'argdesc': '(tagInfo, **kwargs)', 'doc': 'Edit information for an existing tag.', @@ -56,27 +48,32 @@ class TestListApi(utils.CliTestCase): expected += "editTag2(tagInfo, **kwargs)\n" expected += " description: Edit information for an existing tag.\n" expected += "host.getID()\n" - anon_handle_list_api(options, session, []) + anon_handle_list_api(self.options, self.session, []) self.assert_console_message(stdout, expected) + self.ensure_connection.assert_called_once() - # Case 2. non-existent fake method - session.system.methodHelp.return_value = None - expected = self.format_error_message("Unknown method: non-existent-fake-method") + def test_anon_handle_list_api_fake_method(self): + """Test anon_handle_list_api function""" + self.session.system.methodHelp.return_value = None self.assert_system_exit( anon_handle_list_api, - options, - session, + self.options, + self.session, ['non-existent-fake-method'], - stderr=expected, + stderr=self.format_error_message("Unknown method: non-existent-fake-method"), activate_session=None) + self.ensure_connection.assert_called_once() - # Case 3. known method - session.system.methodHelp.return_value = "editTag2(tagInfo, **kwargs)\n" \ - " description: Edit information for an existing tag." - anon_handle_list_api(options, session, ['editTag2']) + @mock.patch('sys.stdout', new_callable=six.StringIO) + def test_anon_handle_list_api_specific_method(self, stdout): + """Test anon_handle_list_api function""" + self.session.system.methodHelp.return_value = \ + "editTag2(tagInfo, **kwargs)\n description: Edit information for an existing tag." + anon_handle_list_api(self.options, self.session, ['editTag2']) expected = "editTag2(tagInfo, **kwargs)\n" expected += " description: Edit information for an existing tag.\n" self.assert_console_message(stdout, expected) + self.ensure_connection.assert_called_once() def test_anon_handle_list_api_help(self): self.assert_help( diff --git a/tests/test_cli/test_list_buildroot.py b/tests/test_cli/test_list_buildroot.py index cd5bb555..75199269 100644 --- a/tests/test_cli/test_list_buildroot.py +++ b/tests/test_cli/test_list_buildroot.py @@ -16,32 +16,64 @@ class TestListBuilds(utils.CliTestCase): self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() - - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_buildroot_with_paths_option(self, stderr): - expected = """Usage: %s list-buildroot [options] + self.error_format = """Usage: %s list-buildroot [options] (Specify the --help global option for a list of other help options) -%s: error: --paths option is deprecated and will be removed in 1.30 +%s: error: {message} """ % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_list_buildroot(self.options, self.session, ['--paths', '1']) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + + def test_list_buildroot_with_paths_option(self): + expected = "--paths option is deprecated and will be removed in 1.30" + self.assert_system_exit( + anon_handle_list_buildroot, + self.options, self.session, ['--paths', '1'], + stderr=self.format_error_message(expected), + exit_code=2, + activate_session=None) self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.listRPMs.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_buildroot_without_args(self, stderr): - expected = """Usage: %s list-buildroot [options] -(Specify the --help global option for a list of other help options) - -%s: error: Incorrect number of arguments -""" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_list_buildroot(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + def test_list_buildroot_without_args(self): + self.assert_system_exit( + anon_handle_list_buildroot, + self.options, self.session, [], + stderr=self.format_error_message('Incorrect number of arguments'), + exit_code=2, + activate_session=None) self.ensure_connection_mock.assert_not_called() + self.session.listRPMs.assert_not_called() + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_buildroot_with_verbose(self, stdout): + expected_output = """testpackage-1.1-7.f33.noarch +testpkg-1.171-5.fc33.noarch [update] +tpkg-4.11-1.fc33.x86_64 [update] +""" + list_rpms = [{'arch': 'noarch', 'is_update': True, 'nvr': 'testpkg-1.171-5.fc33'}, + {'arch': 'noarch', 'is_update': False, 'nvr': 'testpackage-1.1-7.f33'}, + {'arch': 'x86_64', 'is_update': True, 'nvr': 'tpkg-4.11-1.fc33'}] + self.session.listRPMs.return_value = list_rpms + rv = anon_handle_list_buildroot(self.options, self.session, ['--verbose', '1']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.listRPMs.assert_called_once_with(componentBuildrootID=1) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_buildroot_with_built(self, stdout): + expected_output = """testpackage-1.1-7.f33.x86_64 +testpkg-1.171-5.fc33.noarch +tpkg-4.11-1.fc33.noarch +""" + list_rpms = [{'arch': 'noarch', 'nvr': 'testpkg-1.171-5.fc33'}, + {'arch': 'x86_64', 'nvr': 'testpackage-1.1-7.f33'}, + {'arch': 'noarch', 'nvr': 'tpkg-4.11-1.fc33'}] + self.session.listRPMs.return_value = list_rpms + rv = anon_handle_list_buildroot(self.options, self.session, ['--built', '2']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.listRPMs.assert_called_once_with(buildrootID=2) def test_list_buildroot_help(self): self.assert_help( diff --git a/tests/test_cli/test_list_builds.py b/tests/test_cli/test_list_builds.py index b5ade8c6..068efe97 100644 --- a/tests/test_cli/test_list_builds.py +++ b/tests/test_cli/test_list_builds.py @@ -15,279 +15,516 @@ class TestListBuilds(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() self.user_info = {'id': 1, 'name': 'kojiadmin', 'status': 0, 'usertype': 0, 'krb_principals': []} + self.owner = 'kojiadmin' + self.error_format = """Usage: %s list-builds [options] +(Specify the --help global option for a list of other help options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_without_option(self, stderr): - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: Filter must be provided for list\n" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) +%s: error: {message} +""" % (self.progname, self.progname) + self.list_build = [ + {'build_id': 1, 'epoch': 34, 'name': 'test-build', 'volume_id': 1, + 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', 'task_id': None, + 'release': '12', 'state': 1, 'version': '11', 'package_id': 1, + 'source': 'test-source-1'}, + {'build_id': 4, 'epoch': 34, 'name': 'test-build', 'volume_id': 0, + 'nvr': 'test-build-8-12', 'owner_name': 'kojiadmin', 'task_id': 40, + 'release': '12', 'state': 2, 'version': '8', 'package_id': 1, + 'source': 'test-source-2'}, + {'build_id': 2, 'epoch': 34, 'name': 'test-build', 'volume_id': 0, + 'nvr': 'test-build-11-9', 'owner_name': 'kojitest', 'task_id': 20, + 'release': '9', 'state': 1, 'version': '11', 'package_id': 1, + 'source': 'test-source-3'}, + {'build_id': 3, 'epoch': 34, 'name': 'test-build', 'volume_id': 0, + 'nvr': 'test-build-10-12', 'owner_name': 'kojitest', 'task_id': None, + 'release': '12', 'state': 4, 'version': '10', 'package_id': 1, + 'source': 'test-source-4'}, + {'build_id': 5, 'epoch': 34, 'name': 'test-zx-build', 'volume_id': 1, + 'nvr': 'build-test-1-12', 'owner_name': 'kojiadmin', 'task_id': 50, + 'release': '12', 'state': 4, 'version': '1', 'package_id': 2, + 'source': 'test-source-5'}] - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_non_exist_pkg(self, stderr): + def test_list_buildroot_with_args(self): + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['arg'], + stderr=self.format_error_message('This command takes no arguments'), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_not_called() + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() + + def test_list_builds_without_option(self): + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, [], + stderr=self.format_error_message('Filter must be provided for list'), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() + + def test_list_builds_non_exist_pkg(self): pkg = 'test-pkg' - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such package: %s\n" % (self.progname, self.progname, pkg) self.session.getPackageID.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, - ['--package', pkg]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--package', pkg], + stderr=self.format_error_message('No such package: %s' % pkg), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_called_once_with(pkg) + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_non_exist_owner(self, stderr): + def test_list_builds_non_exist_owner(self): owner = 'test-owner' - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such user: %s\n" % (self.progname, self.progname, owner) self.session.getUser.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, - ['--owner', owner]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--owner', owner], + stderr=self.format_error_message('No such user: %s' % owner), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_called_once_with(owner) + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_non_exist_volume(self, stderr): + def test_list_builds_non_exist_volume(self): volume = 'test-volume' - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such volume: %s\n" % (self.progname, self.progname, volume) self.session.listVolumes.return_value = [] - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, - ['--volume', volume]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--volume', volume], + stderr=self.format_error_message('No such volume: %s' % volume), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_called_once_with() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_invalid_state(self, stderr): + def test_list_builds_invalid_state(self): state = '6' - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: Invalid state: %s\n" % (self.progname, self.progname, state) - self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, - ['--state', state]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--state', state], + stderr=self.format_error_message('Invalid state: %s' % state), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_invalid_state_string(self, stderr): + def test_list_builds_invalid_state_string(self): state = 'test-state' - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: Invalid state: %s\n" % (self.progname, self.progname, state) - self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, - ['--state', state]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--state', state], + stderr=self.format_error_message('Invalid state: %s' % state), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_builds_non_exist_build(self, stderr): + def test_list_builds_non_exist_build(self): build = 222 - expected = "Usage: %s list-builds [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such build: '%s'\n" % (self.progname, self.progname, build) self.session.getBuild.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_builds(self.options, self.session, - ['--build', build]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--build', build], + stderr=self.format_error_message("No such build: '%s'" % build), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_called_once_with(build) + self.session.listBuilds.assert_not_called() @mock.patch('sys.stderr', new_callable=StringIO) @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_invalid_key(self, stdout, stderr): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-jx-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-ax-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-zx-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '11'}, ] test_key = 'test-key' expected_warn = "Invalid sort_key: %s." % test_key expected_output = """test-build-11-12 kojiadmin COMPLETE -test-jx-build-11-12 kojiadmin COMPLETE -test-ax-build-11-12 kojiadmin CANCELED -test-zx-build-11-12 kojiadmin CANCELED +test-build-8-12 kojiadmin DELETED +build-test-1-12 kojiadmin CANCELED """ self.session.getUser.return_value = self.user_info - self.session.listBuilds.return_value = list_build - rv = anon_handle_list_builds(self.options, self.session, ['--owner', 'kojiadmin', + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[1], + self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--owner', self.owner, '--sort-key', test_key]) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) self.assert_console_message(stderr, "%s\n" % expected_warn) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_called_once_with(self.owner) + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(userID=1) + @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_opt_owner_sorted_nvr(self, stdout): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-build-8-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '8'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-build-11-9', 'owner_name': 'kojiadmin', - 'release': '9', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-build-10-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '10'}, ] - expected_output = """test-build-10-12 kojiadmin CANCELED + expected_output = """build-test-1-12 kojiadmin CANCELED test-build-11-12 kojiadmin COMPLETE -test-build-11-9 kojiadmin CANCELED -test-build-8-12 kojiadmin COMPLETE +test-build-8-12 kojiadmin DELETED """ self.session.getUser.return_value = self.user_info - self.session.listBuilds.return_value = list_build - rv = anon_handle_list_builds(self.options, self.session, ['--owner', 'kojiadmin', + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[1], + self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--owner', self.owner, '--sort-key', 'nvr']) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_called_once_with(self.owner) + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(userID=1) + @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_opt_owner_sorted_state(self, stdout): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-build-8-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '8'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-build-11-9', 'owner_name': 'kojiadmin', - 'release': '9', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-build-10-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '10'}, ] expected_output = """test-build-11-12 kojiadmin COMPLETE -test-build-8-12 kojiadmin COMPLETE -test-build-11-9 kojiadmin CANCELED -test-build-10-12 kojiadmin CANCELED +test-build-8-12 kojiadmin DELETED +build-test-1-12 kojiadmin CANCELED """ self.session.getUser.return_value = self.user_info - self.session.listBuilds.return_value = list_build - rv = anon_handle_list_builds(self.options, self.session, ['--owner', 'kojiadmin', + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[1], + self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--owner', self.owner, '--sort-key', 'state']) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_called_once_with(self.owner) + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(userID=1) + @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_opt_owner_sorted_state_nvr(self, stdout): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-build-8-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '8'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-build-11-9', 'owner_name': 'kojiadmin', - 'release': '9', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-build-10-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '10'}, ] expected_output = """test-build-11-12 kojiadmin COMPLETE -test-build-8-12 kojiadmin COMPLETE -test-build-10-12 kojiadmin CANCELED -test-build-11-9 kojiadmin CANCELED +test-build-8-12 kojiadmin DELETED +build-test-1-12 kojiadmin CANCELED """ self.session.getUser.return_value = self.user_info - self.session.listBuilds.return_value = list_build - rv = anon_handle_list_builds(self.options, self.session, ['--owner', 'kojiadmin', + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[1], + self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--owner', self.owner, '--sort-key', 'state', '--sort-key', 'nvr']) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_called_once_with(self.owner) + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(userID=1) + @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_opt_prefix_sorted_owner(self, stdout): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-build-8-12', 'owner_name': 'kojitest', - 'release': '12', 'state': 1, 'version': '8'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-build-11-9', 'owner_name': 'kojitest', - 'release': '9', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-build-10-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '10'}, ] expected_output = """test-build-11-12 kojiadmin COMPLETE -test-build-10-12 kojiadmin CANCELED -test-build-8-12 kojitest COMPLETE -test-build-11-9 kojitest CANCELED +test-build-8-12 kojiadmin DELETED +build-test-1-12 kojiadmin CANCELED +test-build-11-9 kojitest COMPLETE +test-build-10-12 kojitest CANCELED """ - self.session.listBuilds.return_value = list_build + self.session.listBuilds.return_value = self.list_build rv = anon_handle_list_builds(self.options, self.session, ['--prefix', 'test-build', '--sort-key', 'owner_name']) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(prefix='test-build') + @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_opt_prefix_sorted_owner_nvr(self, stdout): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-build-8-12', 'owner_name': 'kojitest', - 'release': '12', 'state': 1, 'version': '8'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-build-11-9', 'owner_name': 'kojitest', - 'release': '9', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-build-10-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '10'}, ] - expected_output = """test-build-10-12 kojiadmin CANCELED + expected_output = """build-test-1-12 kojiadmin CANCELED test-build-11-12 kojiadmin COMPLETE -test-build-11-9 kojitest CANCELED -test-build-8-12 kojitest COMPLETE +test-build-8-12 kojiadmin DELETED +test-build-10-12 kojitest CANCELED +test-build-11-9 kojitest COMPLETE """ - self.session.listBuilds.return_value = list_build + self.session.listBuilds.return_value = self.list_build rv = anon_handle_list_builds(self.options, self.session, ['--prefix', 'test-build', '--sort-key', 'owner_name', '--sort-key', 'nvr']) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(prefix='test-build') + @mock.patch('sys.stdout', new_callable=StringIO) def test_list_builds_opt_owner_reverse(self, stdout): - list_build = [{'build_id': 1, 'epoch': 34, 'name': 'test-build', - 'nvr': 'test-build-11-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '11'}, - {'build_id': 4, 'epoch': 34, 'name': 'test-jx-build', - 'nvr': 'test-build-8-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 1, 'version': '8'}, - {'build_id': 2, 'epoch': 34, 'name': 'test-ax-build', - 'nvr': 'test-build-11-9', 'owner_name': 'kojiadmin', - 'release': '9', 'state': 4, 'version': '11'}, - {'build_id': 3, 'epoch': 34, 'name': 'test-zx-build', - 'nvr': 'test-build-10-12', 'owner_name': 'kojiadmin', - 'release': '12', 'state': 4, 'version': '10'}, ] - expected_output = """test-build-8-12 kojiadmin COMPLETE -test-build-11-9 kojiadmin CANCELED + expected_output = """test-build-8-12 kojiadmin DELETED test-build-11-12 kojiadmin COMPLETE -test-build-10-12 kojiadmin CANCELED +build-test-1-12 kojiadmin CANCELED """ self.session.getUser.return_value = self.user_info - self.session.listBuilds.return_value = list_build - rv = anon_handle_list_builds(self.options, self.session, ['--owner', 'kojiadmin', + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[1], + self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--owner', self.owner, '--reverse']) self.assertEqual(rv, None) self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_called_once_with(self.owner) + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(userID=1) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_opt_cg(self, stdout): + expected_output = """test-build-11-9 kojitest COMPLETE +test-build-8-12 kojiadmin DELETED +""" + self.session.listBuilds.return_value = [self.list_build[1], self.list_build[2]] + rv = anon_handle_list_builds(self.options, self.session, ['--cg', 'test-cg']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(cgID='test-cg') + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_pkg_not_int(self, stdout): + pkg = 'build-test' + expected_output = """build-test-1-12 kojiadmin CANCELED +""" + self.session.getPackageID.return_value = 2 + self.session.listBuilds.return_value = [self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--package', pkg]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_called_once_with(pkg) + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(packageID=2) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_pkg_int(self, stdout): + pkg = 2 + expected_output = """build-test-1-12 kojiadmin CANCELED +""" + self.session.listBuilds.return_value = [self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--package', str(pkg)]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(packageID=2) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_volume_not_int(self, stdout): + volume = 'test-volume' + expected_output = """build-test-1-12 kojiadmin CANCELED +test-build-11-12 kojiadmin COMPLETE +""" + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[4]] + self.session.listVolumes.return_value = [{'id': 0, 'name': 'DEFAULT'}, + {'id': 1, 'name': 'test-volume'}] + rv = anon_handle_list_builds(self.options, self.session, ['--volume', volume]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_called_once_with() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(volumeID=1) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_volume_int(self, stdout): + volume = 1 + expected_output = """build-test-1-12 kojiadmin CANCELED +test-build-11-12 kojiadmin COMPLETE +""" + self.session.listBuilds.return_value = [self.list_build[0], self.list_build[4]] + rv = anon_handle_list_builds(self.options, self.session, ['--volume', volume]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(volumeID=1) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_state(self, stdout): + expected_output = """test-build-8-12 kojiadmin DELETED +""" + self.session.listBuilds.return_value = [self.list_build[1]] + rv = anon_handle_list_builds(self.options, self.session, ['--state', '2']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(state=2) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_task_int(self, stdout): + expected_output = """test-build-11-9 kojitest COMPLETE +""" + self.session.listBuilds.return_value = [self.list_build[2]] + rv = anon_handle_list_builds(self.options, self.session, ['--task', '20']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(taskID=20) + + def test_list_builds_task_not_int(self): + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--task', 'task-id'], + stderr=self.format_error_message("Task id must be an integer"), + exit_code=2, + activate_session=None) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_not_called() + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_build_string(self, stdout): + expected_output = """test-build-11-9 kojitest COMPLETE +""" + self.session.getBuild.return_value = self.list_build[2] + rv = anon_handle_list_builds(self.options, self.session, ['--buildid', 'test-build-10-12']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_called_once_with('test-build-10-12') + self.session.listBuilds.assert_not_called() + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_builds_build_source_without_quiet(self, stdout): + self.options.quiet = False + expected_output = """Build Built by State +------------------------------------------------------- ---------------- ---------------- +test-build-10-12 kojitest CANCELED +""" + self.session.listBuilds.return_value = [self.list_build[3]] + rv = anon_handle_list_builds(self.options, self.session, ['--source', 'test-source-4']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected_output) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(source='test-source-4') + + def test_list_builds_pattern_option_error(self): + self.session.listBuilds.side_effect = koji.ParameterError("no option 'pattern'") + expected = "The hub doesn't support the 'pattern' argument, please try filtering " \ + "the result on your local instead." + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--pattern', 'pattern'], + stderr=self.format_error_message(expected), + exit_code=2, + activate_session=None) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(pattern='pattern') + + def test_list_builds_cgid_option_error(self): + self.session.listBuilds.side_effect = koji.ParameterError("no option 'cgID'") + expected = "The hub doesn't support the 'cg' argument, please try filtering " \ + "the result on your local instead." + self.assert_system_exit( + anon_handle_list_builds, + self.options, self.session, ['--cg', 'test-cg'], + stderr=self.format_error_message(expected), + exit_code=2, + activate_session=None) + + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.session.getPackageID.assert_not_called() + self.session.getUser.assert_not_called() + self.session.listVolumes.assert_not_called() + self.session.getBuild.assert_not_called() + self.session.listBuilds.assert_called_once_with(cgID='test-cg') diff --git a/tests/test_cli/test_list_channels.py b/tests/test_cli/test_list_channels.py index e84fc5a4..0dee9153 100644 --- a/tests/test_cli/test_list_channels.py +++ b/tests/test_cli/test_list_channels.py @@ -18,6 +18,7 @@ class TestListChannels(utils.CliTestCase): self.options.quiet = True self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() self.list_channels = [ {'id': 1, 'name': 'default', 'enabled': True, 'comment': 'test-comment-1', 'description': 'test-description-1'}, @@ -45,8 +46,7 @@ class TestListChannels(utils.CliTestCase): ] @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_not_quiet(self, ensure_connection_mock, stdout): + def test_list_channels_not_quiet(self, stdout): self.session.listChannels.return_value = self.list_channels self.session.multiCall.return_value = self.list_hosts_mc args = [] @@ -55,51 +55,45 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = "Channel Enabled Ready Disbld Load Cap Perc \n" \ "default 3 1 0 1 6 22%\n" \ "test [disabled] 2 2 1 1 6 28%\n" self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_comment(self, ensure_connection_mock, stdout): + def test_list_channels_with_comment(self, stdout): self.session.listChannels.return_value = self.list_channels self.session.multiCall.return_value = self.list_hosts_mc args = ['--comment'] anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = 'default 3 1 0 1 6 22% ' \ 'test-comment-1 \n' \ 'test [disabled] 2 2 1 1 6 28% ' \ 'test-comment-2 \n' self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_description(self, ensure_connection_mock, stdout): + def test_list_channels_with_description(self, stdout): self.session.listChannels.return_value = self.list_channels self.session.multiCall.return_value = self.list_hosts_mc args = ['--description'] anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = 'default 3 1 0 1 6 22% ' \ 'test-description-1 \n' \ 'test [disabled] 2 2 1 1 6 28% ' \ 'test-description-2 \n' self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_comment_desc_not_quiet(self, ensure_connection_mock, stdout): + def test_list_channels_with_comment_desc_not_quiet(self, stdout): self.session.listChannels.return_value = self.list_channels self.session.multiCall.return_value = self.list_hosts_mc args = ['--description', '--comment'] @@ -108,7 +102,6 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = "Channel Enabled Ready Disbld Load Cap Perc " \ "Description " \ "Comment \n" \ @@ -119,11 +112,10 @@ class TestListChannels(utils.CliTestCase): "test-description-2 " \ "test-comment-2 \n" self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_enabled_hub_without_enabled(self, ensure_connection_mock, stdout): + def test_list_channels_with_enabled_hub_without_enabled(self, stdout): self.session.listChannels.side_effect = [koji.ParameterError, self.list_channels_without_enabled] self.session.multiCall.return_value = self.list_hosts_mc @@ -131,15 +123,13 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = 'default 3 1 0 1 6 22%\n' \ 'test 2 2 1 1 6 28%\n' self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_enabled(self, ensure_connection_mock, stdout): + def test_list_channels_with_enabled(self, stdout): list_channel_enabled = [ {'id': 1, 'name': 'default', 'enabled': True, 'comment': 'test-comment-1', 'description': 'test-description-1'}, @@ -157,14 +147,12 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = 'default 3 1 0 1 6 22%\n' self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_disabled(self, ensure_connection_mock, stdout): + def test_list_channels_with_disabled(self, stdout): list_channel_disabled = [ {'id': 2, 'name': 'test', 'enabled': False, 'comment': 'test-comment-2', 'description': 'test-description-2'}, @@ -182,14 +170,12 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = 'test [disabled] 2 2 1 1 6 28%\n' self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_with_empty_channels(self, ensure_connection_mock, stdout): + def test_list_channels_with_empty_channels(self, stdout): list_channels = [] list_hosts_mc = [[[]]] self.session.listChannels.return_value = list_channels @@ -198,14 +184,12 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = '' self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_simple_without_quiet(self, ensure_connection_mock, stdout): + def test_list_channels_simple_without_quiet(self, stdout): self.session.listChannels.return_value = self.list_channels self.session.multiCall.return_value = self.list_hosts_mc self.options.quiet = False @@ -214,17 +198,15 @@ class TestListChannels(utils.CliTestCase): anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = """Channel default test [disabled] """ self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_channels_simple_with_quiet(self, ensure_connection_mock, stdout): + def test_list_channels_simple_with_quiet(self, stdout): self.session.listChannels.return_value = self.list_channels self.session.multiCall.return_value = self.list_hosts_mc args = ['--simple', '--quiet'] @@ -232,12 +214,11 @@ test [disabled] anon_handle_list_channels(self.options, self.session, args) actual = stdout.getvalue() - print(actual) expected = """default test [disabled] """ self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) def test_list_channels_help(self): self.assert_help( diff --git a/tests/test_cli/test_list_commands.py b/tests/test_cli/test_list_commands.py index e2659496..63c134bf 100644 --- a/tests/test_cli/test_list_commands.py +++ b/tests/test_cli/test_list_commands.py @@ -17,13 +17,11 @@ class TestListCommands(unittest.TestCase): self.original_parser = cli.OptionParser cli.OptionParser = mock.MagicMock() self.parser = cli.OptionParser.return_value + self.maxDiff = None def tearDown(self): cli.OptionParser = self.original_parser - # Show long diffs in error output... - maxDiff = None - @mock.patch('sys.stdout', new_callable=six.StringIO) def test_list_commands(self, stdout): cli.list_commands() diff --git a/tests/test_cli/test_list_groups.py b/tests/test_cli/test_list_groups.py index a6e0f646..cb7501a4 100644 --- a/tests/test_cli/test_list_groups.py +++ b/tests/test_cli/test_list_groups.py @@ -9,15 +9,12 @@ from . import utils class TestListGroups(utils.CliTestCase): - - # Show long diffs in error output... - maxDiff = None - def setUp(self): + self.maxDiff = None self.session = mock.MagicMock() self.options = mock.MagicMock() - self.activate_session = mock.patch('koji_cli.commands.activate_session').start() + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() self.event_from_opts = mock.patch('koji.util.eventFromOpts').start() self.error_format = """Usage: %s list-groups [options] [] @@ -29,26 +26,15 @@ class TestListGroups(utils.CliTestCase): def tearDown(self): mock.patch.stopall() - @mock.patch('sys.stdout', new_callable=six.StringIO) - @mock.patch('koji_cli.commands.activate_session') - @mock.patch('koji_cli.commands.ensure_connection') - def test_anon_handle_list_groups_argument_error( - self, - ensure_connection_mock, - activate_session_mock, - stdout): + def test_anon_handle_list_groups_argument_error(self): """Test anon_handle_list_groups function""" - expected = self.format_error_message( - "Incorrect number of arguments") for arg in [[], ['tag', 'grp', 'etc']]: self.assert_system_exit( anon_handle_list_groups, - self.options, - self.session, - arg, - stderr=expected, + self.options, self.session, arg, + stderr=self.format_error_message("Incorrect number of arguments"), activate_session=None) - activate_session_mock.assert_not_called() + self.ensure_connection_mock.assert_not_called() def test_anon_handle_list_groups_list_all(self): self.event_from_opts.return_value = {} @@ -164,15 +150,16 @@ class TestListGroups(utils.CliTestCase): for group in groups: if query_group != '' and group['name'] != query_group: continue - expected += "%s [%s]" % (group['name'], tags.get(group['tag_id'], group['tag_id'])) + "\n" + expected += "%s [%s]" % (group['name'], tags.get(group['tag_id'], + group['tag_id'])) + "\n" for grp in group["grouplist"]: grp['tag_name'] = tags.get(grp['tag_id'], grp['tag_id']) expected += " @%(name)s [%(tag_name)s]" % grp + "\n" for pkg in group["packagelist"]: pkg['tag_name'] = tags.get(pkg['tag_id'], pkg['tag_id']) - expected += " %(package)s: %(basearchonly)s, %(type)s [%(tag_name)s]" % pkg + "\n" + expected += " %(package)s: %(basearchonly)s, %(type)s [%(tag_name)s]"\ + % pkg + "\n" - #self.session.listTags.return_value = _list_tags def get_tag(tag_id, strict=False): self.assertFalse(strict) for tag in _list_tags: diff --git a/tests/test_cli/test_list_hosts.py b/tests/test_cli/test_list_hosts.py index 9a147cfa..93f691c2 100644 --- a/tests/test_cli/test_list_hosts.py +++ b/tests/test_cli/test_list_hosts.py @@ -12,6 +12,7 @@ from . import utils class TestListHosts(utils.CliTestCase): def setUp(self): + self.maxDiff = None # force locale to compare 'expect' value locale.setlocale(locale.LC_ALL, ('en_US', 'UTF-8')) self.options = mock.MagicMock() @@ -21,6 +22,22 @@ class TestListHosts(utils.CliTestCase): self.original_timezone = os.environ.get('TZ') os.environ['TZ'] = 'UTC' time.tzset() + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() + self.error_format = """Usage: %s list-hosts [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) + self.list_hosts = [{'arches': 'x86_64', + 'capacity': 2.0, + 'comment': 'test-comment', + 'description': 'test-description', + 'enabled': False, + 'id': 1, + 'name': 'kojibuilder', + 'ready': True, + 'task_load': 0.0, + 'user_id': 2}] def tearDown(self): locale.resetlocale() @@ -31,47 +48,175 @@ class TestListHosts(utils.CliTestCase): time.tzset() @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_hosts_valid(self, ensure_connection, stdout): + def test_list_hosts_valid_without_quiet(self, stdout): + self.options.quiet = False host_update = 1615875554.862938 - expected = "kojibuilder Y Y 0.0/2.0 x86_64 " \ - "Tue, 16 Mar 2021 06:19:14 UTC \n" - list_hosts = [{'arches': 'x86_64', - 'capacity': 2.0, - 'comment': None, - 'description': None, - 'enabled': True, - 'id': 1, - 'name': 'kojibuilder', - 'ready': True, - 'task_load': 0.0, - 'user_id': 2}] + expected = """Hostname Enb Rdy Load/Cap Arches Last Update +kojibuilder N Y 0.0/2.0 x86_64 Tue, 16 Mar 2021 06:19:14 UTC +""" + self.session.getLastHostUpdate.return_value = host_update self.session.multiCall.return_value = [[host_update]] - self.session.listHosts.return_value = list_hosts + self.session.listHosts.return_value = self.list_hosts rv = anon_handle_list_hosts(self.options, self.session, []) self.assertEqual(rv, None) self.assert_console_message(stdout, expected) self.session.listHosts.assert_called_once_with() - self.session.getLastHostUpdate.assert_called_once_with(list_hosts[0]['id'], ts=True) + self.session.getLastHostUpdate.assert_called_once_with(self.list_hosts[0]['id'], ts=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_hosts_non_exist_channel(self, stderr): + def test_list_hosts_non_exist_channel(self): channel = 'test-channel' - expected = "Usage: %s list-hosts [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such channel: %s\n" % (self.progname, self.progname, channel) self.session.getChannel.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_hosts(self.options, self.session, ['--channel', channel]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_hosts, + self.options, self.session, ['--channel', channel], + stderr=self.format_error_message('No such channel: %s' % channel), + exit_code=2, + activate_session=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) @mock.patch('sys.stderr', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_hosts_empty(self, ensure_connection, stderr): + def test_list_hosts_empty(self, stderr): expected = "No hosts found.\n" self.session.listHosts.return_value = [] anon_handle_list_hosts(self.options, self.session, []) self.assert_console_message(stderr, expected) self.session.listHosts.assert_called_once_with() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_with_arch(self, stdout): + host_update = 1615875554.862938 + expected = "kojibuilder N Y 0.0/2.0 x86_64 " \ + "Tue, 16 Mar 2021 06:19:14 UTC \n" + + self.session.getLastHostUpdate.return_value = host_update + self.session.multiCall.return_value = [[host_update]] + self.session.listHosts.return_value = self.list_hosts + rv = anon_handle_list_hosts(self.options, self.session, ['--arch', 'x86_64']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(arches=['x86_64']) + self.session.getLastHostUpdate.assert_called_once_with(self.list_hosts[0]['id'], ts=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_with_arch_not_used(self, stdout): + expected = "" + + self.session.listHosts.return_value = [] + rv = anon_handle_list_hosts(self.options, self.session, ['--arch', 'ppc']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(arches=['ppc']) + self.session.getLastHostUpdate.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_with_ready(self, stdout): + host_update = None + expected = "kojibuilder N Y 0.0/2.0 x86_64 " \ + "- \n" + + self.session.getLastHostUpdate.return_value = host_update + self.session.multiCall.return_value = [[host_update]] + self.session.listHosts.return_value = self.list_hosts + rv = anon_handle_list_hosts(self.options, self.session, ['--ready']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(ready=True) + self.session.getLastHostUpdate.assert_called_once_with(self.list_hosts[0]['id'], ts=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_with_not_ready(self, stdout): + expected = "" + self.session.listHosts.return_value = [] + rv = anon_handle_list_hosts(self.options, self.session, ['--not-ready']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(ready=False) + self.session.getLastHostUpdate.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_with_enabled(self, stdout): + expected = "" + + self.session.listHosts.return_value = [] + rv = anon_handle_list_hosts(self.options, self.session, ['--enabled']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(enabled=True) + self.session.getLastHostUpdate.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_with_not_enabled(self, stdout): + host_update = 1615875554.862938 + expected = "kojibuilder N Y 0.0/2.0 x86_64 " \ + "Tue, 16 Mar 2021 06:19:14 UTC \n" + + self.session.getLastHostUpdate.return_value = host_update + self.session.multiCall.return_value = [[host_update]] + self.session.listHosts.return_value = self.list_hosts + rv = anon_handle_list_hosts(self.options, self.session, ['--not-enabled']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(enabled=False) + self.session.getLastHostUpdate.assert_called_once_with(self.list_hosts[0]['id'], ts=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_param_error_get_last_host_update(self, stdout): + host_update = 1615875554.862938 + expected = "kojibuilder N Y 0.0/2.0 x86_64 " \ + "Tue, 16 Mar 2021 06:19:14 UTC \n" + + self.session.getLastHostUpdate.side_effect = [koji.ParameterError, host_update] + self.session.multiCall.return_value = [[host_update]] + self.session.listHosts.return_value = self.list_hosts + rv = anon_handle_list_hosts(self.options, self.session, ['--ready']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with(ready=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_valid_without_quiet_description_and_comment(self, stdout): + self.options.quiet = False + host_update = 1615875554.862938 + expected = "Hostname Enb Rdy Load/Cap Arches Last Update" \ + " Description " \ + "Comment \n" \ + "kojibuilder N Y 0.0/2.0 x86_64 Tue, 16 Mar 2021 06:19:14 UTC" \ + " test-description test-comment" \ + " \n" + + self.session.getLastHostUpdate.return_value = host_update + self.session.multiCall.return_value = [[host_update]] + self.session.listHosts.return_value = self.list_hosts + rv = anon_handle_list_hosts(self.options, self.session, ['--description', '--comment']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with() + self.session.getLastHostUpdate.assert_called_once_with(self.list_hosts[0]['id'], ts=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_hosts_valid_description_and_comment(self, stdout): + host_update = 1615875554.862938 + expected = "kojibuilder N Y 0.0/2.0 x86_64 Tue, 16 Mar 2021 06:19:14 UTC" \ + " test-description test-comment" \ + " \n" + + self.session.getLastHostUpdate.return_value = host_update + self.session.multiCall.return_value = [[host_update]] + self.session.listHosts.return_value = self.list_hosts + rv = anon_handle_list_hosts(self.options, self.session, ['--description', '--comment']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.listHosts.assert_called_once_with() + self.session.getLastHostUpdate.assert_called_once_with(self.list_hosts[0]['id'], ts=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) diff --git a/tests/test_cli/test_list_notifications.py b/tests/test_cli/test_list_notifications.py index 59d53c3d..b69f68f3 100644 --- a/tests/test_cli/test_list_notifications.py +++ b/tests/test_cli/test_list_notifications.py @@ -10,14 +10,21 @@ from . import utils class TestListNotifications(utils.CliTestCase): def setUp(self): + self.maxDiff = None self.options = mock.MagicMock() self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s list-notifications [options] +(Specify the --help global option for a list of other help options) + +%s: error: {message} +""" % (self.progname, self.progname) @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.activate_session') - def test_list_notifications(self, activate_session_mock, stdout): + def test_list_notifications(self, stdout): self.session.getBuildNotifications.return_value = [ {'id': 1, 'tag_id': 1, 'package_id': 11, 'email': 'email@test.com', 'success_only': True}, @@ -44,17 +51,16 @@ Notifications No notification blocks ''' - self.maxDiff = None self.assertMultiLineEqual(actual, expected) - activate_session_mock.assert_called_once() self.session.getTag.assert_has_calls([mock.call(1), mock.call(1)]) self.session.getPackage.assert_has_calls([mock.call(11), mock.call(11)]) self.session.getUser.assert_not_called() self.session.getBuildNotifications.assert_called_once_with(None) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.ensure_connection_mock.asset_not_called() @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_notifications_user(self, ensure_connection_mock, stdout): + def test_list_notifications_user(self, stdout): self.session.getBuildNotifications.return_value = [ {'id': 1, 'tag_id': 1, 'package_id': 11, 'email': 'email@test.com', 'success_only': True}, @@ -96,64 +102,59 @@ Notification blocks 12 * * ''' - self.maxDiff = None self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) self.session.getTag.assert_has_calls([mock.call(1), mock.call(1)]) self.session.getPackage.assert_has_calls([mock.call(11), mock.call(11)]) self.session.getUser.assert_called_once_with('random_name') self.session.getBuildNotifications.assert_called_once_with(321) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.activate_session_mock.asset_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_list_notifications_without_option(self, stderr): - expected = """Usage: %s list-notifications [options] -(Specify the --help global option for a list of other help options) - -%s: error: Use --user or --mine. -""" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_list_notifications(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + def test_handle_list_notifications_without_option(self): + self.assert_system_exit( + anon_handle_list_notifications, + self.options, self.session, [], + stderr=self.format_error_message('Use --user or --mine.'), + exit_code=2, + activate_session=None) self.session.getBuildNotifications.assert_not_called() self.session.getTag.assert_not_called() self.session.getPackage.assert_not_called() self.session.getUser.assert_not_called() + self.ensure_connection_mock.asset_not_called() + self.activate_session_mock.asset_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_handle_list_notifications_with_args(self, stderr): - expected = """Usage: %s list-notifications [options] -(Specify the --help global option for a list of other help options) - -%s: error: This command takes no arguments -""" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - anon_handle_list_notifications(self.options, self.session, ['test-argument']) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + def test_handle_list_notifications_with_args(self): + self.assert_system_exit( + anon_handle_list_notifications, + self.options, self.session, ['test-argument'], + stderr=self.format_error_message('This command takes no arguments'), + exit_code=2, + activate_session=None) self.session.getBuildNotifications.assert_not_called() self.session.getTag.assert_not_called() self.session.getPackage.assert_not_called() self.session.getUser.assert_not_called() + self.ensure_connection_mock.asset_not_called() + self.activate_session_mock.asset_not_called() - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_notifications_user_non_exist_user(self, stderr): + def test_list_notifications_user_non_exist_user(self): username = 'random_name' self.session.getUser.return_value = None - - with self.assertRaises(SystemExit): - anon_handle_list_notifications(self.options, self.session, - ['--user', username]) - actual = stderr.getvalue() - expected = 'No such user: %s\n' % username - self.assertMultiLineEqual(actual, expected) + self.assert_system_exit( + anon_handle_list_notifications, + self.options, self.session, ['--user', username], + stderr='No such user: %s\n' % username, + exit_code=1, + activate_session=None) self.session.getBuildNotifications.assert_not_called() self.session.getTag.assert_not_called() self.session.getPackage.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.activate_session_mock.asset_not_called() @mock.patch('sys.stdout', new_callable=StringIO) - @mock.patch('koji_cli.commands.ensure_connection') - def test_list_notifications_without_notification(self, ensure_connection_mock, stdout): + def test_list_notifications_without_notification(self, stdout): username = 'random_name' self.session.getUser.return_value = {'id': 321} self.session.getBuildNotifications.return_value = [] @@ -171,8 +172,9 @@ Notification blocks """ actual = stdout.getvalue() self.assertMultiLineEqual(actual, expected) - ensure_connection_mock.assert_called_once_with(self.session, self.options) self.session.getTag.assert_called_once_with(22) self.session.getPackage.assert_not_called() self.session.getUser.assert_called_once_with('random_name') self.session.getBuildNotifications.assert_called_once_with(321) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + self.activate_session_mock.asset_not_called() diff --git a/tests/test_cli/test_list_pkgs.py b/tests/test_cli/test_list_pkgs.py index f1973614..adfa7ba0 100644 --- a/tests/test_cli/test_list_pkgs.py +++ b/tests/test_cli/test_list_pkgs.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import mock +import copy from six.moves import StringIO import koji @@ -14,27 +15,263 @@ class TestListPkgs(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.ensure_connection_mock = mock.patch('koji_cli.commands.ensure_connection').start() + self.error_format = """Usage: %s list-pkgs [options] +(Specify the --help global option for a list of other help options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_pkgs_non_exist_tag(self, stderr): - tag = 'test-tag' - expected = "Usage: %s list-pkgs [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such tag: %s\n" % (self.progname, self.progname, tag) +%s: error: {message} +""" % (self.progname, self.progname) + self.owner = 'test-owner' + self.tag = 'test-tag-2' + self.pkg = 'test-pkg-2' + self.userinfo = {'id': 1, 'krb_principals': [], 'name': self.owner, + 'status': 0, 'usertype': 0} + self.list_packages = [{'blocked': False, + 'extra_arches': '', + 'owner_id': 1, + 'owner_name': 'test-owner', + 'package_id': 1, + 'package_name': 'test-pkg-1', + 'tag_id': 1, + 'tag_name': 'test-tag-1'}, + {'blocked': True, + 'extra_arches': 'x86_64', + 'owner_id': 1, + 'owner_name': 'usertest', + 'package_id': 2, + 'package_name': 'test-pkg-2', + 'tag_id': 2, + 'tag_name': 'test-tag-2'}, ] + self.taginfo = {'arches': 'x86_64', + 'extra': {}, + 'id': 2, + 'locked': False, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'test-tag-2', + 'perm': None, + 'perm_id': None} + + def test_list_pkgs_non_exist_tag(self): self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_pkgs(self.options, self.session, ['--tag', tag]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_pkgs, + self.options, self.session, ['--tag', self.tag], + stderr=self.format_error_message("No such tag: %s" % self.tag), + activate_session=None, + exit_code=2 + ) + self.session.getUser.assert_not_called() + self.session.listPackages.assert_not_called() + self.session.getTag.assert_called_once_with(self.tag) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_list_pkgs_non_exist_owner(self, stderr): - owner = 'test-owner' - expected = "Usage: %s list-pkgs [options]\n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such user: %s\n" % (self.progname, self.progname, owner) + def test_list_pkgs_non_exist_owner(self): self.session.getUser.return_value = None - with self.assertRaises(SystemExit) as ex: - anon_handle_list_pkgs(self.options, self.session, ['--owner', owner]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + self.assert_system_exit( + anon_handle_list_pkgs, + self.options, self.session, ['--owner', self.owner], + stderr=self.format_error_message("No such user: %s" % self.owner), + activate_session=None, + exit_code=2 + ) + self.session.getUser.assert_called_once_with(self.owner) + self.session.listPackages.assert_not_called() + self.session.getTag.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + def test_list_pkgs_argument_error(self): + self.assert_system_exit( + anon_handle_list_pkgs, + self.options, self.session, ['arg'], + stderr=self.format_error_message("This command takes no arguments"), + activate_session=None) + self.ensure_connection_mock.assert_not_called() + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_with_owner_without_quiet(self, stdout): + self.options.quiet = False + expected = """Package Tag Extra Arches Owner +----------------------- ----------------------- ---------------- --------------- +test-pkg-1 test-tag-1 test-owner +""" + self.session.getUser.return_value = self.userinfo + self.session.listPackages.return_value = [self.list_packages[0]] + rv = anon_handle_list_pkgs(self.options, self.session, ['--owner', self.owner]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_called_once_with(self.owner) + self.session.getTag.assert_not_called() + self.session.listPackages.assert_called_once_with(inherited=True, userID=1, + with_dups=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_with_tag_and_pkg_without_quiet_with_blocked(self, stdout): + self.options.quiet = False + expected = """Package Tag Extra Arches Owner +----------------------- ----------------------- ---------------- --------------- +test-pkg-2 test-tag-2 x86_64 usertest [BLOCKED] +""" + self.session.getTag.return_value = self.taginfo + self.session.listPackages.return_value = [self.list_packages[1]] + rv = anon_handle_list_pkgs(self.options, self.session, ['--tag', self.tag, + '--package', self.pkg, + '--show-blocked']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_called_once_with(self.tag) + self.session.listPackages.assert_called_once_with(inherited=True, tagID=2, pkgID=self.pkg, + with_blocked=True, with_dups=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_with_tag_and_pkg_without_quiet_with_blocked_extra_arch_none(self, stdout): + self.options.quiet = False + list_packages = copy.deepcopy(self.list_packages) + list_packages[1]['extra_arches'] = None + expected = """Package Tag Extra Arches Owner +----------------------- ----------------------- ---------------- --------------- +test-pkg-2 test-tag-2 usertest [BLOCKED] +""" + self.session.getTag.return_value = self.taginfo + self.session.listPackages.return_value = [list_packages[1]] + rv = anon_handle_list_pkgs(self.options, self.session, ['--tag', self.tag, + '--package', self.pkg, + '--show-blocked']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_called_once_with(self.tag) + self.session.listPackages.assert_called_once_with(inherited=True, tagID=2, pkgID=self.pkg, + with_blocked=True, with_dups=None) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_with_pkg_without_quiet_with_blocked_tag_not_in_pkg(self, stdout): + self.options.quiet = False + list_packages = copy.deepcopy(self.list_packages) + del list_packages[1]['tag_id'] + del list_packages[1]['tag_name'] + expected = """Package Tag Extra Arches Owner +----------------------- ----------------------- ---------------- --------------- +test-pkg-2 +""" + self.session.listPackages.return_value = [list_packages[1]] + rv = anon_handle_list_pkgs(self.options, self.session, ['--package', self.pkg, + '--show-blocked']) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_not_called() + self.session.listPackages.assert_called_once_with(inherited=True, pkgID=self.pkg, + with_blocked=True, with_dups=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_without_options(self, stdout): + expected = """test-pkg-1 +test-pkg-2 +""" + self.session.listPackages.return_value = self.list_packages + rv = anon_handle_list_pkgs(self.options, self.session, []) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_not_called() + self.session.listPackages.assert_called_once_with(inherited=True, with_dups=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_not_quiet(self, stdout): + self.options.quiet = False + expected = """Package +----------------------- +test-pkg-1 +test-pkg-2 +""" + self.session.listPackages.return_value = self.list_packages + rv = anon_handle_list_pkgs(self.options, self.session, []) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_not_called() + self.session.listPackages.assert_called_once_with(inherited=True, with_dups=True) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + def test_list_pkgs_no_pkg(self): + self.session.listPackages.return_value = [] + self.session.getTag.return_value = self.taginfo + self.session.getUser.return_value = self.userinfo + self.assert_system_exit( + anon_handle_list_pkgs, + self.options, self.session, ['--tag', self.tag, '--owner', self.owner], + stderr="(no matching packages)\n", + activate_session=None, + exit_code=1 + ) + self.session.getUser.assert_called_once_with(self.owner) + self.session.getTag.assert_called_once_with(self.tag) + self.session.listPackages.assert_called_once_with(inherited=True, with_dups=None, + tagID=2, userID=1) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_without_blocked_empty_result(self, stdout): + expected = "" + self.session.getTag.return_value = self.taginfo + self.session.listPackages.return_value = [self.list_packages[1]] + rv = anon_handle_list_pkgs(self.options, self.session, ['--tag', self.tag]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_called_once_with(self.tag) + self.session.listPackages.assert_called_once_with(inherited=True, with_dups=None, tagID=2) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('sys.stdout', new_callable=StringIO) + def test_list_pkgs_param_error(self, stdout): + expected = """test-pkg-1 test-tag-1 test-owner +test-pkg-2 test-tag-2 x86_64 usertest [BLOCKED] +""" + self.session.getTag.return_value = self.taginfo + self.session.listPackages.side_effect = [koji.ParameterError, self.list_packages] + rv = anon_handle_list_pkgs(self.options, self.session, ['--show-blocked', + '--tag', self.tag]) + self.assertEqual(rv, None) + self.assert_console_message(stdout, expected) + self.session.getUser.assert_not_called() + self.session.getTag.assert_called_once_with(self.tag) + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + def test_list_pkgs_blocked_without_option(self): + expected = '--show-blocked makes sense only with --tag, --owner or --package' + self.assert_system_exit( + anon_handle_list_pkgs, + self.options, self.session, ['--show-blocked'], + stderr=self.format_error_message(expected), + activate_session=None, + exit_code=2 + ) + self.session.getUser.assert_not_called() + self.session.getTag.assert_not_called() + self.session.listPackages.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) + + @mock.patch('koji.util.eventFromOpts', return_value={'id': 1000, + 'ts': 1000000.11}) + def test_list_pkgs_event_without_option(self, event_from_opts): + expected = '--event and --ts makes sense only with --tag, --owner or --package' + self.assert_system_exit( + anon_handle_list_pkgs, + self.options, self.session, ['--event', '1000'], + stderr=self.format_error_message(expected), + stdout='Querying at event 1000 (Mon Jan 12 13:46:40 1970)\n', + activate_session=None, + exit_code=2 + ) + self.session.getUser.assert_not_called() + self.session.getTag.assert_not_called() + self.session.listPackages.assert_not_called() + self.ensure_connection_mock.assert_called_once_with(self.session, self.options) diff --git a/tests/test_cli/test_remove_tag_inheritance.py b/tests/test_cli/test_remove_tag_inheritance.py index 2b23cbae..f97a3ae6 100644 --- a/tests/test_cli/test_remove_tag_inheritance.py +++ b/tests/test_cli/test_remove_tag_inheritance.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import mock -from six.moves import StringIO +from mock import call import koji from koji_cli.commands import handle_remove_tag_inheritance @@ -14,35 +14,24 @@ class TestRemoveTagInheritance(utils.CliTestCase): self.options.debug = False self.session = mock.MagicMock() self.session.getAPIVersion.return_value = koji.API_VERSION + self.activate_session_mock = mock.patch('koji_cli.commands.activate_session').start() + self.error_format = """Usage: %s remove-tag-inheritance +(Specify the --help global option for a list of other help options) - @mock.patch('sys.stderr', new_callable=StringIO) - def test_remove_tag_inheritance_without_option(self, stderr): - expected = "Usage: %s remove-tag-inheritance \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: This command takes at least one argument: " \ - "a tag name or ID\n" % (self.progname, self.progname) - with self.assertRaises(SystemExit) as ex: - handle_remove_tag_inheritance(self.options, self.session, []) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - - @mock.patch('sys.stderr', new_callable=StringIO) - def test_remove_tag_inheritance_non_exist_tag(self, stderr): - tag = 'test-tag' - parent_tag = 'parent-test-tag' - priority = '99' - expected = "Usage: %s remove-tag-inheritance \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such tag: %s\n" % (self.progname, self.progname, tag) - self.session.getTag.return_value = None - with self.assertRaises(SystemExit) as ex: - handle_remove_tag_inheritance(self.options, self.session, [tag, parent_tag, priority]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) - - @mock.patch('sys.stderr', new_callable=StringIO) - def test_remove_tag_inheritance_non_exist_parent_tag(self, stderr): - side_effect_result = [{'arches': 'x86_64', +%s: error: {message} +""" % (self.progname, self.progname) + self.tag = 'test-tag' + self.parent_tag = 'parent-test-tag' + self.priority = '99' + self.tag_inheritance = {'child_id': 1, + 'intransitive': False, + 'maxdepth': None, + 'name': self.tag, + 'noconfig': False, + 'parent_id': 2, + 'pkg_filter': '', + 'priority': self.priority} + self.child_tag_info = {'arches': 'x86_64', 'extra': {}, 'id': 1, 'locked': False, @@ -50,16 +39,172 @@ class TestRemoveTagInheritance(utils.CliTestCase): 'maven_support': False, 'name': 'test-tag', 'perm': None, - 'perm_id': None}, - None] - tag = 'test-tag' - parent_tag = 'parent-test-tag' - priority = '99' - expected = "Usage: %s remove-tag-inheritance \n" \ - "(Specify the --help global option for a list of other help options)\n\n" \ - "%s: error: No such tag: %s\n" % (self.progname, self.progname, parent_tag) - self.session.getTag.side_effect = side_effect_result - with self.assertRaises(SystemExit) as ex: - handle_remove_tag_inheritance(self.options, self.session, [tag, parent_tag, priority]) - self.assertExitCode(ex, 2) - self.assert_console_message(stderr, expected) + 'perm_id': None} + self.parent_tag_info = {'arches': 'x86_64', + 'extra': {}, + 'id': 2, + 'locked': False, + 'maven_include_all': False, + 'maven_support': False, + 'name': 'parent-test-tag', + 'perm': None, + 'perm_id': None} + + def test_remove_tag_inheritance_without_option(self): + expected = self.format_error_message( + "This command takes at least one argument: a tag name or ID") + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() + self.session.getTag.assert_not_called() + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_more_arguments(self): + expected = self.format_error_message( + "This command takes at most three argument: a tag name or ID, " + "a parent tag name or ID, and a priority") + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + ['arg1', 'arg2', 'arg3', 'arg4'], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_not_called() + self.session.getTag.assert_not_called() + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_non_exist_tag(self): + self.session.getTag.return_value = None + expected = self.format_error_message("No such tag: %s" % self.tag) + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.tag) + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_non_exist_parent_tag(self): + self.session.getTag.side_effect = [self.child_tag_info, None] + expected = self.format_error_message("No such tag: %s" % self.parent_tag) + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='', + stderr=expected, + activate_session=None, + exit_code=2 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_not_called() + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_non_exist_inheritance(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.return_value = [] + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='', + stderr='No inheritance link found to remove. Please check your arguments\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_multi_inheritance_without_parent(self): + self.session.getTag.return_value = self.child_tag_info + self.session.getInheritanceData.return_value = [self.tag_inheritance, self.tag_inheritance] + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [self.tag], + stdout='Multiple matches for tag.\n', + stderr='Please specify a parent on the command line.\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_called_once_with(self.tag) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_multi_inheritance_without_priority(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.return_value = [self.tag_inheritance, self.tag_inheritance] + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag], + stdout='Multiple matches for tag.\n', + stderr='Please specify a priority on the command line.\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_multi_inheritance(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.return_value = [self.tag_inheritance, self.tag_inheritance] + self.assert_system_exit( + handle_remove_tag_inheritance, + self.options, + self.session, + [self.tag, self.parent_tag, self.priority], + stdout='Multiple matches for tag.\n', + stderr='Error: Key constraints may be broken. Exiting.\n', + activate_session=None, + exit_code=1 + ) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_called_once_with(1) + self.session.setInheritanceData.assert_not_called() + + def test_remove_tag_inheritance_valid(self): + self.session.getTag.side_effect = [self.child_tag_info, self.parent_tag_info] + self.session.getInheritanceData.side_effect = [[self.tag_inheritance], + [self.tag_inheritance]] + handle_remove_tag_inheritance(self.options, self.session, + [self.tag, self.parent_tag, self.priority]) + self.activate_session_mock.assert_called_once_with(self.session, self.options) + self.session.getTag.assert_has_calls([call(self.tag), call(self.parent_tag)]) + self.session.getInheritanceData.assert_has_calls([call(1), call(1)]) + self.session.setInheritanceData.assert_called_once_with( + 1, [{'child_id': 1, 'intransitive': False, 'maxdepth': None, 'name': self.tag, + 'noconfig': False, 'parent_id': 2, 'pkg_filter': '', 'priority': self.priority, + 'delete link': True}])