make cli and hub to support remove-extra for edit-tag

This commit is contained in:
Yuming Zhu 2017-03-10 00:28:16 +08:00 committed by Mike McLean
parent 120ee07d24
commit 75d07f6d01
4 changed files with 409 additions and 8 deletions

View file

@ -4886,6 +4886,8 @@ def handle_edit_tag(options, session, args):
parser.add_option("--no-include-all", action="store_true", help=_("Do not include all packages in this tag when generating Maven repos"))
parser.add_option("-x", "--extra", action="append", default=[], metavar="key=value",
help=_("Set tag extra option"))
parser.add_option("-r", "--remove-extra", action="append", default=[], metavar="key",
help=_("Remove tag extra option"))
(options, args) = parser.parse_args(args)
if len(args) != 1:
parser.error(_("Please specify a name for the tag"))
@ -4920,8 +4922,10 @@ def handle_edit_tag(options, session, args):
value = arg_filter(value)
extra[key] = value
opts['extra'] = extra
if options.remove_extra:
opts['remove_extra'] = options.remove_extra
#XXX change callname
session.editTag2(tag,**opts)
session.editTag2(tag, **opts)
def handle_lock_tag(options, session, args):
"[admin] Lock a tag"

View file

@ -2976,7 +2976,8 @@ def edit_tag(tagInfo, **kwargs):
maven_support: whether Maven repos should be generated for the tag
maven_include_all: include every build in this tag (including multiple
versions of the same package) in the Maven repo
extra: extra tag parameters (dictionary)
extra: add or update extra tag parameters (dictionary)
remove_extra: remove extra tag parameters (list)
"""
context.session.assertPerm('admin')
@ -3014,8 +3015,8 @@ def _edit_tag(tagInfo, **kwargs):
#new name is taken
raise koji.GenericError("Name %s already taken by tag %s" % (name, id))
update = """UPDATE tag
SET name = %(name)s
WHERE id = %(tagID)i"""
SET name = %(name)s
WHERE id = %(tagID)i"""
_dml(update, values)
#check for changes
@ -3038,13 +3039,18 @@ def _edit_tag(tagInfo, **kwargs):
# handle extra data
if 'extra' in kwargs:
# check whether one key is both in extra and remove_extra
if 'remove_extra' in kwargs:
for removed in kwargs['remove_extra']:
if removed in kwargs['extra']:
raise koji.GenericError("Can not both add/update and remove tag-extra: '%s'" % removed)
for key in kwargs['extra']:
value = kwargs['extra'][key]
if key not in tag['extra'] or tag['extra'] != value:
if key not in tag['extra'] or tag['extra'][key] != value:
data = {
'tag_id' : tag['id'],
'key' : key,
'value' : json.dumps(kwargs['extra'][key]),
'tag_id': tag['id'],
'key': key,
'value': json.dumps(kwargs['extra'][key]),
}
# revoke old entry, if any
update = UpdateProcessor('tag_extra', values=data, clauses=['tag_id = %(tag_id)i', 'key=%(key)s'])
@ -3055,6 +3061,21 @@ def _edit_tag(tagInfo, **kwargs):
insert.make_create()
insert.execute()
# handle remove_extra data
if 'remove_extra' in kwargs:
ne = [e for e in kwargs['remove_extra'] if e not in tag['extra']]
if ne:
raise koji.GenericError("Tag: %s doesn't have extra: %s" % (tag['name'], ', '.join(ne)))
for key in kwargs['remove_extra']:
data = {
'tag_id': tag['id'],
'key': key,
}
# revoke old entry
update = UpdateProcessor('tag_extra', values=data, clauses=['tag_id = %(tag_id)i', 'key=%(key)s'])
update.make_revoke()
update.execute()
def old_edit_tag(tagInfo, name, arches, locked, permissionID, extra=None):
"""Edit information for an existing tag."""

View file

@ -0,0 +1,180 @@
import unittest
import StringIO as stringio
import os
import sys
import mock
from mock import call
import loadcli
cli = loadcli.cli
progname = os.path.basename(sys.argv[0]) or 'koji'
class TestEditTag(unittest.TestCase):
# Show long diffs in error output...
maxDiff = None
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
@mock.patch('koji_cli.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)
args.append('--lock')
args.append('--rename=' + rename)
args.append('--maven-support')
args.append('--include-all')
for k, x in extra.iteritems():
args.append('-x')
args.append(k + '=' + str(x))
for r in 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,
'remove_extra': remove_extra}
options = mock.MagicMock()
# Mock out the xmlrpc server
session = mock.MagicMock()
# 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 = cli.handle_edit_tag(options, 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)
session.editTag2.assert_called_once_with(tag, **opts)
self.assertEqual(rv, None)
stdout.seek(0)
stdout.truncate()
session.reset_mock()
activate_session_mock.reset_mock()
args = [tag]
args.append('--no-perm')
args.append('--unlock')
args.append('--no-maven-support')
args.append('--no-include-all')
opts = {'perm_id': None,
'locked': not locked,
'maven_support': not maven_support,
'maven_include_all': not maven_include_all}
# Run it and check immediate output
# args: tag --no-perm --unlock --no-maven-support --no-include-all
# expected: success
rv = cli.handle_edit_tag(options, 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)
session.editTag2.assert_called_once_with(tag, **opts)
self.assertEqual(rv, None)
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
@mock.patch('sys.stderr', new_callable=stringio.StringIO)
@mock.patch('koji_cli.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()
# Run it and check immediate output
# args: --help
# expected: failed, help info shows
with self.assertRaises(SystemExit) as cm:
cli.handle_edit_tag(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = """Usage: %s edit-tag [options] name
(Specify the --help global option for a list of other help options)
Options:
-h, --help show this help message and exit
--arches=ARCHES Specify arches
--perm=PERM Specify permission requirement
--no-perm Remove permission requirement
--lock Lock the tag
--unlock Unlock the tag
--rename=RENAME Rename the tag
--maven-support Enable creation of Maven repos for this tag
--no-maven-support Disable creation of Maven repos for this tag
--include-all Include all packages in this tag when generating Maven
repos
--no-include-all Do not include all packages in this tag when
generating Maven repos
-x key=value, --extra=key=value
Set tag extra option
-r key, --remove-extra=key
Remove tag extra option
""" % progname
expected_stderr = ''
self.assertMultiLineEqual(actual_stdout, expected_stdout)
self.assertMultiLineEqual(actual_stderr, expected_stderr)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_not_called()
session.editTag2.assert_not_called()
self.assertEqual(cm.exception.code, 0)
@mock.patch('sys.stdout', new_callable=stringio.StringIO)
@mock.patch('sys.stderr', new_callable=stringio.StringIO)
@mock.patch('koji_cli.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()
# Run it and check immediate output
# args: --help
# expected: failed, help info shows
with self.assertRaises(SystemExit) as cm:
cli.handle_edit_tag(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
expected_stderr = """Usage: %(progname)s edit-tag [options] name
(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)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_not_called()
session.editTag2.assert_not_called()
self.assertEqual(cm.exception.code, 2)
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,196 @@
import mock
import unittest
import koji
import kojihub
UP = kojihub.UpdateProcessor
IP = kojihub.InsertProcessor
class TestEditTag(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
side_effect=self.getInsert).start()
self.inserts = []
self.UpdateProcessor = mock.patch('kojihub.UpdateProcessor',
side_effect=self.getUpdate).start()
self.updates = []
self._dml = mock.patch('kojihub._dml').start()
self._singleValue = mock.patch('kojihub._singleValue').start()
self.get_tag = mock.patch('kojihub.get_tag').start()
self.get_perm_id = mock.patch('kojihub.get_perm_id').start()
self.context = mock.patch('kojihub.context').start()
# It seems MagicMock will not automatically handle attributes that
# start with "assert"
self.context.session.assertLogin = mock.MagicMock()
def tearDown(self):
mock.patch.stopall()
def test_maven_disable(self):
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError):
kojihub._edit_tag('tag', maven_support=True)
with self.assertRaises(koji.GenericError):
kojihub._edit_tag('tag', maven_include_all=False)
self.context.opts.get.return_value = True
kojihub._edit_tag('tag', maven_support=True)
self.get_tag.assert_called_once()
def test_edit(self):
self.get_tag.return_value = {'id': 333,
'perm_id': 1,
'name': 'tag',
'arches': 'arch1 arch3',
'locked': False,
'maven_support': False,
'maven_include_all': False,
'extra': {'exA': 1,
'exC': 3,
'exD': 4}}
self._singleValue.return_value = None
self.context.event_id = 42
self.context.session.user_id = 23
# no1 invoke
kwargs = {
'perm': None,
'name': 'newtag',
'arches': 'arch1 arch2',
'locked': True,
'maven_support': True,
'maven_include_all': True,
'extra': {'exB': [None, 1, 'text', {'dict': 'val'}, (1, 2)]},
'remove_extra': ['exC']
}
kojihub._edit_tag('tag', **kwargs)
self.get_perm_id.assert_not_called()
self._dml.assert_called_with("""UPDATE tag
SET name = %(name)s
WHERE id = %(tagID)i""", {'name': 'newtag', 'tagID': 333})
# check the insert/update
self.assertEqual(len(self.updates), 3)
self.assertEqual(len(self.inserts), 2)
values = {
'arches': 'arch1 arch2',
'locked': True,
'maven_include_all': True,
'maven_support': True,
'perm_id': None,
'id': 333,
'name': 'tag',
'extra': {'exA': 1, 'exC': 3, 'exD': 4}
}
revoke_data = {
'revoke_event': 42,
'revoker_id': 23
}
revoke_rawdata = {'active': 'NULL'}
update = self.updates[0]
self.assertEqual(update.table, 'tag_config')
self.assertEqual(update.values, values)
self.assertEqual(update.data, revoke_data)
self.assertEqual(update.rawdata, revoke_rawdata)
self.assertEqual(update.clauses, ['tag_id = %(id)i', 'active = TRUE'])
data = {
'create_event': 42,
'creator_id': 23,
'arches': 'arch1 arch2',
'locked': True,
'maven_include_all': True,
'maven_support': True,
'perm_id': None,
'tag_id': 333,
}
insert = self.inserts[0]
self.assertEqual(insert.table, 'tag_config')
self.assertEqual(insert.data, data)
self.assertEqual(insert.rawdata, {})
values = {
'key': 'exB',
'value': '[null, 1, "text", {"dict": "val"}, [1, 2]]',
'tag_id': 333,
}
update = self.updates[1]
self.assertEqual(update.table, 'tag_extra')
self.assertEqual(update.values, values)
self.assertEqual(update.data, revoke_data)
self.assertEqual(update.rawdata, revoke_rawdata)
self.assertEqual(update.clauses, ['tag_id = %(tag_id)i', 'key=%(key)s', 'active = TRUE'])
data = {
'create_event': 42,
'creator_id': 23,
'key': 'exB',
'value': '[null, 1, "text", {"dict": "val"}, [1, 2]]',
'tag_id': 333,
}
insert = self.inserts[1]
self.assertEqual(insert.table, 'tag_extra')
self.assertEqual(insert.data, data)
self.assertEqual(insert.rawdata, {})
values = {
'key': 'exC',
'tag_id': 333,
}
update = self.updates[2]
self.assertEqual(update.table, 'tag_extra')
self.assertEqual(update.values, values)
self.assertEqual(update.data, revoke_data)
self.assertEqual(update.rawdata, revoke_rawdata)
self.assertEqual(update.clauses, ['tag_id = %(tag_id)i', 'key=%(key)s', 'active = TRUE'])
# no2 invoke
kwargs = {
'extra': {'exC': 'text'},
'remove_extra': ['exC']
}
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_tag('tag', **kwargs)
self.assertEqual(cm.exception.args[0], 'Can not both add/update and remove tag-extra: \'exC\'')
# no3 invoke
kwargs = {
'remove_extra': ['exE']
}
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_tag('tag', **kwargs)
self.assertEqual(cm.exception.args[0], "Tag: tag doesn't have extra: exE")
# no4 invoke
self.get_perm_id.reset_mock()
self.get_perm_id.return_value = 99
self._singleValue.reset_mock()
self._singleValue.return_value = 2
kwargs = {
'perm': 'admin',
'name': 'newtag',
}
with self.assertRaises(koji.GenericError) as cm:
kojihub._edit_tag('tag', **kwargs)
self.get_perm_id.assert_called_once()
self._singleValue.assert_called_once()
self.assertEqual(cm.exception.args[0], 'Name newtag already taken by tag 2')