Hub, plugins and tools inputs validation

Fixes: https://pagure.io/koji/issue/3319
This commit is contained in:
Jana Cupova 2022-04-04 08:38:29 +02:00
parent a371c76128
commit 9bfefe782e
75 changed files with 3031 additions and 1695 deletions

View file

@ -91,6 +91,30 @@ def xform_user_krb(entry):
return entry
def convert_value(value, cast=None, message=None, exc_type=None, none_allowed=False):
if exc_type is None:
exc_type = koji.ParameterError
if value is None:
if not none_allowed:
raise(exc_type(message or "Invalid type"))
else:
return value
try:
return cast(value)
except (ValueError, TypeError):
raise(exc_type(message or f"Invalid type for value '{value}': {type(value)}"))
def check_value_type(value, cast=None, message=None, exc_type=None, none_allowed=False):
if none_allowed:
if value is None:
return value
if exc_type is None:
exc_type = koji.ParameterError
if not isinstance(value, cast):
raise (exc_type(message or f"Invalid type for value '{value}': {type(value)}"))
class Task(object):
"""A task for the build hosts"""
@ -116,7 +140,7 @@ class Task(object):
('task.weight', 'weight'))
def __init__(self, id):
self.id = int(id)
self.id = convert_value(id, cast=int)
self.logger = logging.getLogger("koji.hub.Task")
def _split_fields(self, fields=None):
@ -288,7 +312,7 @@ class Task(object):
def setWeight(self, weight):
"""Set weight for task"""
task_id = self.id
weight = float(weight)
weight = convert_value(weight, cast=float)
info = self.getInfo(request=True)
self.runCallbacks('preTaskStateChange', info, 'weight', weight)
# access checks should be performed by calling function
@ -299,7 +323,7 @@ class Task(object):
def setPriority(self, priority, recurse=False):
"""Set priority for task"""
task_id = self.id
priority = int(priority)
priority = convert_value(priority, cast=int)
info = self.getInfo(request=True)
self.runCallbacks('preTaskStateChange', info, 'priority', priority)
# access checks should be performed by calling function
@ -540,6 +564,22 @@ def make_task(method, arglist, **opts):
priority: the priority of the task
assign: a host_id to assign the task to
"""
check_value_type(method, cast=str)
if 'parent' in opts:
opts['parent'] = convert_value(opts['parent'], cast=int)
if 'label' in opts:
check_value_type(opts['label'], cast=str)
if 'owner' in opts:
if not isinstance(opts['owner'], int):
opts['owner'] = get_user(opts['owner'], strict=True)['id']
if 'arch' in opts:
opts['arch'] = koji.parse_arches(opts['arch'], strict=True, allow_none=True)
if 'priority' in opts:
opts['priority'] = \
convert_value(opts['priority'], cast=int)
if 'assign' in opts:
if not isinstance(opts['assign'], int):
opts['assign'] = get_host(opts['assign'], strict=True)['id']
if 'parent' in opts:
# for subtasks, we use some of the parent's options as defaults
fields = ('state', 'owner', 'channel_id', 'priority', 'arch')
@ -1389,6 +1429,8 @@ def readTaggedBuilds(tag, event=None, inherit=False, latest=False, package=None,
'build.state = %(st_complete)i'
]
if package:
if not isinstance(package, str):
package = lookup_package(package, strict=True)['name']
clauses.append('package.name = %(package)s')
if owner:
clauses.append('users.name = %(owner)s')
@ -1636,8 +1678,10 @@ def check_tag_access(tag_id, user_id=None):
"""
if user_id is None:
user_id = context.session.user_id
if user_id is None:
raise koji.GenericError("a user_id is required")
if not user_id:
raise koji.GenericError("a user_id is required")
else:
user_id = convert_value(user_id, cast=int)
perms = koji.auth.get_user_perms(user_id)
override = False
if 'admin' in perms:
@ -2376,12 +2420,14 @@ def edit_channel(channelInfo, **kw):
return False
if kw.get('name'):
if not isinstance(kw['name'], str):
raise koji.GenericError("new channel name must be a string")
verify_name_internal(kw['name'])
dup_check = get_channel(kw['name'], strict=False)
if dup_check:
raise koji.GenericError("channel %(name)s already exists (id=%(id)i)" % dup_check)
if kw.get('description'):
check_value_type(kw['description'], cast=str)
if kw.get('comment'):
check_value_type(kw['comment'], cast=str)
update = UpdateProcessor('channels',
values={'channelID': channel['id']},
@ -2433,8 +2479,7 @@ def add_channel(channel_name, description=None):
:param str description: description of channel
"""
context.session.assertPerm('admin')
if not isinstance(channel_name, str):
raise koji.GenericError("Channel name must be a string")
check_value_type(description, cast=str, none_allowed=True)
verify_name_internal(channel_name)
dup_check = get_channel(channel_name, strict=False)
if dup_check:
@ -2449,6 +2494,7 @@ def add_channel(channel_name, description=None):
def set_channel_enabled(channelname, enabled=True, comment=None):
context.session.assertPerm('host')
check_value_type(comment, cast=str, none_allowed=True)
channel = get_channel(channelname)
if not channel:
raise koji.GenericError('No such channel: %s' % channelname)
@ -2640,6 +2686,7 @@ def repo_init(tag, task_id=None, with_src=False, with_debuginfo=False, event=Non
Returns a dictionary containing
repo_id, event_id
"""
task_id = convert_value(task_id, cast=int, none_allowed=True)
logger = logging.getLogger("koji.hub.repo_init")
state = koji.REPO_INIT
tinfo = get_tag(tag, strict=True, event=event)
@ -2694,9 +2741,9 @@ def repo_init(tag, task_id=None, with_src=False, with_debuginfo=False, event=Non
'tag_id': tinfo['id'],
'task_id': task_id,
'event_id': event_id,
'with_src': with_src,
'with_separate_src': with_separate_src,
'with_debuginfo': with_debuginfo,
'with_src': bool(with_src),
'with_separate_src': bool(with_separate_src),
'with_debuginfo': bool(with_debuginfo),
}
with open('%s/repo.json' % repodir, 'wt', encoding='utf-8') as fp:
json.dump(repo_info, fp, indent=2)
@ -2823,9 +2870,12 @@ def _write_maven_repo_metadata(destdir, artifacts):
def dist_repo_init(tag, keys, task_opts):
"""Create a new repo entry in the INIT state, return full repo data"""
state = koji.REPO_INIT
check_value_type(keys, cast=list)
tinfo = get_tag(tag, strict=True)
tag_id = tinfo['id']
check_value_type(task_opts, cast=dict)
event = task_opts.get('event')
event = convert_value(event, cast=int, none_allowed=True)
volume = task_opts.get('volume')
if volume is not None:
volume = lookup_name('volume', volume, strict=True)['name']
@ -2853,6 +2903,7 @@ def dist_repo_init(tag, keys, task_opts):
os.symlink(relpath, basedir)
# handle comps
if task_opts.get('comps'):
check_value_type(task_opts['comps'], cast=str)
groupsdir = joinpath(repodir, 'groups')
koji.ensuredir(groupsdir)
shutil.copyfile(joinpath(koji.pathinfo.work(),
@ -2877,6 +2928,7 @@ def dist_repo_init(tag, keys, task_opts):
def repo_set_state(repo_id, state, check=True):
"""Set repo state"""
repo_id = convert_value(repo_id, cast=int)
if check:
# The repo states are sequential, going backwards makes no sense
q = """SELECT state FROM repo WHERE id = %(repo_id)s FOR UPDATE"""
@ -2934,6 +2986,7 @@ def repo_delete(repo_id):
"""Attempt to mark repo deleted, return number of references
If the number of references is nonzero, no change is made"""
repo_id = convert_value(repo_id, cast=int)
# get a row lock on the repo
q = """SELECT state FROM repo WHERE id = %(repo_id)s FOR UPDATE"""
_singleValue(q, locals())
@ -3235,14 +3288,12 @@ def name_or_id_clause(table, info):
"""
if isinstance(info, dict):
if 'id' in info:
try:
info = int(info['id'])
except (ValueError, TypeError):
raise koji.ParameterError('Invalid name or id value: %r' % info)
info = convert_value(info['id'], cast=int,
message=fr"Invalid name or id value: {info}")
elif 'name' in info:
info = info['name']
else:
raise koji.ParameterError('Invalid name or id value: %r' % info)
raise koji.ParameterError(fr'Invalid name or id value: {info}')
if isinstance(info, int):
clause = f"({table}.id = %({table}_id)s)"
values = {f"{table}_id": info}
@ -3250,7 +3301,7 @@ def name_or_id_clause(table, info):
clause = f"({table}.name = %({table}_name)s)"
values = {f"{table}_name": info}
else:
raise koji.ParameterError('Invalid name or id value: %r' % info)
raise koji.ParameterError(fr"Invalid name or id value: {info}")
return clause, values
@ -3557,6 +3608,10 @@ def _edit_tag(tagInfo, **kwargs):
if not context.opts.get('EnableMaven') \
and dslice(kwargs, ['maven_support', 'maven_include_all'], strict=False):
raise koji.GenericError("Maven support not enabled")
if kwargs.get('remove_extra'):
check_value_type(kwargs['remove_extra'], cast=list, none_allowed=True)
if kwargs.get('block_extra'):
check_value_type(kwargs['block_extra'], cast=list, none_allowed=True)
tag = get_tag(tagInfo, strict=True)
if 'perm' in kwargs and 'perm_id' not in kwargs:
@ -3882,6 +3937,8 @@ def add_external_repo_to_tag(tag_info, repo_info, priority, merge_mode='koji', a
if arches is not None:
arches = koji.parse_arches(arches, strict=True)
priority = convert_value(priority, cast=int)
tag_repos = get_tag_external_repos(tag_info=tag_id)
if [tr for tr in tag_repos if tr['external_repo_id'] == repo_id]:
raise koji.GenericError('tag %s already associated with external repo %s' %
@ -4442,8 +4499,7 @@ def get_next_release(build_info, incr=1):
:raises: BuildError if the latest build uses a release value that Koji
does not know how to increment.
"""
if not isinstance(incr, int):
raise koji.ParameterError("incr parameter must be an integer")
incr = convert_value(incr, cast=int, message='incr parameter must be an integer')
values = {
'name': build_info['name'],
'version': build_info['version'],
@ -5522,6 +5578,10 @@ def edit_host(hostInfo, **kw):
if not changes:
return False
for change in changes:
if change in ['description', 'comment', 'arches']:
check_value_type(kw[change], cast=str)
update = UpdateProcessor('host_config', values=host, clauses=['host_id = %(id)i'])
update.make_revoke()
update.execute()
@ -5675,7 +5735,7 @@ def query_buildroots(hostID=None, tagID=None, state=None, rpmID=None, archiveID=
def get_buildroot(buildrootID, strict=False):
"""Return information about a buildroot. buildrootID must be an int ID."""
buildrootID = convert_value(buildrootID, cast=int)
result = query_buildroots(buildrootID=buildrootID)
if len(result) == 0:
if strict:
@ -5741,6 +5801,7 @@ def list_channels(hostID=None, event=None, enabled=None):
def new_package(name, strict=True):
verify_name_internal(name)
c = context.cnx.cursor()
# TODO - table lock?
# check for existing
@ -6171,6 +6232,10 @@ def import_build(srpm, rpms, brmap=None, task_id=None, build_id=None, logs=None)
"""
if brmap is None:
brmap = {}
else:
check_value_type(brmap, cast=dict)
check_value_type(srpm, cast=str)
check_value_type(rpms, cast=list)
koji.plugin.run_callbacks('preImport', type='build', srpm=srpm, rpms=rpms, brmap=brmap,
task_id=task_id, build_id=build_id, build=None, logs=logs)
uploadpath = koji.pathinfo.work()
@ -6536,7 +6601,6 @@ class CG_Importer(object):
def get_metadata(self, metadata, directory):
"""Get the metadata from the args"""
if isinstance(metadata, dict):
self.metadata = metadata
try:
@ -6548,8 +6612,7 @@ class CG_Importer(object):
if metadata is None:
# default to looking for uploaded file
metadata = 'metadata.json'
if not isinstance(metadata, str):
raise koji.GenericError("Invalid type for metadata value: %r" % type(metadata))
check_value_type(metadata, cast=str)
if metadata.endswith('.json'):
# handle uploaded metadata
workdir = koji.pathinfo.work()
@ -7324,8 +7387,7 @@ def get_archive_type(filename=None, type_name=None, type_id=None, strict=False):
elif type_name:
return _get_archive_type_by_name(type_name, strict)
elif filename:
# we handle that below
pass
check_value_type(filename, cast=str)
else:
raise koji.GenericError('one of filename, type_name, or type_id must be specified')
@ -7365,6 +7427,8 @@ def add_archive_type(name, description, extensions):
"""
context.session.assertPerm('admin')
verify_name_internal(name)
check_value_type(description, cast=str)
check_value_type(extensions, cast=str)
data = {'name': name,
'description': description,
'extensions': extensions,
@ -8774,6 +8838,9 @@ def tag_notification(is_successful, tag_id, from_id, build_id, user_id, ignore_s
failure_msg=''):
if context.opts.get('DisableNotifications'):
return
if user_id:
if not isinstance(user_id, int):
user_id = get_user(user_id, strict=True)
if is_successful:
state = koji.BUILD_STATES['COMPLETE']
else:
@ -10320,6 +10387,7 @@ def policy_data_from_task_args(method, arglist):
# newRepo has a 'src' parameter that means something else
break
if k in params:
check_value_type(params[k], cast=str)
policy_data['source'] = params.get(k)
break
# parameters that indicate build target
@ -10482,8 +10550,10 @@ class RootExports(object):
context.session.assertPerm('host')
if options is None:
args = []
else:
elif isinstance(options, dict):
args = [options]
else:
raise koji.ParameterError('Invalid type of options: %s' % type(options))
return make_task('restartHosts', args, priority=priority)
def build(self, src, target, opts=None, priority=None, channel=None):
@ -10499,6 +10569,7 @@ class RootExports(object):
if not opts:
opts = {}
taskOpts = {}
check_value_type(src, cast=str)
if priority:
if priority < 0:
if not context.session.hasPerm('admin'):
@ -10522,6 +10593,7 @@ class RootExports(object):
Returns a list of all the dependent task ids
"""
context.session.assertLogin()
check_value_type(srcs, cast=list)
if not opts:
opts = {}
taskOpts = {}
@ -10550,6 +10622,7 @@ class RootExports(object):
context.session.assertLogin()
if not context.opts.get('EnableMaven'):
raise koji.GenericError("Maven support not enabled")
check_value_type(url, cast=str)
if not opts:
opts = {}
taskOpts = {}
@ -10586,13 +10659,13 @@ class RootExports(object):
if not opts:
opts = {}
check_value_type(url, cast=str)
build = self.getBuild(build, strict=True)
if list_rpms(build['id']) and not (opts.get('scratch') or opts.get('create_build')):
raise koji.PreBuildError('wrapper rpms for %s have already been built' %
koji.buildLabel(build))
build_target = self.getBuildTarget(target)
if not build_target:
raise koji.PreBuildError('no such build target: %s' % target)
build_target = self.getBuildTarget(target, strict=True)
build_tag = self.getTag(build_target['build_tag'], strict=True)
repo_info = self.getRepo(build_tag['id'])
if not repo_info:
@ -10602,7 +10675,8 @@ class RootExports(object):
taskOpts = {}
if priority:
taskOpts['priority'] = koji.PRIO_DEFAULT + priority
taskOpts['channel'] = channel
if channel:
taskOpts['channel'] = channel
return make_task('wrapperRPM', [url, build_target, build, None, opts], **taskOpts)
@ -10621,6 +10695,7 @@ class RootExports(object):
context.session.assertLogin()
if not context.opts.get('EnableMaven'):
raise koji.GenericError("Maven support not enabled")
check_value_type(builds, cast=list)
taskOpts = {}
if priority:
if priority < 0:
@ -10650,7 +10725,9 @@ class RootExports(object):
context.session.assertLogin()
if not context.opts.get('EnableWin'):
raise koji.GenericError("Windows support not enabled")
targ_info = self.getBuildTarget(target)
check_value_type(vm, cast=str)
check_value_type(url, cast=str)
targ_info = get_build_target(target, strict=True)
policy_data = {'vm_name': vm,
'tag': targ_info['dest_tag']}
assert_policy('vm', policy_data)
@ -10676,6 +10753,8 @@ class RootExports(object):
if img_type not in ('livecd', 'appliance', 'livemedia'):
raise koji.GenericError('Unrecognized image type: %s' % img_type)
for i in [name, ksfile, version]:
check_value_type(i, cast=str)
context.session.assertPerm(img_type)
@ -10723,6 +10802,8 @@ class RootExports(object):
"""
Create an image using a kickstart file and group package list.
"""
for i in [name, inst_tree, version]:
check_value_type(i, cast=str)
context.session.assertPerm('image')
taskOpts = {'channel': 'image'}
if priority:
@ -10986,6 +11067,9 @@ class RootExports(object):
def downloadTaskOutput(self, taskID, fileName, offset=0, size=-1, volume=None):
"""Download the file with the given name, generated by the task with the
given ID."""
size = convert_value(size, cast=int)
if volume:
volume = self.getVolume(volume, strict=True)['name']
if '..' in fileName:
raise koji.GenericError('Invalid file name: %s' % fileName)
filePath = '%s/%s/%s' % (koji.pathinfo.work(volume),
@ -12493,6 +12577,7 @@ class RootExports(object):
verify_name_internal(permission)
if description is not None and not create:
raise koji.GenericError('Description should be specified only with create.')
check_value_type(description, cast=str, none_allowed=True)
user_id = get_user(userinfo, strict=True)['id']
perm = lookup_perm(permission, strict=(not create), create=create)
perm_id = perm['id']
@ -12526,6 +12611,7 @@ class RootExports(object):
def editPermission(self, permission, description):
"""Edit a permission description"""
context.session.assertPerm('admin')
check_value_type(description, cast=str)
perm = lookup_perm(permission, strict=True)
perm_id = perm['id']
update = UpdateProcessor('permissions', clauses=['id=%(perm_id)i'],
@ -12550,22 +12636,18 @@ class RootExports(object):
raise koji.GenericError('user already exists: %s' % username)
if krb_principal and get_user_by_krb_principal(krb_principal):
raise koji.GenericError(
'user with this Kerberos principal already exists: %s'
% krb_principal)
return context.session.createUser(username, status=status,
krb_principal=krb_principal)
'user with this Kerberos principal already exists: %s' % krb_principal)
status = convert_value(status, cast=int, none_allowed=True)
return context.session.createUser(username, status=status, krb_principal=krb_principal)
def addUserKrbPrincipal(self, user, krb_principal):
"""Add a Kerberos principal for user"""
context.session.assertPerm('admin')
userinfo = get_user(user, strict=True)
if not krb_principal:
raise koji.GenericError('krb_principal must be specified')
verify_name_user(krb=krb_principal)
if get_user_by_krb_principal(krb_principal):
raise koji.GenericError(
'user with this Kerberos principal already exists: %s'
% krb_principal)
'user with this Kerberos principal already exists: %s' % krb_principal)
return context.session.setKrbPrincipal(userinfo['name'], krb_principal)
def removeUserKrbPrincipal(self, user, krb_principal):
@ -13036,6 +13118,7 @@ class RootExports(object):
# builder user can already exist, if host tried to log in before adding into db
userinfo = {'name': hostname}
if krb_principal:
verify_name_user(krb=krb_principal)
userinfo['krb_principal'] = krb_principal
user = get_user(userInfo=userinfo)
if user:
@ -13757,6 +13840,7 @@ class BuildRoot(object):
self.is_standard = True
def new(self, host, repo, arch, task_id=None, ctype='chroot'):
arch = koji.parse_arches(arch, strict=True, allow_none=True)
state = koji.BR_STATES['INIT']
br_id = _singleValue("SELECT nextval('buildroot_id_seq')", strict=True)
insert = InsertProcessor('buildroot', data={'id': br_id})
@ -14016,7 +14100,7 @@ class Host(object):
def taskSetWait(self, parent, tasks):
"""Mark task waiting and subtasks awaited"""
check_value_type(tasks, cast=list, none_allowed=True)
# mark parent as waiting
update = UpdateProcessor('task', clauses=['id=%(parent)s'], values=locals())
update.set(waiting=True)
@ -14134,6 +14218,7 @@ class Host(object):
def updateHost(self, task_load, ready):
host_data = get_host(self.id)
task_load = convert_value(task_load, cast=float)
if task_load != host_data['task_load'] or ready != host_data['ready']:
c = context.cnx.cursor()
id = self.id
@ -14416,6 +14501,7 @@ class HostExports(object):
def moveImageBuildToScratch(self, task_id, results):
"""move a completed image scratch build into place"""
check_value_type(results, cast=dict)
host = Host()
host.verify()
task = Task(task_id)
@ -14861,6 +14947,8 @@ class HostExports(object):
pkg_id = build['package_id']
tag_id = get_tag(tag, strict=True)['id']
user_id = task.getOwner()
if not isinstance(fromtag, str):
tag = get_tag(tag, strict=True)['name']
policy_data = {'tag': tag, 'build': build, 'fromtag': fromtag}
policy_data['user_id'] = user_id
if fromtag is None:
@ -15156,6 +15244,7 @@ class HostExports(object):
host = Host()
host.verify()
rinfo = repo_info(repo_id, strict=True)
check_value_type(data, cast=dict)
koji.plugin.run_callbacks('preRepoDone', repo=rinfo, data=data, expire=expire)
if rinfo['state'] != koji.REPO_INIT:
raise koji.GenericError("Repo %(id)s not in INIT state (got %(state)s)" % rinfo)

View file

@ -18,10 +18,19 @@ koji.tasks.LEGACY_SIGNATURES['createKiwiImage'] = [
def kiwiBuild(target, arches, desc_url, desc_path, optional_arches=None, profile=None,
scratch=False, priority=None, make_prep=False, repos=None, release=None):
context.session.assertPerm('image')
for i in [desc_url, desc_path, profile, release]:
if i is not None:
kojihub.check_value_type(i, cast=str)
if repos:
kojihub.check_value_type(repos, cast=list)
kojihub.get_build_targets(target, strict=True)
arches = koji.parse_arches(arches, strict=True, allow_none=False)
optional_arches = koji.parse_arches(optional_arches, strict=True, allow_none=True)
taskOpts = {
'channel': 'image',
}
if priority:
priority = kojihub.convert_value(priority, cast=int)
if priority < 0:
if not context.session.hasPerm('admin'):
raise koji.ActionNotAllowed(
@ -31,10 +40,10 @@ def kiwiBuild(target, arches, desc_url, desc_path, optional_arches=None, profile
opts = {
'optional_arches': optional_arches,
'profile': profile,
'scratch': scratch,
'scratch': bool(scratch),
'release': release,
'repos': repos or [],
'make_prep': make_prep,
'make_prep': bool(make_prep),
}
return kojihub.make_task('kiwiBuild',
[target, arches, desc_url, desc_path, opts],

View file

@ -30,12 +30,17 @@ def get_channel_arches(channel):
def runroot(tagInfo, arch, command, channel=None, **opts):
""" Create a runroot task """
context.session.assertPerm('runroot')
arch = koji.parse_arches(arch, strict=True, allow_none=False)
kojihub.check_value_type(command, cast=str)
taskopts = {
'priority': 15,
'arch': arch,
}
taskopts['channel'] = channel or 'runroot'
if channel is None:
taskopts['channel'] = 'runroot'
else:
taskopts['channel'] = kojihub.get_channel(channel, strict=True)['name']
tag = kojihub.get_tag(tagInfo, strict=True)
if arch == 'noarch':

View file

@ -22,7 +22,7 @@ def saveFailedTree(buildrootID, full=False, **opts):
global config, allowed_methods
# let it raise errors
buildrootID = int(buildrootID)
buildrootID = kojihub.convert_value(buildrootID, cast=int)
full = bool(full)
# read configuration only once

View file

@ -21,7 +21,8 @@ from kojihub import ( # noqa: E402
get_tag,
get_user,
nextval,
policy_get_user
policy_get_user,
check_value_type
)
CONFIG_FILE = "/etc/koji-hub/plugins/sidetag.conf"
@ -270,9 +271,11 @@ def editSideTag(sidetag, debuginfo=None, rpm_macros=None, remove_rpm_macros=None
if debuginfo is not None:
kwargs['extra']['with_debuginfo'] = bool(debuginfo)
if rpm_macros is not None:
check_value_type(rpm_macros, cast=dict)
for macro, value in rpm_macros.items():
kwargs['extra']['rpm.macro.%s' % macro] = value
if remove_rpm_macros is not None:
check_value_type(remove_rpm_macros, cast=list)
kwargs['remove_extra'] = ['rpm.macro.%s' % m for m in remove_rpm_macros]
_edit_tag(sidetag['id'], **kwargs)

View file

@ -10,54 +10,74 @@ IP = kojihub.InsertProcessor
class TestAddArchiveType(unittest.TestCase):
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub._multiRow')
@mock.patch('kojihub.get_archive_type')
@mock.patch('kojihub.InsertProcessor')
def test_add_archive_type(self, InsertProcessor, get_archive_type, _multiRow,
verify_name_internal):
# Not sure why mock can't patch kojihub.context, so we do this
session = kojihub.context.session = mock.MagicMock()
mocks = [InsertProcessor, get_archive_type, session]
# It seems MagicMock will not automatically handle attributes that
# start with "assert"
session.assertPerm = mock.MagicMock()
verify_name_internal.return_value = None
def setUp(self):
# expected case
get_archive_type.return_value = None
insert = InsertProcessor.return_value
self.context = mock.patch('kojihub.context').start()
self.context.session.assertPerm = mock.MagicMock()
self.exports = kojihub.RootExports()
self.channel_name = 'test-channel'
self.description = 'test-description'
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
side_effect=self.getInsert).start()
self.inserts = []
self.insert_execute = mock.MagicMock()
self.verify_name_internal = mock.patch('kojihub.verify_name_internal').start()
self.get_archive_type = mock.patch('kojihub.get_archive_type').start()
self._multiRow = mock.patch('kojihub._multiRow').start()
def tearDown(self):
mock.patch.stopall()
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = self.insert_execute
self.inserts.append(insert)
return insert
def test_add_archive_type_valid(self):
self.verify_name_internal.return_value = None
self.get_archive_type.return_value = None
kojihub.add_archive_type('deb', 'Debian package', 'deb')
InsertProcessor.assert_called_once()
insert.execute.assert_called_once()
args, kwargs = InsertProcessor.call_args
ip = IP(*args, **kwargs)
self.assertEqual(ip.table, 'archivetypes')
self.assertEqual(ip.data, {'name': 'deb',
'description': 'Debian package',
'extensions': 'deb'})
self.assertEqual(ip.rawdata, {})
session.assertPerm.assert_called_with('admin')
self.assertEqual(len(self.inserts), 1)
insert = self.inserts[0]
self.assertEqual(insert.table, 'archivetypes')
self.assertEqual(insert.data, {'name': 'deb',
'description': 'Debian package',
'extensions': 'deb'})
self.assertEqual(insert.rawdata, {})
self.context.session.assertPerm.assert_called_with('admin')
for m in mocks:
m.reset_mock()
session.assertPerm = mock.MagicMock()
# already exists
get_archive_type.return_value = True
def test_add_archive_type_already_exists(self):
self.get_archive_type.return_value = True
with self.assertRaises(koji.GenericError):
kojihub.add_archive_type('deb', 'Debian package', 'deb')
InsertProcessor.assert_not_called()
session.assertPerm.assert_called_with('admin')
self.assertEqual(len(self.inserts), 0)
self.context.session.assertPerm.assert_called_with('admin')
def test_add_archive_type_invalid_value_type(self):
self.verify_name_internal.return_value = None
description = ['Debian package']
with self.assertRaises(koji.ParameterError) as ex:
kojihub.add_archive_type('deb', description, 'deb')
self.assertEqual(f"Invalid type for value '{description}': {type(description)}",
str(ex.exception))
def test_add_archive_type_invalid_value_extensions(self):
extensions = ['deb']
with self.assertRaises(koji.ParameterError) as ex:
kojihub.add_archive_type('deb', 'Debian package', extensions)
self.assertEqual(f"Invalid type for value '{extensions}': {type(extensions)}",
str(ex.exception))
def test_add_archive_type_wrong_name_verify(self):
# name is longer as expected
new_archive_type = 'new-archive-type+'
verify_name_internal.side_effect = koji.GenericError
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub.add_archive_type(new_archive_type, 'Debian package', 'deb')
# not except regex rules
verify_name_internal.side_effect = koji.GenericError
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub.add_archive_type(new_archive_type, 'Debian package', 'deb')

View file

@ -22,6 +22,9 @@ class TestAddChannel(unittest.TestCase):
side_effect=self.getInsert).start()
self.inserts = []
self.insert_execute = mock.MagicMock()
self.verify_name_internal = mock.patch('kojihub.verify_name_internal').start()
self.get_channel = mock.patch('kojihub.get_channel').start()
self._singleValue = mock.patch('kojihub._singleValue').start()
def tearDown(self):
mock.patch.stopall()
@ -32,25 +35,19 @@ class TestAddChannel(unittest.TestCase):
self.inserts.append(insert)
return insert
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub.get_channel')
@mock.patch('kojihub._singleValue')
def test_add_channel_exists(self, _singleValue, get_channel, verify_name_internal):
verify_name_internal.return_value = None
get_channel.return_value = {'id': 123, 'name': self.channel_name}
def test_add_channel_exists(self):
self.verify_name_internal.return_value = None
self.get_channel.return_value = {'id': 123, 'name': self.channel_name}
with self.assertRaises(koji.GenericError):
self.exports.addChannel(self.channel_name)
get_channel.assert_called_once_with(self.channel_name, strict=False)
_singleValue.assert_not_called()
self.get_channel.assert_called_once_with(self.channel_name, strict=False)
self._singleValue.assert_not_called()
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub.get_channel')
@mock.patch('kojihub._singleValue')
def test_add_channel_valid(self, _singleValue, get_channel, verify_name_internal):
get_channel.return_value = {}
_singleValue.side_effect = [12]
verify_name_internal.return_value = None
def test_add_channel_valid(self):
self.get_channel.return_value = {}
self._singleValue.side_effect = [12]
self.verify_name_internal.return_value = None
r = self.exports.addChannel(self.channel_name, description=self.description)
self.assertEqual(r, 12)
@ -62,21 +59,20 @@ class TestAddChannel(unittest.TestCase):
self.assertEqual(insert.table, 'channels')
self.context.session.assertPerm.assert_called_once_with('admin')
get_channel.assert_called_once_with(self.channel_name, strict=False)
self.assertEqual(_singleValue.call_count, 1)
_singleValue.assert_has_calls([
self.get_channel.assert_called_once_with(self.channel_name, strict=False)
self.assertEqual(self._singleValue.call_count, 1)
self._singleValue.assert_has_calls([
mock.call("SELECT nextval('channels_id_seq')", strict=True)
])
@mock.patch('kojihub.verify_name_internal')
def test_add_channel_wrong_format(self, verify_name_internal):
def test_add_channel_wrong_name(self):
# name is longer as expected
channel_name = 'test-channel+'
verify_name_internal.side_effect = koji.GenericError
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.addChannel(channel_name)
# not except regex rules
verify_name_internal.side_effect = koji.GenericError
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.addChannel(channel_name)

View file

@ -1,4 +1,5 @@
import unittest
import mock
import koji
import kojihub
@ -6,8 +7,26 @@ import kojihub
class TestAddExternalRepoToTag(unittest.TestCase):
def setUp(self):
self.tag_name = 'test-tag'
self.get_tag = mock.patch('kojihub.get_tag').start()
self.get_external_repo = mock.patch('kojihub.get_external_repo').start()
self.tag_info = {'id': 1, 'name': self.tag_name}
def tearDown(self):
mock.patch.stopall()
def test_with_wrong_merge_mode(self):
merge_mode = 'test-mode'
with self.assertRaises(koji.GenericError) as cm:
kojihub.add_external_repo_to_tag('tag', 'repo', 1, merge_mode=merge_mode)
self.assertEqual('No such merge mode: %s' % merge_mode, str(cm.exception))
kojihub.add_external_repo_to_tag(self.tag_name, 'repo', 1, merge_mode=merge_mode)
self.assertEqual(f"No such merge mode: {merge_mode}", str(cm.exception))
def test_priority_not_int(self):
priority = 'test-priority'
self.get_tag.return_value = self.tag_info
self.get_external_repo.return_value = {'id': 123}
with self.assertRaises(koji.GenericError) as cm:
kojihub.add_external_repo_to_tag(self.tag_name, 'repo', priority, merge_mode=None)
self.assertEqual(f"Invalid type for value '{priority}': {type(priority)}",
str(cm.exception))

View file

@ -20,20 +20,20 @@ class TestAddExternalRPM(unittest.TestCase):
self.nextval = mock.patch('kojihub.nextval').start()
self.Savepoint = mock.patch('kojihub.Savepoint').start()
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
side_effect=self.getInsert).start()
side_effect=self.getInsert).start()
self.inserts = []
self.insert_execute = mock.MagicMock()
self.rpminfo = {
'name': 'NAME',
'version': 'VERSION',
'release': 'RELEASE',
'epoch': None,
'arch': 'noarch',
'payloadhash': 'fakehash',
'size': 42,
'buildtime': 0,
}
'name': 'NAME',
'version': 'VERSION',
'release': 'RELEASE',
'epoch': None,
'arch': 'noarch',
'payloadhash': 'fakehash',
'size': 42,
'buildtime': 0,
}
self.repo = 'myrepo'
def tearDown(self):
@ -63,8 +63,9 @@ class TestAddExternalRPM(unittest.TestCase):
rpminfo = self.rpminfo.copy()
del rpminfo['size']
with self.assertRaises(koji.GenericError):
with self.assertRaises(koji.GenericError) as ex:
kojihub.add_external_rpm(rpminfo, self.repo)
self.assertEqual(f"size field missing: {rpminfo}", str(ex.exception))
self.get_rpm.assert_not_called()
self.nextval.assert_not_called()
@ -73,8 +74,10 @@ class TestAddExternalRPM(unittest.TestCase):
rpminfo = self.rpminfo.copy()
rpminfo['size'] = ['invalid type']
with self.assertRaises(koji.GenericError):
with self.assertRaises(koji.GenericError) as ex:
kojihub.add_external_rpm(rpminfo, self.repo)
self.assertEqual(f"Invalid value for size: {rpminfo['size']}",
str(ex.exception))
self.get_rpm.assert_not_called()
self.nextval.assert_not_called()
@ -88,8 +91,11 @@ class TestAddExternalRPM(unittest.TestCase):
self.get_external_repo_id.return_value = mock.sentinel.repo_id
# call it (default is strict)
with self.assertRaises(koji.GenericError):
nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % self.rpminfo
disp = f"{nvra}@{self.repo}"
with self.assertRaises(koji.GenericError) as ex:
kojihub.add_external_rpm(self.rpminfo, self.repo)
self.assertEqual(f"external rpm already exists: {disp}", str(ex.exception))
self.assertEqual(len(self.inserts), 0)
self.nextval.assert_not_called()
@ -103,8 +109,12 @@ class TestAddExternalRPM(unittest.TestCase):
# different hash
prev['payloadhash'] = 'different hash'
with self.assertRaises(koji.GenericError):
nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % self.rpminfo
disp = f"{nvra}@{self.repo}"
with self.assertRaises(koji.GenericError) as ex:
kojihub.add_external_rpm(self.rpminfo, self.repo, strict=False)
self.assertEqual(f"hash changed for external rpm: {disp} (different hash -> fakehash)",
str(ex.exception))
self.assertEqual(len(self.inserts), 0)
self.nextval.assert_not_called()
@ -118,8 +128,11 @@ class TestAddExternalRPM(unittest.TestCase):
self.insert_execute.side_effect = FakeException('insert failed')
# call it (default is strict)
with self.assertRaises(koji.GenericError):
nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % self.rpminfo
disp = f"{nvra}@{self.repo}"
with self.assertRaises(koji.GenericError) as ex:
kojihub.add_external_rpm(self.rpminfo, self.repo)
self.assertEqual(f"external rpm already exists: {disp}", str(ex.exception))
self.assertEqual(len(self.inserts), 1)
self.nextval.assert_called_once()
@ -139,8 +152,12 @@ class TestAddExternalRPM(unittest.TestCase):
self.nextval.reset_mock()
self.get_rpm.side_effect = [None, prev]
prev['payloadhash'] = 'different hash'
with self.assertRaises(koji.GenericError):
nvra = "%(name)s-%(version)s-%(release)s.%(arch)s" % self.rpminfo
disp = f"{nvra}@{self.repo}"
with self.assertRaises(koji.GenericError) as ex:
kojihub.add_external_rpm(self.rpminfo, self.repo, strict=False)
self.assertEqual(f"hash changed for external rpm: {disp} (different hash -> fakehash)",
str(ex.exception))
self.assertEqual(len(self.inserts), 1)
self.nextval.assert_called_once()
@ -149,10 +166,9 @@ class TestAddExternalRPM(unittest.TestCase):
self.inserts[:] = []
self.nextval.reset_mock()
self.get_rpm.side_effect = [None, None]
with self.assertRaises(FakeException):
with self.assertRaises(FakeException) as ex:
kojihub.add_external_rpm(self.rpminfo, self.repo, strict=False)
self.assertEqual('insert failed', str(ex.exception))
self.assertEqual(len(self.inserts), 1)
self.nextval.assert_called_once()

View file

@ -36,32 +36,31 @@ class TestAddHost(unittest.TestCase):
self.context.session.assertPerm = mock.MagicMock()
self.context.opts = {'HostPrincipalFormat': '-%s-'}
self.exports = kojihub.RootExports()
self.verify_host_name = mock.patch('kojihub.verify_host_name').start()
self.verify_name_user = mock.patch('kojihub.verify_name_user').start()
self._dml = mock.patch('kojihub._dml').start()
self.get_host = mock.patch('kojihub.get_host').start()
self._singleValue = mock.patch('kojihub._singleValue').start()
self.get_user = mock.patch('kojihub.get_user').start()
def tearDown(self):
mock.patch.stopall()
@mock.patch('kojihub.verify_host_name')
@mock.patch('kojihub._dml')
@mock.patch('kojihub.get_host')
@mock.patch('kojihub._singleValue')
def test_add_host_exists(self, _singleValue, get_host, _dml, verify_host_name):
verify_host_name.return_value = None
get_host.return_value = {'id': 123}
def test_add_host_exists(self):
self.verify_host_name.return_value = None
self.get_host.return_value = {'id': 123}
with self.assertRaises(koji.GenericError):
self.exports.addHost('hostname', ['i386', 'x86_64'])
_dml.assert_not_called()
get_host.assert_called_once_with('hostname')
_singleValue.assert_not_called()
self._dml.assert_not_called()
self.get_host.assert_called_once_with('hostname')
self._singleValue.assert_not_called()
@mock.patch('kojihub.verify_host_name')
@mock.patch('kojihub._dml')
@mock.patch('kojihub.get_host')
@mock.patch('kojihub._singleValue')
def test_add_host_valid(self, _singleValue, get_host, _dml, verify_host_name):
verify_host_name.return_value = None
get_host.return_value = {}
_singleValue.side_effect = [333, 12]
def test_add_host_valid(self):
self.verify_host_name.return_value = None
self.get_host.return_value = {}
self._singleValue.side_effect = [333, 12]
self.context.session.createUser.return_value = 456
self.get_user.return_value = None
r = self.exports.addHost('hostname', ['i386', 'x86_64'])
self.assertEqual(r, 12)
@ -70,59 +69,48 @@ class TestAddHost(unittest.TestCase):
kojihub.get_host.assert_called_once_with('hostname')
self.context.session.createUser.assert_called_once_with(
'hostname', usertype=koji.USERTYPES['HOST'], krb_principal='-hostname-')
self.assertEqual(_singleValue.call_count, 2)
_singleValue.assert_has_calls([
self.assertEqual(self._singleValue.call_count, 2)
self._singleValue.assert_has_calls([
mock.call("SELECT id FROM channels WHERE name = 'default'"),
mock.call("SELECT nextval('host_id_seq')", strict=True)
])
self.assertEqual(_dml.call_count, 1)
_dml.assert_called_once_with("INSERT INTO host (id, user_id, name) "
"VALUES (%(hostID)i, %(userID)i, %(hostname)s)",
{'hostID': 12, 'userID': 456, 'hostname': 'hostname'})
self.assertEqual(self._dml.call_count, 1)
self._dml.assert_called_once_with("INSERT INTO host (id, user_id, name) "
"VALUES (%(hostID)i, %(userID)i, %(hostname)s)",
{'hostID': 12, 'userID': 456, 'hostname': 'hostname'})
@mock.patch('kojihub.verify_host_name')
@mock.patch('kojihub.get_user')
@mock.patch('kojihub._dml')
@mock.patch('kojihub.get_host')
@mock.patch('kojihub._singleValue')
def test_add_host_wrong_user(self, _singleValue, get_host, _dml, get_user, verify_host_name):
verify_host_name.return_value = None
get_user.return_value = {
def test_add_host_wrong_user(self):
self.verify_host_name.return_value = None
self.get_user.return_value = {
'id': 1,
'name': 'hostname',
'usertype': koji.USERTYPES['NORMAL']
}
get_host.return_value = {}
self.get_host.return_value = {}
with self.assertRaises(koji.GenericError):
self.exports.addHost('hostname', ['i386', 'x86_64'])
_dml.assert_not_called()
get_user.assert_called_once_with(userInfo={'name': 'hostname'})
get_host.assert_called_once_with('hostname')
_singleValue.assert_called_once()
self._dml.assert_not_called()
self.get_user.assert_called_once_with(userInfo={'name': 'hostname'})
self.get_host.assert_called_once_with('hostname')
self._singleValue.assert_called_once()
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
@mock.patch('kojihub.verify_host_name')
@mock.patch('kojihub.get_user')
@mock.patch('kojihub._dml')
@mock.patch('kojihub.get_host')
@mock.patch('kojihub._singleValue')
def test_add_host_wrong_user_forced(self, _singleValue, get_host, _dml, get_user,
verify_host_name):
verify_host_name.return_value = None
get_user.return_value = {
def test_add_host_wrong_user_forced(self):
self.verify_host_name.return_value = None
self.get_user.return_value = {
'id': 123,
'name': 'hostname',
'usertype': koji.USERTYPES['NORMAL']
}
get_host.return_value = {}
self.get_host.return_value = {}
self.exports.addHost('hostname', ['i386', 'x86_64'], force=True)
_dml.assert_called_once()
get_user.assert_called_once_with(userInfo={'name': 'hostname'})
get_host.assert_called_once_with('hostname')
_singleValue.assert_called()
self._dml.assert_called_once()
self.get_user.assert_called_once_with(userInfo={'name': 'hostname'})
self.get_host.assert_called_once_with('hostname')
self._singleValue.assert_called()
self.assertEqual(len(self.inserts), 2)
self.assertEqual(len(self.updates), 1)
update = self.updates[0]
@ -131,40 +119,50 @@ class TestAddHost(unittest.TestCase):
self.assertEqual(update.clauses, ['id = %(userID)i'])
self.assertEqual(update.data, {'usertype': koji.USERTYPES['HOST']})
@mock.patch('kojihub.verify_host_name')
@mock.patch('kojihub.get_user')
@mock.patch('kojihub._dml')
@mock.patch('kojihub.get_host')
@mock.patch('kojihub._singleValue')
def test_add_host_superwrong_user_forced(self, _singleValue, get_host, _dml, get_user,
verify_host_name):
verify_host_name.return_value = None
get_user.return_value = {
def test_add_host_superwrong_user_forced(self):
self.verify_host_name.return_value = None
self.get_user.return_value = {
'id': 123,
'name': 'hostname',
'usertype': koji.USERTYPES['GROUP']
}
get_host.return_value = {}
self.get_host.return_value = {}
with self.assertRaises(koji.GenericError):
self.exports.addHost('hostname', ['i386', 'x86_64'], force=True)
_dml.assert_not_called()
get_user.assert_called_once_with(userInfo={'name': 'hostname'})
get_host.assert_called_once_with('hostname')
_singleValue.assert_called()
self._dml.assert_not_called()
self.get_user.assert_called_once_with(userInfo={'name': 'hostname'})
self.get_host.assert_called_once_with('hostname')
self._singleValue.assert_called()
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
@mock.patch('kojihub.verify_host_name')
def test_add_host_wrong_format(self, verify_host_name):
def test_add_host_wrong_format(self):
# name is longer as expected
hostname = 'host-name+'
verify_host_name.side_effect = koji.GenericError
self.verify_host_name.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.addHost(hostname, ['i386', 'x86_64'], force=True)
# not except regex rules
verify_host_name.side_effect = koji.GenericError
self.verify_host_name.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.addHost(hostname, ['i386', 'x86_64'], force=True)
def test_add_host_krbprincipal_wrong_type(self):
krb_principal = ['test-krb']
self.verify_host_name.return_value = None
self.get_host.return_value = {}
self._singleValue.side_effect = [333, 12]
self.verify_name_user.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.addHost('hostname', ['i386', 'x86_64'], krb_principal=krb_principal)
self.context.session.assertPerm.assert_called_once_with('host')
kojihub.get_host.assert_called_once_with('hostname')
self.context.session.createUser.assert_not_called()
self.assertEqual(self._singleValue.call_count, 1)
self._singleValue.assert_called_once_with("SELECT id FROM channels WHERE name = 'default'")
self.verify_host_name.assert_called_once_with('hostname')
self.verify_name_user.assert_called_once_with(krb=krb_principal)

View file

@ -0,0 +1,42 @@
import mock
import unittest
import koji
import kojihub
import copy
class TestAddUserKrbPrincipal(unittest.TestCase):
def setUp(self):
self.get_user = mock.patch('kojihub.get_user').start()
self.verify_name_user = mock.patch('kojihub.verify_name_user').start()
self.get_user_by_krb_principal = mock.patch('kojihub.get_user_by_krb_principal').start()
self.username = 'testuser'
self.krbprincipal = '%s@TEST.COM' % self.username
self.userinfo = {'id': 1, 'name': self.username}
def tearDown(self):
mock.patch.stopall()
def test_non_exist_user(self):
self.get_user.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub.RootExports().addUserKrbPrincipal(self.username, self.krbprincipal)
def test_wrong_krbprincipal_format(self):
krbprincipal = 'test-krbprincipal+'
self.get_user.return_value = self.userinfo
self.verify_name_user.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub.RootExports().addUserKrbPrincipal(self.username, krbprincipal)
def test_existing_krb(self):
userinfo = copy.deepcopy(self.userinfo)
userinfo['krb_principal'] = self.krbprincipal
self.get_user.return_value = self.userinfo
self.verify_name_user.return_value = None
self.get_user_by_krb_principal.return_value = userinfo
with self.assertRaises(koji.GenericError) as ex:
kojihub.RootExports().addUserKrbPrincipal(self.username, self.krbprincipal)
self.assertEqual('user with this Kerberos principal already exists: %s'
% self.krbprincipal, str(ex.exception))

View file

@ -0,0 +1,40 @@
import unittest
import koji
import kojihub
import mock
class TestBuild(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertLogin = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.get_channel = mock.patch('kojihub.get_channel').start()
self.make_task = mock.patch('kojihub.make_task').start()
self.src = 'test-src'
self.target = 'test-target'
def tearDown(self):
mock.patch.stopall()
def test_src_wrong_type(self):
src = ['test-priority']
with self.assertRaises(koji.GenericError) as cm:
self.exports.build(src, self.target)
self.assertEqual(f"Invalid type for value '{src}': {type(src)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.build(self.src, self.target, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_channel_not_str(self):
priority = 10
self.get_channel.return_value = {'comment': None, 'description': None, 'enabled': True,
'id': 2, 'name': 'maven'}
self.make_task.return_value = 123
self.exports.build(self.src, self.target, priority=priority, channel=2)

View file

@ -0,0 +1,69 @@
import unittest
import koji
import kojihub
import mock
class TestBuildImage(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertPerm = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.make_task = mock.patch('kojihub.make_task').start()
self.mock_parse_arches = mock.patch('koji.parse_arches').start()
self.name = 'image-name'
self.version = 'test-version'
self.arch = 'x86_64'
self.target = 'test-target'
self.ksfile = 'test-ksfile'
self.image_type = 'livecd'
def tearDown(self):
mock.patch.stopall()
def test_img_type_not_supported(self):
image_type = 'test-type'
with self.assertRaises(koji.GenericError) as cm:
self.exports.buildImage(self.name, self.version, self.arch, self.target,
self.ksfile, image_type)
self.assertEqual(f"Unrecognized image type: {image_type}", str(cm.exception))
def test_name_wrong_type(self):
name = ['test-name']
with self.assertRaises(koji.GenericError) as cm:
self.exports.buildImage(name, self.version, self.arch, self.target, self.ksfile,
self.image_type)
self.assertEqual(f"Invalid type for value '{name}': {type(name)}", str(cm.exception))
def test_version_wrong_type(self):
version = ['test-version']
with self.assertRaises(koji.GenericError) as cm:
self.exports.buildImage(self.name, version, self.arch, self.target, self.ksfile,
self.image_type)
self.assertEqual(f"Invalid type for value '{version}': {type(version)}", str(cm.exception))
def test_ksfile_wrong_type(self):
ksfile = ['test-ksfile']
with self.assertRaises(koji.GenericError) as cm:
self.exports.buildImage(self.name, self.version, self.arch, self.target, ksfile,
self.image_type)
self.assertEqual(f"Invalid type for value '{ksfile}': {type(ksfile)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
image_type = 'livemedia'
self.context.session.assertPerm.side_effect = None
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.ActionNotAllowed) as cm:
self.exports.buildImage(self.name, self.version, self.arch, self.target, self.ksfile,
image_type, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_valid(self):
priority = 10
self.context.session.assertPerm.side_effect = None
self.make_task.return_value = 123
self.exports.buildImage(self.name, self.version, self.arch, self.target, self.ksfile,
self.image_type, priority=priority)

View file

@ -0,0 +1,33 @@
import unittest
import koji
import kojihub
import mock
class TestBuildImageIndirection(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertPerm = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
def tearDown(self):
mock.patch.stopall()
def test_priority_without_admin(self):
priority = -10
self.context.session.assertPerm.side_effect = None
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.ActionNotAllowed) as cm:
self.exports.buildImageIndirection(priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_opts_without_expected_keys(self):
priority = 10
opts = {}
self.context.session.assertPerm.side_effect = None
with self.assertRaises(koji.ActionNotAllowed) as cm:
self.exports.buildImageIndirection(opts=opts, priority=priority)
self.assertEqual("Non-scratch builds must provide url for the indirection template",
str(cm.exception))

View file

@ -0,0 +1,59 @@
import unittest
import koji
import kojihub
import mock
class TestBuildImageOz(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertPerm = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.parse_arches = mock.patch('koji.parse_arches').start()
self.name = 'image-name'
self.version = 'test-version'
self.arches = ['x86_64', 'i386']
self.target = 'test-target'
self.inst_tree = 'test-tree'
def tearDown(self):
mock.patch.stopall()
def test_name_wrong_type(self):
name = ['image-name']
with self.assertRaises(koji.ParameterError) as cm:
self.exports.buildImageOz(name, self.version, self.arches, self.target, self.inst_tree)
self.assertEqual(f"Invalid type for value '{name}': {type(name)}", str(cm.exception))
def test_inst_tree_wrong_type(self):
inst_tree = ['test-tree']
with self.assertRaises(koji.ParameterError) as cm:
self.exports.buildImageOz(self.name, self.version, self.arches, self.target, inst_tree)
self.assertEqual(f"Invalid type for value '{inst_tree}': {type(inst_tree)}",
str(cm.exception))
def test_version_wrong_type(self):
version = ['test-version']
with self.assertRaises(koji.ParameterError) as cm:
self.exports.buildImageOz(self.name, version, self.arches, self.target, self.inst_tree)
self.assertEqual(f"Invalid type for value '{version}': {type(version)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
self.context.session.assertPerm.side_effect = None
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.ActionNotAllowed) as cm:
self.exports.buildImageOz(self.name, self.version, self.arches, self.target,
self.inst_tree, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_opts_without_expected_keys(self):
priority = 10
opts = {}
self.context.session.assertPerm.side_effect = None
with self.assertRaises(koji.ActionNotAllowed) as cm:
self.exports.buildImageOz(self.name, self.version, self.arches, self.target,
self.inst_tree, opts=opts, priority=priority)
self.assertEqual("Non-scratch builds must provide ksurl", str(cm.exception))

View file

@ -10,6 +10,7 @@ from koji import GenericError
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestCGImporter(unittest.TestCase):
TMP_PATH = os.path.join(os.path.dirname(__file__), 'tmptest')
@ -36,7 +37,8 @@ class TestCGImporter(unittest.TestCase):
metadata = 42
with self.assertRaises(GenericError) as ex:
x.get_metadata(metadata, '')
self.assertEqual('Invalid type for metadata value: %s' % type(metadata), str(ex.exception))
self.assertEqual(f"Invalid type for value '{metadata}': {type(metadata)}",
str(ex.exception))
def test_get_metadata_is_none(self):
x = kojihub.CG_Importer()
@ -158,7 +160,7 @@ class TestCGImporter(unittest.TestCase):
'start_time': None, 'start_ts': None,
'completion_time': None, 'completion_ts': None,
'source': 'https://example.com', 'extra': {}
}
}
new_build_id.return_value = 43
x.get_build()
assert x.buildinfo
@ -187,7 +189,7 @@ class TestCGImporter(unittest.TestCase):
get_metadata.return_value = metadata
with self.assertRaises(koji.GenericError) as ex:
x.do_import(metadata, '/test/dir')
self.assertEqual('No such metadata version: %s' % metadata['metadata_version'],
self.assertEqual(f"No such metadata version: {metadata['metadata_version']}",
str(ex.exception))
def test_match_componemt_wrong_component(self):
@ -195,7 +197,7 @@ class TestCGImporter(unittest.TestCase):
components = [{'type': 'type'}]
with self.assertRaises(koji.GenericError) as ex:
x.match_components(components)
self.assertEqual('No such component type: %s' % components[0]['type'], str(ex.exception))
self.assertEqual(f"No such component type: {components[0]['type']}", str(ex.exception))
class TestMatchKojiFile(unittest.TestCase):
@ -203,23 +205,23 @@ class TestMatchKojiFile(unittest.TestCase):
def setUp(self):
self.importer = kojihub.CG_Importer()
self.archive1 = {
'id': 99,
'build_id': 42,
'checksum': 'e1f95555eae04b8e1ebdc5555c5555f0',
'checksum_type': 0,
'filename': 'foo-bar-3.0.jar',
'size': 42710,
}
'id': 99,
'build_id': 42,
'checksum': 'e1f95555eae04b8e1ebdc5555c5555f0',
'checksum_type': 0,
'filename': 'foo-bar-3.0.jar',
'size': 42710,
}
self.build1 = {
'id': 79218,
'nvr': 'foo-3.0-1',
}
'id': 79218,
'nvr': 'foo-3.0-1',
}
self.comp1 = {
'type': 'kojifile',
'archive_id': self.archive1['id'],
'nvr': self.build1['nvr'],
'filename': self.archive1['filename'],
}
'type': 'kojifile',
'archive_id': self.archive1['id'],
'nvr': self.build1['nvr'],
'filename': self.archive1['filename'],
}
self.get_archive = mock.patch('kojihub.get_archive').start()
self.get_build = mock.patch('kojihub.get_build').start()
@ -270,7 +272,6 @@ class TestCGReservation(unittest.TestCase):
self.updates.append(update)
return update
def setUp(self):
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
side_effect=self.getInsert).start()
@ -298,8 +299,8 @@ class TestCGReservation(unittest.TestCase):
new_build.return_value = 654
cg = 'content_generator_name'
self.mock_cursor.fetchone.side_effect = [
[333], # get pkg_id
[1234], # get nextval pkg_id
[333], # get pkg_id
[1234], # get nextval pkg_id
]
self.mock_cursor.fetchall.side_effect = [
[[]],

View file

@ -0,0 +1,40 @@
import unittest
import koji
import kojihub
import mock
class TestChainBuild(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertLogin = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.get_channel = mock.patch('kojihub.get_channel').start()
self.make_task = mock.patch('kojihub.make_task').start()
self.srcs = ['pkg1']
self.target = 'test-target'
def tearDown(self):
mock.patch.stopall()
def test_srcs_wrong_type(self):
srcs = 'pkg'
with self.assertRaises(koji.GenericError) as cm:
self.exports.chainBuild(srcs, self.target)
self.assertEqual(f"Invalid type for value '{srcs}': {type(srcs)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.chainBuild(self.srcs, self.target, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_channel_not_str(self):
priority = 10
self.get_channel.return_value = {'comment': None, 'description': None, 'enabled': True,
'id': 2, 'name': 'maven'}
self.make_task.return_value = 123
self.exports.chainBuild(self.srcs, self.target, priority=priority, channel=2)

View file

@ -0,0 +1,48 @@
import unittest
import koji
import kojihub
import mock
class TestChainMaven(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertLogin = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.get_channel = mock.patch('kojihub.get_channel').start()
self.make_task = mock.patch('kojihub.make_task').start()
self.builds = ['build1', 'build2', 'build3']
self.target = 'test-target'
def tearDown(self):
mock.patch.stopall()
def test_maven_not_supported(self):
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.chainMaven(self.builds, self.target)
self.assertEqual("Maven support not enabled", str(cm.exception))
def test_builds_wrong_type(self):
builds = 'test-builds'
self.context.opts.get.return_value = True
with self.assertRaises(koji.ParameterError) as cm:
self.exports.chainMaven(builds, self.target)
self.assertEqual(f"Invalid type for value '{builds}': {type(builds)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
self.context.opts.get.return_value = True
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.chainMaven(self.builds, self.target, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_channel_not_str(self):
self.context.opts.get.return_value = True
self.make_task.return_value = 123
self.get_channel.return_value = {'comment': None, 'description': None, 'enabled': True,
'id': 2, 'name': 'maven'}
self.exports.chainMaven(self.builds, self.target, channel=2, priority=10)

View file

@ -4,57 +4,168 @@ import mock
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestCreateNotification(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.get_build_notifications = mock.patch('kojihub.get_build_notifications').start()
self.get_tag_id = mock.patch('kojihub.get_tag_id').start()
self.get_package_id = mock.patch('kojihub.get_package_id').start()
self.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.context = mock.patch('kojihub.context').start()
self.exports.getUser = mock.MagicMock()
self.exports.hasPerm = mock.MagicMock()
self.cursor = mock.MagicMock()
self.user_id = 1
self.package_id = 345
self.tag_id = 345
def tearDown(self):
mock.patch.stopall()
def test_createNotification(self):
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = {'id': 2, 'name': 'username'}
self.exports.hasPerm.return_value = True
self.get_package_id.return_value = self.package_id
self.get_tag_id.return_value = self.tag_id
self.get_build_notifications.return_value = []
r = self.exports.createNotification(
self.user_id, self.package_id, self.tag_id, success_only)
self.assertEqual(r, None)
self.exports.getLoggedInUser.assert_called_once()
self.exports.getUser.asssert_called_once_with(self.user_id)
self.exports.hasPerm.asssert_called_once_with('admin')
self.get_package_id.assert_called_once_with(self.package_id, strict=True)
self.get_tag_id.assert_called_once_with(self.tag_id, strict=True)
self.get_build_notifications.assert_called_once_with(2)
self.assertEqual(len(self.inserts), 1)
insert = self.inserts[0]
self.assertEqual(insert.table, 'build_notifications')
self.assertEqual(insert.data, {
'package_id': self.package_id,
'user_id': 2,
'tag_id': self.tag_id,
'success_only': success_only,
'email': 'username@test.domain.com',
})
self.assertEqual(insert.rawdata, {})
def test_createNotification_unauthentized(self):
success_only = True
self.exports.getLoggedInUser.return_value = None
def test_non_exist_user(self):
user_id = 999
package_id = 555
tag_id = 111
success_only = False
logged_user = {'authtype': 2,
'id': 1,
'krb_principal': None,
'krb_principals': [],
'name': 'kojiadmin',
'status': 0,
'usertype': 0}
self.cursor.fetchone.return_value = None
self.context.cnx.cursor.return_value = self.cursor
self.exports.getLoggedInUser.return_value = logged_user
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual('No such user ID: %s' % user_id, str(cm.exception))
self.exports.createNotification(
self.user_id, self.package_id, self.tag_id, success_only)
self.assertEqual('Not logged-in', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
class TestCreateNotificationBlock(unittest.TestCase):
def test_createNotification_invalid_user(self):
user_id = 2
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = None
def setUp(self):
self.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.context = mock.patch('kojihub.context').start()
self.cursor = mock.MagicMock()
def test_non_exist_user(self):
user_id = 999
package_id = 555
tag_id = 111
logged_user = {'authtype': 2,
'id': 1,
'krb_principal': None,
'krb_principals': [],
'name': 'kojiadmin',
'status': 0,
'usertype': 0}
self.cursor.fetchone.return_value = None
self.context.cnx.cursor.return_value = self.cursor
self.exports.getLoggedInUser.return_value = logged_user
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual('No such user ID: %s' % user_id, str(cm.exception))
self.exports.createNotification(user_id, self.package_id, self.tag_id, success_only)
self.assertEqual(f'No such user ID: {user_id}', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
def test_createNotification_no_perm(self):
user_id = 2
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'b'}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotification(user_id, self.package_id, self.tag_id, success_only)
self.assertEqual('user a cannot create notifications for user b', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
def test_createNotification_invalid_pkg(self):
user_id = 2
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
self.get_package_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotification(user_id, self.package_id, self.tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
def test_createNotification_invalid_tag(self):
user_id = 2
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
self.get_package_id.return_value = self.package_id
self.get_tag_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotification(user_id, self.package_id, self.tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
def test_createNotification_exists(self):
user_id = 2
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
self.get_package_id.return_value = self.package_id
self.get_tag_id.return_value = self.tag_id
self.get_build_notifications.return_value = [{
'package_id': self.package_id,
'tag_id': self.tag_id,
'success_only': success_only,
}]
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotification(user_id, self.package_id, self.tag_id, success_only)
self.assertEqual('notification already exists', str(cm.exception))
self.assertEqual(len(self.inserts), 0)

View file

@ -0,0 +1,161 @@
import unittest
import mock
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestCreateNotificationBlock(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.get_tag_id = mock.patch('kojihub.get_tag_id').start()
self.get_package_id = mock.patch('kojihub.get_package_id').start()
self.get_build_notification_blocks = mock.patch(
'kojihub.get_build_notification_blocks').start()
self.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.exports.getUser = mock.MagicMock()
self.exports.hasPerm = mock.MagicMock()
self.cursor = mock.MagicMock()
self.user_id = 1
self.package_id = 555
self.tag_id = 111
def tearDown(self):
mock.patch.stopall()
def test_createNotificationBlock(self):
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = {'id': 2, 'name': 'username'}
self.exports.hasPerm.return_value = True
self.get_package_id.return_value = self.package_id
self.get_tag_id.return_value = self.tag_id
self.get_build_notification_blocks.return_value = []
r = self.exports.createNotificationBlock(self.user_id, self.package_id, self.tag_id)
self.assertEqual(r, None)
self.exports.getLoggedInUser.assert_called_once()
self.exports.getUser.asssert_called_once_with(self.user_id)
self.exports.hasPerm.asssert_called_once_with('admin')
self.get_package_id.assert_called_once_with(self.package_id, strict=True)
self.get_tag_id.assert_called_once_with(self.tag_id, strict=True)
self.get_build_notification_blocks.assert_called_once_with(2)
self.assertEqual(len(self.inserts), 1)
insert = self.inserts[0]
self.assertEqual(insert.table, 'build_notifications_block')
self.assertEqual(insert.data, {
'package_id': self.package_id,
'user_id': 2,
'tag_id': self.tag_id,
})
self.assertEqual(insert.rawdata, {})
def test_createNotificationBlock_unauthentized(self):
self.exports.getLoggedInUser.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotificationBlock(self.user_id, self.package_id, self.tag_id)
self.assertEqual('Not logged-in', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
def test_createNotificationBlock_invalid_user(self):
user_id = 2
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotificationBlock(user_id, self.package_id, self.tag_id)
self.assertEqual(f'No such user ID: {user_id}', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
def test_createNotificationBlock_no_perm(self):
user_id = 2
self.exports.getLoggedInUser.return_value = {'id': 1, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'b'}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotificationBlock(user_id, self.package_id, self.tag_id)
self.assertEqual('user a cannot create notification blocks for user b', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
def test_createNotificationBlock_invalid_pkg(self):
user_id = 2
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
self.get_package_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotificationBlock(user_id, self.package_id, self.tag_id)
self.assertEqual(len(self.inserts), 0)
def test_createNotificationBlock_invalid_tag(self):
user_id = 2
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
self.get_package_id.return_value = self.package_id
self.get_tag_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotificationBlock(user_id, self.package_id, self.tag_id)
self.assertEqual(len(self.inserts), 0)
def test_createNotificationBlock_exists(self):
user_id = 2
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
self.get_package_id.return_value = self.package_id
self.get_tag_id.return_value = self.tag_id
self.get_build_notification_blocks.return_value = [{
'package_id': self.package_id,
'tag_id': self.tag_id,
}]
with self.assertRaises(koji.GenericError) as cm:
self.exports.createNotificationBlock(user_id, self.package_id, self.tag_id)
self.assertEqual('notification already exists', str(cm.exception))
self.assertEqual(len(self.inserts), 0)

View file

@ -24,8 +24,9 @@ class TestCreateTag(unittest.TestCase):
self._dml = mock.patch('kojihub._dml').start()
self.get_tag = mock.patch('kojihub.get_tag').start()
self.get_tag_id = mock.patch('kojihub.get_tag_id').start()
self.get_perm_id = mock.patch('kojihub.get_perm_id').start()
self.verify_name_internal = mock.patch('kojihub.verify_name_internal').start()
self.writeInheritanceData = mock.patch('kojihub.writeInheritanceData').start()
self.writeInheritanceData = mock.patch('kojihub._writeInheritanceData').start()
self.context = mock.patch('kojihub.context').start()
# It seems MagicMock will not automatically handle attributes that
# start with "assert"
@ -42,12 +43,13 @@ class TestCreateTag(unittest.TestCase):
kojihub.create_tag('duptag')
def test_simple_create(self):
self.get_tag.return_value = None
self.get_tag.side_effect = [None, {'id': 1, 'name': 'parent-tag'}]
self.get_tag_id.return_value = 99
self.verify_name_internal.return_value = None
self.context.event_id = 42
self.context.session.user_id = 23
kojihub.create_tag('newtag')
self.writeInheritanceData.return_value = None
kojihub.create_tag('newtag', parent='parent-tag')
# check the insert
self.assertEqual(len(self.inserts), 1)
@ -97,3 +99,21 @@ class TestCreateTag(unittest.TestCase):
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub.create_tag(tag_name)
def test_tag_non_exist_parent(self):
parent_tag = 'parent-tag'
self.verify_name_internal.return_value = None
self.get_tag.side_effect = [None, None]
with self.assertRaises(koji.GenericError) as ex:
kojihub.create_tag('new-tag', parent=parent_tag)
self.assertEqual("Parent tag '%s' could not be found" % parent_tag, str(ex.exception))
def test_tag_not_maven_support(self):
self.verify_name_internal.return_value = None
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as ex:
kojihub.create_tag('new-tag', maven_support=True)
self.assertEqual("Maven support not enabled", str(ex.exception))
with self.assertRaises(koji.GenericError) as ex:
kojihub.create_tag('new-tag', maven_include_all=True)
self.assertEqual("Maven support not enabled", str(ex.exception))

View file

@ -38,19 +38,27 @@ class TestCreateUser(unittest.TestCase):
self.exports.createUser(user_name)
def test_create_user_exists(self):
expected = 'user already exists: %s' % self.user_name
self.verify_name_user.return_value = None
self.get_user.return_value = self.user_info
with self.assertRaises(koji.GenericError) as cm:
self.exports.createUser(self.user_name)
self.assertEqual(expected, str(cm.exception))
self.assertEqual(f"user already exists: {self.user_name}", str(cm.exception))
def test_create_user_exists_krb(self):
krb_principal = 'test_user@fedora.org'
expected = 'user with this Kerberos principal already exists: %s' % krb_principal
expected = f"user with this Kerberos principal already exists: {krb_principal}"
self.verify_name_user.return_value = None
self.get_user.return_value = None
self.get_user_by_krb_principal.return_value = self.user_info_krb
with self.assertRaises(koji.GenericError) as cm:
self.exports.createUser(self.user_name, krb_principal=krb_principal)
self.assertEqual(expected, str(cm.exception))
def test_create_user_wrong_type_status(self):
status = 'test-status'
self.verify_name_user.return_value = None
self.get_user.return_value = None
self.get_user_by_krb_principal.return_value = self.user_info_krb
with self.assertRaises(koji.ParameterError) as cm:
self.exports.createUser(self.user_name, status=status)
self.assertEqual(f"Invalid type for value '{status}': {type(status)}", str(cm.exception))

View file

@ -0,0 +1,103 @@
import mock
import unittest
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestDeleteNotifications(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.exports.hasPerm = mock.MagicMock()
self.exports.getBuildNotification = mock.MagicMock()
self.user_id = 752
self.n_id = 543
def tearDown(self):
mock.patch.stopall()
def test_deleteNotification(self):
self.exports.getBuildNotification.return_value = {'user_id': self.user_id}
self.exports.deleteNotification(self.n_id)
self.exports.getBuildNotification.assert_called_once_with(self.n_id, strict=True)
self.exports.getLoggedInUser.assert_called_once_with()
self._dml.assert_called_once()
def test_deleteNotification_missing(self):
self.exports.getBuildNotification.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.deleteNotification(self.n_id)
self.exports.getBuildNotification.assert_called_once_with(self.n_id, strict=True)
def test_deleteNotification_not_logged(self):
self.exports.getBuildNotification.return_value = {'user_id': self.user_id}
self.exports.getLoggedInUser.return_value = None
# self.set_queries = ([
# [{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
# ])
with self.assertRaises(koji.GenericError) as cm:
self.exports.deleteNotification(self.n_id)
self.assertEqual('Not logged-in', str(cm.exception))
self.exports.getBuildNotification.assert_called_once_with(self.n_id, strict=True)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
self.assertEqual(len(self.queries), 0)
def test_deleteNotification_no_perm(self):
self.exports.getBuildNotification.return_value = {'user_id': self.user_id}
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.deleteNotification(self.n_id)
self.assertEqual(f'user 1 cannot delete notifications for user {self.user_id}',
str(cm.exception))
self.exports.getBuildNotification.assert_called_once_with(self.n_id, strict=True)
self._dml.assert_not_called()

View file

@ -0,0 +1,104 @@
import mock
import unittest
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestDeleteNotificationsBlocks(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.get_user = mock.patch('kojihub.get_user').start()
self._dml = mock.patch('kojihub._dml').start()
self.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.exports.hasPerm = mock.MagicMock()
self.exports.getBuildNotificationBlock = mock.MagicMock()
self.user_id = 752
self.n_id = 543
def tearDown(self):
mock.patch.stopall()
def test_deleteNotificationBlock(self):
self.exports.getBuildNotificationBlock.return_value = {'user_id': self.user_id}
self.exports.deleteNotificationBlock(self.n_id)
self.exports.getBuildNotificationBlock.assert_called_once_with(self.n_id, strict=True)
self.exports.getLoggedInUser.assert_called_once_with()
self._dml.assert_called_once()
def test_deleteNotificationBlock_missing(self):
self.exports.getBuildNotificationBlock.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.deleteNotificationBlock(self.n_id)
self.exports.getBuildNotificationBlock.assert_called_once_with(self.n_id, strict=True)
def test_deleteNotificationBlock_not_logged(self):
self.exports.getBuildNotificationBlock.return_value = {'user_id': self.user_id}
self.exports.getLoggedInUser.return_value = None
# self.set_queries = ([
# [{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
# ])
with self.assertRaises(koji.GenericError) as cm:
self.exports.deleteNotificationBlock(self.n_id)
self.assertEqual('Not logged-in', str(cm.exception))
self.exports.getBuildNotificationBlock.assert_called_once_with(self.n_id, strict=True)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
self.assertEqual(len(self.queries), 0)
def test_deleteNotificationBlock_no_perm2(self):
self.exports.getBuildNotificationBlock.return_value = {'user_id': self.user_id}
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.deleteNotificationBlock(self.n_id)
self.assertEqual(f'user 1 cannot delete notification blocks for user {self.user_id}',
str(cm.exception))
self.exports.getBuildNotificationBlock.assert_called_once_with(self.n_id, strict=True)
self._dml.assert_not_called()

View file

@ -28,7 +28,13 @@ class TestDisableChannel(unittest.TestCase):
self.get_channel.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.disableChannel(self.channelname)
self.assertEqual("No such channel: %s" % self.channelname, str(cm.exception))
self.assertEqual(f"No such channel: {self.channelname}", str(cm.exception))
def test_wrong_type_channel(self):
comment = ['test-comment']
with self.assertRaises(koji.GenericError) as cm:
self.exports.disableChannel(self.channelname, comment=comment)
self.assertEqual(f"Invalid type for value '{comment}': {type(comment)}", str(cm.exception))
def test_valid(self):
self.get_channel.return_value = {'comment': None, 'description': None,

View file

@ -31,6 +31,7 @@ class TestDistRepoInit(unittest.TestCase):
self.get_event = mock.patch('kojihub.get_event').start()
self.nextval = mock.patch('kojihub.nextval').start()
self.copyfile = mock.patch('shutil.copyfile').start()
self.lookup_name = mock.patch('kojihub.lookup_name').start()
self.get_tag.return_value = {'id': 42, 'name': 'tag'}
self.get_event.return_value = 12345
@ -70,6 +71,34 @@ class TestDistRepoInit(unittest.TestCase):
self.copyfile.assert_called_once()
def test_simple_dist_repo_init_wrong_type_keys(self):
keys = 'key1 key2'
with self.assertRaises(koji.ParameterError) as cm:
kojihub.dist_repo_init('tag', keys, {'arch': ['x86_64']})
self.assertEqual(f"Invalid type for value '{keys}': {type(keys)}", str(cm.exception))
self.InsertProcessor.assert_not_called()
def test_simple_dist_repo_init_wrong_type_task_opts(self):
task_opts = 'opts'
with self.assertRaises(koji.ParameterError) as cm:
kojihub.dist_repo_init('tag', ['key'], task_opts)
self.assertEqual(f"Invalid type for value '{task_opts}': {type(task_opts)}",
str(cm.exception))
self.InsertProcessor.assert_not_called()
def test_simple_dist_repo_init_wrong_type_event(self):
event = 'test-event'
with self.assertRaises(koji.ParameterError) as cm:
kojihub.dist_repo_init('tag', ['key'], {'arch': ['x86_64'], 'event': event})
self.assertEqual(f"Invalid type for value '{event}': {type(event)}", str(cm.exception))
self.InsertProcessor.assert_not_called()
def test_simple_dist_repo_init_wrong_type_volume(self):
self.lookup_name.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub.dist_repo_init('tag', ['key'], {'arch': ['x86_64'], 'volume': 'test-volume'})
self.InsertProcessor.assert_not_called()
class TestDistRepo(unittest.TestCase):
@ -206,7 +235,7 @@ class TestDistRepoMove(unittest.TestCase):
path = os.path.join(repodir, relpath)
basename = os.path.basename(path)
if not os.path.exists(path):
raise Exception("Missing file: %s" % path)
raise Exception(f"Missing file: {path}")
data = open(path, 'rt', encoding='utf-8').read()
data.strip()
self.assertEqual(data, basename)

View file

@ -0,0 +1,36 @@
import mock
import unittest
import koji
import kojihub
class TestDownloadTaskOutput(unittest.TestCase):
def setUp(self):
self.exports = kojihub.RootExports()
self.exports.getVolume = mock.MagicMock()
self.task_id = 1
self.filename = 'test-file'
self.volumename = 'test-volume'
def tearDown(self):
mock.patch.stopall()
def test_size_wrong_type(self):
size = 'test-size'
with self.assertRaises(koji.ParameterError) as cm:
self.exports.downloadTaskOutput(self.task_id, self.filename, size=size)
self.assertEqual(f"Invalid type for value '{size}': {type(size)}", str(cm.exception))
def test_volume_non_exist_wrong_type(self):
self.exports.getVolume.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.downloadTaskOutput(self.task_id, self.filename, volume=self.volumename)
def test_filename_wrong_format(self):
filename = '../test-file'
volumeinfo = {'id': 1, 'name': self.volumename}
self.exports.getVolume.return_value = volumeinfo
with self.assertRaises(koji.GenericError) as cm:
self.exports.downloadTaskOutput(self.task_id, filename, volume=self.volumename)
self.assertEqual(f"Invalid file name: {filename}", str(cm.exception))

View file

@ -34,32 +34,28 @@ class TestEditChannel(unittest.TestCase):
self.exports = kojihub.RootExports()
self.channel_name = 'test-channel'
self.channel_name_new = 'test-channel-2'
self.channel_info = {'id': 123, 'name': self.channel_name, 'description': 'description',
'comment': 'comment'}
self.get_channel = mock.patch('kojihub.get_channel').start()
self.verify_name_internal = mock.patch('kojihub.verify_name_internal').start()
def tearDown(self):
mock.patch.stopall()
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub.get_channel')
def test_edit_channel_missing(self, get_channel, verify_name_internal):
def test_edit_channel_missing(self):
expected = 'Invalid type for channelInfo: %s' % self.channel_name
get_channel.side_effect = koji.GenericError(expected)
self.get_channel.side_effect = koji.GenericError(expected)
with self.assertRaises(koji.GenericError) as ex:
self.exports.editChannel(self.channel_name, name=self.channel_name_new)
get_channel.assert_called_once_with(self.channel_name, strict=True)
self.get_channel.assert_called_once_with(self.channel_name, strict=True)
self.assertEqual(self.inserts, [])
self.assertEqual(self.updates, [])
self.assertEqual(expected, str(ex.exception))
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub.get_channel')
def test_edit_channel_already_exists(self, get_channel, verify_name_internal):
verify_name_internal.return_value = None
get_channel.side_effect = [
{
'id': 123,
'name': self.channel_name,
'description': 'description',
},
def test_edit_channel_already_exists(self):
self.verify_name_internal.return_value = None
self.get_channel.side_effect = [
self.channel_info,
{
'id': 124,
'name': self.channel_name_new,
@ -70,29 +66,22 @@ class TestEditChannel(unittest.TestCase):
self.exports.editChannel(self.channel_name, name=self.channel_name_new)
expected_calls = [mock.call(self.channel_name, strict=True),
mock.call(self.channel_name_new, strict=False)]
get_channel.assert_has_calls(expected_calls)
self.get_channel.assert_has_calls(expected_calls)
self.assertEqual(self.inserts, [])
self.assertEqual(self.updates, [])
self.assertEqual('channel %s already exists (id=124)' % self.channel_name_new,
self.assertEqual(f'channel {self.channel_name_new} already exists (id=124)',
str(ex.exception))
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub.get_channel')
def test_edit_channel_valid(self, get_channel, verify_name_internal):
verify_name_internal.return_value = None
kojihub.get_channel.side_effect = [{
'id': 123,
'name': self.channel_name,
'description': 'description',
},
{}]
def test_edit_channel_valid(self):
self.verify_name_internal.return_value = None
kojihub.get_channel.side_effect = [self.channel_info, {}]
r = self.exports.editChannel(self.channel_name, name=self.channel_name_new,
description='description_new')
self.assertTrue(r)
expected_calls = [mock.call(self.channel_name, strict=True),
mock.call(self.channel_name_new, strict=False)]
get_channel.assert_has_calls(expected_calls)
self.get_channel.assert_has_calls(expected_calls)
self.assertEqual(len(self.updates), 1)
values = {'channelID': 123}
@ -103,21 +92,56 @@ class TestEditChannel(unittest.TestCase):
self.assertEqual(update.values, values)
self.assertEqual(update.clauses, clauses)
@mock.patch('kojihub.verify_name_internal')
@mock.patch('kojihub.get_channel')
def test_edit_channel_wrong_format(self, get_channel, verify_name_internal):
def test_edit_channel_wrong_name(self):
channel_name_new = 'test-channel+'
get_channel.return_value = {'id': 123,
'name': self.channel_name,
'description': 'description',
}
self.get_channel.return_value = self.channel_info
# name is longer as expected
verify_name_internal.side_effect = koji.GenericError
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.editChannel(self.channel_name, name=channel_name_new)
# not except regex rules
verify_name_internal.side_effect = koji.GenericError
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.editChannel(self.channel_name, name=channel_name_new)
def test_edit_channel_no_change(self):
self.verify_name_internal.return_value = None
kojihub.get_channel.return_value = self.channel_info
r = self.exports.editChannel(self.channel_name, description='description')
self.assertFalse(r)
self.assertEqual(self.updates, [])
self.get_channel.assert_called_once_with(self.channel_name, strict=True)
self.verify_name_internal.assert_not_called()
def test_edit_channel_wrong_format_new_name(self):
channel_name_new = 13568
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.editChannel(self.channel_name, name=channel_name_new)
self.assertEqual(self.updates, [])
self.get_channel.assert_called_once_with(self.channel_name, strict=True)
self.verify_name_internal.assert_called_once_with(channel_name_new)
def test_edit_channel_wrong_format_description(self):
description = ['description']
self.get_channel.return_value = self.channel_info
with self.assertRaises(koji.ParameterError) as ex:
self.exports.editChannel(self.channel_name, description=description)
self.assertEqual(self.updates, [])
self.assertEqual(f"Invalid type for value '{description}': {type(description)}",
str(ex.exception))
self.get_channel.assert_called_once_with(self.channel_name, strict=True)
self.verify_name_internal.assert_not_called()
def test_edit_channel_wrong_format_comment(self):
comment = ['comment']
self.get_channel.return_value = self.channel_info
with self.assertRaises(koji.ParameterError) as ex:
self.exports.editChannel(self.channel_name, comment=comment)
self.assertEqual(self.updates, [])
self.assertEqual(f"Invalid type for value '{comment}': {type(comment)}", str(ex.exception))
self.get_channel.assert_called_once_with(self.channel_name, strict=True)
self.verify_name_internal.assert_not_called()

View file

@ -8,7 +8,7 @@ UP = kojihub.UpdateProcessor
IP = kojihub.InsertProcessor
class TestSetHostEnabled(unittest.TestCase):
class TestEditHost(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
@ -22,6 +22,7 @@ class TestSetHostEnabled(unittest.TestCase):
return update
def setUp(self):
self.diff = None
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
side_effect=self.getInsert).start()
self.inserts = []
@ -34,12 +35,22 @@ class TestSetHostEnabled(unittest.TestCase):
self.context.session.assertLogin = mock.MagicMock()
self.context.session.assertPerm = mock.MagicMock()
self.exports = kojihub.RootExports()
self.get_host = mock.patch('kojihub.get_host').start()
self.hostinfo = {
'id': 123,
'user_id': 234,
'name': 'hostname',
'arches': 'x86_64',
'capacity': 100.0,
'description': 'description',
'comment': 'comment',
'enabled': False,
}
def tearDown(self):
mock.patch.stopall()
def test_edit_host_missing(self):
kojihub.get_host = mock.MagicMock()
kojihub.get_host.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.editHost('hostname')
@ -47,23 +58,47 @@ class TestSetHostEnabled(unittest.TestCase):
self.assertEqual(self.inserts, [])
self.assertEqual(self.updates, [])
def test_edit_host_invalid_description(self):
description = ['description']
kojihub.get_host.return_value = self.hostinfo
with self.assertRaises(koji.ParameterError) as ex:
self.exports.editHost('hostname', description=description)
self.assertEqual('Invalid type for description parameter: %s' % type(description),
str(ex.exception))
kojihub.get_host.assert_called_once_with('hostname', strict=True)
self.assertEqual(self.inserts, [])
self.assertEqual(self.updates, [])
def test_edit_host_invalid_comment_parameter(self):
comment = ['comment']
kojihub.get_host.return_value = self.hostinfo
with self.assertRaises(koji.ParameterError) as ex:
self.exports.editHost('hostname', comment=comment)
self.assertEqual('Invalid type for comment parameter: %s' % type(comment),
str(ex.exception))
kojihub.get_host.assert_called_once_with('hostname', strict=True)
self.assertEqual(self.inserts, [])
self.assertEqual(self.updates, [])
def test_edit_host_invalid_arches_parameter(self):
arches = ['arches arches']
kojihub.get_host.return_value = self.hostinfo
with self.assertRaises(koji.ParameterError) as ex:
self.exports.editHost('hostname', arches=arches)
self.assertEqual('Invalid type for arches parameter: %s' % type(arches),
str(ex.exception))
kojihub.get_host.assert_called_once_with('hostname', strict=True)
self.assertEqual(self.inserts, [])
self.assertEqual(self.updates, [])
def test_edit_host_valid(self):
kojihub.get_host = mock.MagicMock()
kojihub.get_host.return_value = {
'id': 123,
'user_id': 234,
'name': 'hostname',
'arches': ['x86_64'],
'capacity': 100.0,
'description': 'description',
'comment': 'comment',
'enabled': False,
}
kojihub.get_host.return_value = self.hostinfo
self.context.event_id = 42
self.context.session.user_id = 23
r = self.exports.editHost('hostname', arches=['x86_64', 'i386'],
capacity=12.0, comment='comment_new', non_existing_kw='bogus')
r = self.exports.editHost('hostname', arches='x86_64 i386', capacity=12.0,
comment='comment_new', non_existing_kw='bogus')
self.assertTrue(r)
kojihub.get_host.assert_called_once_with('hostname', strict=True)
@ -87,12 +122,11 @@ class TestSetHostEnabled(unittest.TestCase):
# insert
self.assertEqual(len(self.inserts), 1)
insert = self.inserts[0]
#data = kojihub.get_host.return_value
data = {
'create_event': 42,
'creator_id': 23,
'host_id': 123,
'arches': ['x86_64', 'i386'],
'arches': 'x86_64 i386',
'capacity': 12.0,
'comment': 'comment_new',
'description': 'description',
@ -105,16 +139,7 @@ class TestSetHostEnabled(unittest.TestCase):
def test_edit_host_no_change(self):
kojihub.get_host = mock.MagicMock()
kojihub.get_host.return_value = {
'id': 123,
'user_id': 234,
'name': 'hostname',
'arches': ['x86_64'],
'capacity': 100.0,
'description': 'description',
'comment': 'comment',
'enabled': False,
}
kojihub.get_host.return_value = self.hostinfo
self.context.event_id = 42
self.context.session.user_id = 23

View file

@ -42,3 +42,12 @@ class TestEditPermission(unittest.TestCase):
self.assertEqual(up.table, 'permissions')
self.assertEqual(up.rawdata, {})
self.context.session.assertPerm.assert_called_with('admin')
def test_edit_permission_wrong_type_permission(self):
description = ['test-description']
with self.assertRaises(koji.GenericError) as ex:
self.exports.editPermission(self.perm_name, description=description)
self.assertEqual(f"Invalid type for value '{description}': {type(description)}",
str(ex.exception))
self.update_processor.assert_not_called()
self.context.session.assertPerm.assert_called_with('admin')

View file

@ -236,7 +236,7 @@ WHERE id = %(tagID)i""", {'name': 'newtag', 'tagID': 333})
with self.assertRaises(koji.GenericError):
kojihub._edit_tag('tag', **kwargs)
def test_edit_wrong_format_tag(self):
def test_edit_wrong_tag(self):
tag_name_new = 'new-test-tag+'
tag_name = 'tag'
self.get_tag.return_value = {'id': 333,
@ -268,3 +268,36 @@ WHERE id = %(tagID)i""", {'name': 'newtag', 'tagID': 333})
self.verify_name_internal.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
kojihub._edit_tag('tag', **kwargs)
def test_edit_tag_remove_extra_wrong_format(self):
kwargs = {
'perm': None,
'name': 'tag_name_new',
'arches': 'arch1 arch2',
'locked': True,
'maven_support': False,
'maven_include_all': False,
'extra': {},
'remove_extra': 'remove-extra'
}
with self.assertRaises(koji.ParameterError) as ex:
kojihub._edit_tag('tag', **kwargs)
self.assertEqual(f"Invalid type for value '{kwargs['remove_extra']}': "
f"{type(kwargs['remove_extra'])}", str(ex.exception))
def test_edit_tag_block_extra_wrong_format(self):
kwargs = {
'perm': None,
'name': 'tag_name_new',
'arches': 'arch1 arch2',
'locked': True,
'maven_support': False,
'maven_include_all': False,
'extra': {},
'remove_extra': [],
'block_extra': 'block-extra'
}
with self.assertRaises(koji.ParameterError) as ex:
kojihub._edit_tag('tag', **kwargs)
self.assertEqual(f"Invalid type for value '{kwargs['block_extra']}': "
f"{type(kwargs['block_extra'])}", str(ex.exception))

View file

@ -42,8 +42,7 @@ class TestEditTagExternalRepo(unittest.TestCase):
self.get_tag_external_repos.return_value = []
with self.assertRaises(koji.GenericError) as cm:
kojihub.edit_tag_external_repo('tag', 'ext_repo', priority=6, merge_mode='bare')
self.assertEqual(cm.exception.args[0],
'external repo ext_repo not associated with tag tag')
self.assertEqual('external repo ext_repo not associated with tag tag', str(cm.exception))
self.get_tag.assert_called_once_with('tag', strict=True)
self.get_external_repo.assert_called_once_with('ext_repo', strict=True)
self.get_tag_external_repos.assert_called_once_with(tag_info=1, repo_info=11)

View file

@ -29,7 +29,7 @@ class TestEnableChannel(unittest.TestCase):
self.get_channel.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.enableChannel(self.channelname)
self.assertEqual("No such channel: %s" % self.channelname, str(cm.exception))
self.assertEqual(f"No such channel: {self.channelname}", str(cm.exception))
def test_valid(self):
self.get_channel.return_value = {'comment': None, 'description': None,
@ -42,3 +42,9 @@ class TestEnableChannel(unittest.TestCase):
self.assertEqual(update.values, {'comment': None, 'description': None, 'enabled': False,
'id': 1, 'name': 'test-channel'})
self.assertEqual(update.clauses, ['id = %(id)i'])
def test_wrong_type_channel(self):
comment = ['test-comment']
with self.assertRaises(koji.GenericError) as cm:
self.exports.enableChannel(self.channelname, comment=comment)
self.assertEqual(f"Invalid type for value '{comment}': {type(comment)}", str(cm.exception))

View file

@ -14,7 +14,7 @@ class TestGetRPM(unittest.TestCase):
rpminfo = ['test-user']
with self.assertRaises(koji.GenericError) as cm:
kojihub.get_rpm(rpminfo)
self.assertEqual("Invalid type for rpminfo: %s" % type(rpminfo), str(cm.exception))
self.assertEqual(f"Invalid type for rpminfo: {type(rpminfo)}", str(cm.exception))
class TestGetRPMHeaders(unittest.TestCase):
@ -41,7 +41,7 @@ class TestGetRPMHeaders(unittest.TestCase):
filepath = '../test/path'
with self.assertRaises(koji.GenericError) as cm:
self.exports.getRPMHeaders(taskID=99, filepath=filepath)
self.assertEqual("Invalid filepath: %s" % filepath, str(cm.exception))
self.assertEqual(f"Invalid filepath: {filepath}", str(cm.exception))
self.get_rpm.assert_not_called()
self.get_build.assert_not_called()
self.get_header_fields.assert_not_called()

View file

@ -0,0 +1,28 @@
import unittest
import mock
import koji
import kojihub
class TestGetArchive(unittest.TestCase):
def setUp(self):
self.maxDiff = None
self.list_archives = mock.patch('kojihub.list_archives').start()
def tearDown(self):
mock.patch.stopall()
def test_get_archive_non_exist_archive_with_strict(self):
archive_id = 1
self.list_archives.return_value = []
with self.assertRaises(koji.GenericError) as cm:
kojihub.get_archive(archive_id, strict=True)
self.assertEqual(f"No such archive: {archive_id}", str(cm.exception))
def test_get_archive_non_exist_archive_without_strict(self):
archive_id = 1
self.list_archives.return_value = []
rv = kojihub.get_archive(archive_id)
self.assertEqual(rv, None)

View file

@ -0,0 +1,20 @@
import unittest
import koji
import kojihub
class TestGetArchiveType(unittest.TestCase):
def test_get_archive_wrong_type_filename(self):
filename = ['test-filename']
with self.assertRaises(koji.ParameterError) as cm:
kojihub.get_archive_type(filename=filename)
self.assertEqual(f"Invalid type for value '{filename}': {type(filename)}",
str(cm.exception))
def test_get_archive_without_opt(self):
with self.assertRaises(koji.GenericError) as cm:
kojihub.get_archive_type()
self.assertEqual("one of filename, type_name, or type_id must be specified",
str(cm.exception))

View file

@ -0,0 +1,22 @@
import mock
import unittest
import koji
import kojihub
class TestGetBuildNotification(unittest.TestCase):
def setUp(self):
self.QueryProcessor = mock.patch('kojihub.QueryProcessor').start()
self.query = self.QueryProcessor.return_value
self.exports = kojihub.RootExports()
def tearDown(self):
mock.patch.stopall()
def test_empty_result_with_strict(self):
notif_id = 1
self.query.executeOne.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.getBuildNotification(notif_id, strict=True)
self.assertEqual(f"No notification with ID {notif_id} found", str(cm.exception))

View file

@ -0,0 +1,22 @@
import mock
import unittest
import koji
import kojihub
class TestGetBuildNotificationBlock(unittest.TestCase):
def setUp(self):
self.QueryProcessor = mock.patch('kojihub.QueryProcessor').start()
self.query = self.QueryProcessor.return_value
self.exports = kojihub.RootExports()
def tearDown(self):
mock.patch.stopall()
def test_empty_result_with_strict(self):
notif_id = 1
self.query.executeOne.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.getBuildNotificationBlock(notif_id, strict=True)
self.assertEqual(f"No notification block with ID {notif_id} found", str(cm.exception))

View file

@ -0,0 +1,29 @@
import mock
import unittest
import koji
import kojihub
class TestGetBuildNotificationBlocks(unittest.TestCase):
def setUp(self):
self.exports = kojihub.RootExports()
self.get_user = mock.patch('kojihub.get_user').start()
self.get_build_notification_blocks = mock.patch(
'kojihub.get_build_notification_blocks').start()
def tearDown(self):
mock.patch.stopall()
def test_loggedin_user(self):
self.get_user.return_value = {'id': 1}
self.exports.getBuildNotificationBlocks(None)
self.get_user.assert_called_once_with(None, strict=True)
self.get_build_notification_blocks.assert_called_once_with(1)
def test_user_not_found(self):
self.get_user.side_effect = koji.GenericError('error msg')
with self.assertRaises(koji.GenericError) as cm:
self.exports.getBuildNotificationBlocks(1)
self.get_user.assert_called_once_with(1, strict=True)
self.get_build_notification_blocks.assert_not_called()
self.assertEqual(cm.exception.args[0], 'error msg')

View file

@ -5,18 +5,21 @@ import kojihub
class TestGetBuildNotifications(unittest.TestCase):
@mock.patch('kojihub.get_user', return_value={'id': 1})
@mock.patch('kojihub.get_build_notifications')
def test_loggedin_user(self, get_build_notifications, get_user):
kojihub.RootExports().getBuildNotifications(None)
get_user.assert_called_once_with(None, strict=True)
get_build_notifications.assert_called_once_with(1)
def setUp(self):
self.exports = kojihub.RootExports()
self.get_user = mock.patch('kojihub.get_user').start()
self.get_build_notifications = mock.patch('kojihub.get_build_notifications').start()
@mock.patch('kojihub.get_user', side_effect=koji.GenericError('error msg'))
@mock.patch('kojihub.get_build_notifications')
def test_user_not_found(self, get_build_notifications, get_user):
def test_loggedin_user(self):
self.get_user.return_value = {'id': 1}
kojihub.RootExports().getBuildNotifications(None)
self.get_user.assert_called_once_with(None, strict=True)
self.get_build_notifications.assert_called_once_with(1)
def test_user_not_found(self):
self.get_user.side_effect = koji.GenericError('error msg')
with self.assertRaises(koji.GenericError) as cm:
kojihub.RootExports().getBuildNotifications(1)
get_user.assert_called_once_with(1, strict=True)
get_build_notifications.assert_not_called()
self.get_user.assert_called_once_with(1, strict=True)
self.get_build_notifications.assert_not_called()
self.assertEqual(cm.exception.args[0], 'error msg')

View file

@ -24,13 +24,13 @@ class TestGetChangelogEntries(unittest.TestCase):
self.get_build.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.getChangelogEntries(buildID=build_id, strict=True)
self.assertEqual("No such build: %s" % build_id, str(cm.exception))
self.assertEqual(f"No such build: {build_id}", str(cm.exception))
def test_taskid_invalid_path(self):
filepath = '../test/path'
with self.assertRaises(koji.GenericError) as cm:
self.exports.getChangelogEntries(taskID=99, filepath=filepath)
self.assertEqual("Invalid filepath: %s" % filepath, str(cm.exception))
self.assertEqual(f"Invalid filepath: {filepath}", str(cm.exception))
def test_taskid_without_filepath(self):
with self.assertRaises(koji.GenericError) as cm:
@ -43,7 +43,7 @@ class TestGetChangelogEntries(unittest.TestCase):
self.os_path_exists.return_value = True
with self.assertRaises(koji.GenericError) as cm:
self.exports.getChangelogEntries(taskID=99, before=before, filepath=filepath)
self.assertEqual("Invalid type for before: %s" % type(before), str(cm.exception))
self.assertEqual(f"Invalid type for before: {type(before)}", str(cm.exception))
def test_after_invalid_type(self):
after = {'after': '1133456'}
@ -51,7 +51,7 @@ class TestGetChangelogEntries(unittest.TestCase):
self.os_path_exists.return_value = True
with self.assertRaises(koji.GenericError) as cm:
self.exports.getChangelogEntries(taskID=99, after=after, filepath=filepath)
self.assertEqual("Invalid type for after: %s" % type(after), str(cm.exception))
self.assertEqual(f"Invalid type for after: {type(after)}", str(cm.exception))
def test_srpm_path_not_exist(self):
filepath = 'test/path'
@ -62,4 +62,4 @@ class TestGetChangelogEntries(unittest.TestCase):
self.os_path_exists.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.getChangelogEntries(taskID=task_id, filepath=filepath, strict=True)
self.assertEqual("SRPM %s doesn't exist" % srpm_path, str(cm.exception))
self.assertEqual(f"SRPM {srpm_path} doesn't exist", str(cm.exception))

View file

@ -17,7 +17,7 @@ class TestGetExternalRepo(unittest.TestCase):
self.get_external_repos.return_value = []
with self.assertRaises(koji.GenericError) as cm:
self.exports.getExternalRepo(repo, strict=True)
self.assertEqual("No such repo: %s" % repo, str(cm.exception))
self.assertEqual(f"No such repo: {repo}", str(cm.exception))
def test_non_exist_repo_without_strict(self):
repo = 'test-repo'

View file

@ -1,4 +1,3 @@
import koji
import kojihub
from .utils import DBQueryTestCase
@ -97,9 +96,3 @@ class TestGetExternalRepos(DBQueryTestCase):
self.assertEqual(rv, [{'id': 1,
'name': 'ext_repo_1',
'url': 'http://example.com/repo/'}])
def test_get_external_repos_wrong_type(self):
info = {'info_key': 'info_value'}
with self.assertRaises(koji.GenericError) as cm:
kojihub.get_external_repos(info=info)
self.assertEqual("Invalid name or id value: %s" % info, str(cm.exception))

View file

@ -7,7 +7,9 @@ import kojihub
class TestGetNextRelease(unittest.TestCase):
def setUp(self):
self.maxDiff = None
self.QueryProcessor = mock.patch('kojihub.QueryProcessor').start()
self.get_build = mock.patch('kojihub.get_build').start()
self._dml = mock.patch('kojihub._dml').start()
self.query = self.QueryProcessor.return_value
self.binfo = {'name': 'name', 'version': 'version'}
@ -25,7 +27,7 @@ class TestGetNextRelease(unittest.TestCase):
for n in [1, 2, 3, 5, 8, 13, 21, 34, 55]:
self.query.executeOne.return_value = {'release': str(n)}
result = kojihub.get_next_release(self.binfo)
self.assertEqual(result, str(n+1))
self.assertEqual(result, str(n + 1))
def test_get_next_release_complex(self):
data = [
@ -59,10 +61,10 @@ class TestGetNextRelease(unittest.TestCase):
# bad_incr_value
"foo",
None,
1.1,
{1:1},
{1: 1},
[1],
]
for val in data:
with self.assertRaises(koji.ParameterError):
with self.assertRaises(koji.ParameterError) as ex:
kojihub.get_next_release(self.binfo, incr=val)
self.assertEqual('incr parameter must be an integer', str(ex.exception))

View file

@ -0,0 +1,258 @@
import mock
import unittest
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestGetNotificationRecipients(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.readPackageList = mock.patch('kojihub.readPackageList').start()
self.get_user = mock.patch('kojihub.get_user').start()
self.exports = kojihub.RootExports()
def tearDown(self):
mock.patch.stopall()
def test_get_notification_recipients_watchers(self):
# without build / tag_id
build = None
tag_id = None
state = koji.BUILD_STATES['CANCELED']
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, [])
# only query to watchers
self.assertEqual(len(self.queries), 1)
q = self.queries[0]
self.assertEqual(q.columns, ['email', 'user_id'])
self.assertEqual(q.tables, ['build_notifications'])
self.assertEqual(q.clauses, ['package_id IS NULL',
'status = %(users_status)i',
'success_only = FALSE',
'tag_id IS NULL',
'usertype IN %(users_usertypes)s'])
self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id'])
self.assertEqual(q.values['state'], state)
self.assertEqual(q.values['build'], build)
self.assertEqual(q.values['tag_id'], tag_id)
'''
q = self.queries[1]
self.assertEqual(q.columns, ['user_id'])
self.assertEqual(q.tables, ['build_notifications_block'])
self.assertEqual(q.clauses, ['user_id IN %(user_ids)s'])
self.assertEqual(q.joins, [])
self.assertEqual(q.values['user_ids'], None)
'''
self.readPackageList.assert_not_called()
def test_get_notification_recipients_build_without_tag(self):
### with build without tag
tag_id = None
state = koji.BUILD_STATES['CANCELED']
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
self.queries = []
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, ['owner_name@test.domain.com'])
# there should be only query to watchers
self.assertEqual(len(self.queries), 2)
q = self.queries[0]
self.assertEqual(q.columns, ['email', 'user_id'])
self.assertEqual(q.tables, ['build_notifications'])
self.assertEqual(q.clauses, ['package_id = %(package_id)i OR package_id IS NULL',
'status = %(users_status)i',
'success_only = FALSE',
'tag_id IS NULL',
'usertype IN %(users_usertypes)s'])
self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id'])
self.assertEqual(q.values['package_id'], build['package_id'])
self.assertEqual(q.values['state'], state)
self.assertEqual(q.values['build'], build)
self.assertEqual(q.values['tag_id'], tag_id)
q = self.queries[1]
self.assertEqual(q.columns, ['user_id'])
self.assertEqual(q.tables, ['build_notifications_block'])
self.assertEqual(q.clauses, ['package_id = %(package_id)i OR package_id IS NULL',
'tag_id IS NULL',
'user_id IN %(user_ids)s',
])
self.assertEqual(q.joins, None)
self.assertEqual(q.values['user_ids'], [5])
self.readPackageList.assert_not_called()
def test_get_notification_recipients_tag_without_build(self):
### with tag without build makes no sense
build = None
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
self.queries = []
with self.assertRaises(koji.GenericError):
kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(self.queries, [])
self.readPackageList.assert_not_called()
def set_queries(self, return_values):
self.query_returns = return_values
self.query_returns.reverse()
def getQuery(*args, **kwargs):
q = QP(*args, **kwargs)
q.execute = mock.MagicMock()
q.execute.return_value = self.query_returns.pop()
self.queries.append(q)
return q
self.QueryProcessor.side_effect = getQuery
def test_get_notification_recipients_tag_with_build(self):
### with tag and build
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
self.readPackageList.return_value = {12345: {'blocked': False, 'owner_id': 'owner_id'}}
self.get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['NORMAL'],
'usertype': koji.USERTYPES['NORMAL']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(sorted(emails),
['owner_name@test.domain.com', 'pkg_owner_name@test.domain.com'])
# there should be only query to watchers
self.assertEqual(len(self.queries), 2)
q = self.queries[0]
self.assertEqual(q.columns, ['email', 'user_id'])
self.assertEqual(q.tables, ['build_notifications'])
self.assertEqual(q.clauses, ['package_id = %(package_id)i OR package_id IS NULL',
'status = %(users_status)i',
'success_only = FALSE',
'tag_id = %(tag_id)i OR tag_id IS NULL',
'usertype IN %(users_usertypes)s',
])
self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id'])
self.assertEqual(q.values['package_id'], build['package_id'])
self.assertEqual(q.values['state'], state)
self.assertEqual(q.values['build'], build)
self.assertEqual(q.values['tag_id'], tag_id)
q = self.queries[1]
self.assertEqual(q.columns, ['user_id'])
self.assertEqual(q.tables, ['build_notifications_block'])
self.assertEqual(q.clauses, ['package_id = %(package_id)i OR package_id IS NULL',
'tag_id = %(tag_id)i OR tag_id IS NULL',
'user_id IN %(user_ids)s',
])
self.assertEqual(q.joins, None)
self.assertEqual(sorted(q.values['user_ids']), [5, 342])
self.readPackageList.assert_called_once_with(
pkgID=build['package_id'], tagID=tag_id, inherit=True)
self.get_user.asssert_called_once_with(342, strict=True)
def test_get_notification_recipients_blocked_pkg_owner(self):
# blocked package owner
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
self.get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['BLOCKED'],
'usertype': koji.USERTYPES['NORMAL']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, ['owner_name@test.domain.com'])
def test_get_notification_recipients_optout(self):
# blocked package owner
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
self.get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['NORMAL'],
'usertype': koji.USERTYPES['NORMAL']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[{'user_id': 5}]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, [])
def test_get_notification_recipients_machine(self):
# package owner is machine
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
self.get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['NORMAL'],
'usertype': koji.USERTYPES['HOST']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, ['owner_name@test.domain.com'])

View file

@ -122,3 +122,13 @@ class TestGrantPermission(unittest.TestCase):
self.assertEqual(ip.table, 'user_perms')
self.assertEqual(ip.rawdata, {})
self.context.session.assertPerm.assert_called_with('admin')
def test_grant_permission_description_wrong_type(self):
description = ['test-description']
with self.assertRaises(koji.ParameterError) as ex:
self.exports.grantPermission(self.user_name, self.perms_name,
description=description, create=True)
self.assertEqual(f"Invalid type for value '{description}': {type(description)}",
str(ex.exception))
self.insert_processor.assert_not_called()
self.context.session.assertPerm.assert_called_with('admin')

View file

@ -0,0 +1,40 @@
import mock
import unittest
import koji
import kojihub
class TestImportArchive(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertPerm = mock.MagicMock()
self.filepath = 'path/to/file'
self.buildinfo = 'build-1-1.4'
self.type_archive = 'maven'
self.typeinfo = {'group_id': 1, 'artifact_id': 2, 'version': 1}
def tearDown(self):
mock.patch.stopall()
def test_maven_not_enabled(self):
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.importArchive(self.filepath, self.buildinfo, self.type_archive,
self.typeinfo)
self.assertEqual("Maven support not enabled", str(cm.exception))
def test_win_not_enabled(self):
type_archive = 'win'
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.importArchive(self.filepath, self.buildinfo, type_archive, self.typeinfo)
self.assertEqual("Windows support not enabled", str(cm.exception))
def test_unsupported_type(self):
type_archive = 'test-type'
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.importArchive(self.filepath, self.buildinfo, type_archive, self.typeinfo)
self.assertEqual(f"unsupported archive type: {type_archive}", str(cm.exception))

View file

@ -0,0 +1,23 @@
import unittest
import mock
import koji
import kojihub
class TestImportArchiveInternal(unittest.TestCase):
def setUp(self):
self.os_path_exists = mock.patch('os.path.exists').start()
def tearDown(self):
mock.patch.stopall()
def test_import_archive_internal_non_exist_filepath(self):
self.os_path_exists.return_value = False
filepath = 'test/file/path/to/archive'
buildinfo = {'id': 1, 'name': 'test-build'}
type_archive = 'maven'
typeInfo = {'group_id': 1, 'artifact_id': 2, 'version': 3}
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_archive_internal(filepath, buildinfo, type_archive, typeInfo)
self.assertEqual(f"No such file: {filepath}", str(cm.exception))

View file

@ -1,203 +1,13 @@
import copy
import mock
import unittest
import shutil
import tempfile
import unittest
import koji
import kojihub
class TestImportRPM(unittest.TestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
self.filename = self.tempdir + "/name-version-release.arch.rpm"
# Touch a file
with open(self.filename, 'w'):
pass
self.src_filename = self.tempdir + "/name-version-release.src.rpm"
# Touch a file
with open(self.src_filename, 'w'):
pass
self.context = mock.patch('kojihub.context').start()
self.cursor = mock.MagicMock()
self.rpm_header_retval = {
'filename': 'name-version-release.arch.rpm',
'sourcepackage': 2,
1000: 'name',
1001: 'version',
1002: 'release',
1003: 'epoch',
1006: 'buildtime',
1022: 'arch',
1044: 'name-version-release.arch',
1106: 'sourcepackage',
261: 'payload hash',
}
def tearDown(self):
shutil.rmtree(self.tempdir)
def test_nonexistant_rpm(self):
with self.assertRaises(koji.GenericError):
kojihub.import_rpm("this does not exist")
@mock.patch('kojihub.get_build')
@mock.patch('koji.get_rpm_header')
def test_import_rpm_failed_build(self, get_rpm_header, get_build):
get_rpm_header.return_value = self.rpm_header_retval
get_build.return_value = {
'state': koji.BUILD_STATES['FAILED'],
'name': 'name',
'version': 'version',
'release': 'release',
}
with self.assertRaises(koji.GenericError):
kojihub.import_rpm(self.filename)
@mock.patch('kojihub.new_typed_build')
@mock.patch('kojihub._dml')
@mock.patch('kojihub._singleValue')
@mock.patch('kojihub.get_build')
@mock.patch('koji.get_rpm_header')
def test_import_rpm_completed_build(self, get_rpm_header, get_build,
_singleValue, _dml,
new_typed_build):
get_rpm_header.return_value = self.rpm_header_retval
get_build.return_value = {
'state': koji.BUILD_STATES['COMPLETE'],
'name': 'name',
'version': 'version',
'release': 'release',
'id': 12345,
}
_singleValue.return_value = 9876
kojihub.import_rpm(self.filename)
fields = [
'arch',
'build_id',
'buildroot_id',
'buildtime',
'epoch',
'external_repo_id',
'id',
'name',
'payloadhash',
'release',
'size',
'version',
]
statement = 'INSERT INTO rpminfo (%s) VALUES (%s)' % (
", ".join(fields),
", ".join(['%%(%s)s' % field for field in fields])
)
values = {
'build_id': 12345,
'name': 'name',
'arch': 'arch',
'buildtime': 'buildtime',
'payloadhash': '7061796c6f61642068617368',
'epoch': 'epoch',
'version': 'version',
'buildroot_id': None,
'release': 'release',
'external_repo_id': 0,
'id': 9876,
'size': 0,
}
_dml.assert_called_once_with(statement, values)
@mock.patch('kojihub.new_typed_build')
@mock.patch('kojihub._dml')
@mock.patch('kojihub._singleValue')
@mock.patch('kojihub.get_build')
@mock.patch('koji.get_rpm_header')
def test_import_rpm_completed_source_build(self, get_rpm_header, get_build,
_singleValue, _dml,
new_typed_build):
retval = copy.copy(self.rpm_header_retval)
retval.update({
'filename': 'name-version-release.arch.rpm',
1044: 'name-version-release.src',
1022: 'src',
1106: 1,
})
get_rpm_header.return_value = retval
get_build.return_value = {
'state': koji.BUILD_STATES['COMPLETE'],
'name': 'name',
'version': 'version',
'release': 'release',
'id': 12345,
}
_singleValue.return_value = 9876
kojihub.import_rpm(self.src_filename)
fields = [
'arch',
'build_id',
'buildroot_id',
'buildtime',
'epoch',
'external_repo_id',
'id',
'name',
'payloadhash',
'release',
'size',
'version',
]
statement = 'INSERT INTO rpminfo (%s) VALUES (%s)' % (
", ".join(fields),
", ".join(['%%(%s)s' % field for field in fields])
)
values = {
'build_id': 12345,
'name': 'name',
'arch': 'src',
'buildtime': 'buildtime',
'payloadhash': '7061796c6f61642068617368',
'epoch': 'epoch',
'version': 'version',
'buildroot_id': None,
'release': 'release',
'external_repo_id': 0,
'id': 9876,
'size': 0,
}
_dml.assert_called_once_with(statement, values)
@mock.patch('os.path.exists')
def test_non_exist_file(self, os_path_exist):
exports = kojihub.RootExports()
basename = 'rpm-1-34'
uploadpath = koji.pathinfo.work()
filepath = '%s/%s/%s' % (uploadpath, self.filename, basename)
os_path_exist.return_value = False
with self.assertRaises(koji.GenericError) as cm:
exports.importRPM(self.filename, basename)
self.assertEqual("No such file: %s" % filepath, str(cm.exception))
@mock.patch('koji.get_rpm_header')
@mock.patch('os.path.exists')
@mock.patch('os.path.basename')
def test_non_exist_file(self, os_path_basename, os_path_exist, get_rpm_header):
self.cursor.fetchone.return_value = None
self.context.cnx.cursor.return_value = self.cursor
retval = copy.copy(self.rpm_header_retval)
retval.update({
'filename': 'name-version-release.arch.rpm',
'sourcepackage': 2
})
get_rpm_header.return_value = retval
os_path_exist.return_value = True
os_path_basename.return_value = 'name-version-release.arch.rpm'
kojihub.get_build.return_value = None
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_rpm(self.src_filename)
self.assertEqual("No such build", str(cm.exception))
class TestImportBuild(unittest.TestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
@ -210,6 +20,22 @@ class TestImportBuild(unittest.TestCase):
with open(self.src_filename, 'w'):
pass
self.check_volume_policy = mock.patch('kojihub.check_volume_policy').start()
self.new_typed_build = mock.patch('kojihub.new_typed_build').start()
self._dml = mock.patch('kojihub._dml').start()
self._singleValue = mock.patch('kojihub._singleValue').start()
self.get_build = mock.patch('kojihub.get_build').start()
self.add_rpm_sig = mock.patch('kojihub.add_rpm_sig').start()
self.rip_rpm_sighdr = mock.patch('koji.rip_rpm_sighdr').start()
self.import_rpm_file = mock.patch('kojihub.import_rpm_file').start()
self.import_rpm = mock.patch('kojihub.import_rpm').start()
self.QueryProcessor = mock.patch('kojihub.QueryProcessor').start()
self.context = mock.patch('kojihub.context').start()
self.new_package = mock.patch('kojihub.new_package').start()
self.get_rpm_header = mock.patch('koji.get_rpm_header').start()
self.pathinfo_work = mock.patch('koji.pathinfo.work').start()
self.os_path_exists = mock.patch('os.path.exists').start()
self.rpm_header_retval = {
'filename': 'name-version-release.arch.rpm',
1000: 'name',
@ -225,39 +51,21 @@ class TestImportBuild(unittest.TestCase):
def tearDown(self):
shutil.rmtree(self.tempdir)
mock.patch.stopall()
@mock.patch('kojihub.check_volume_policy')
@mock.patch('kojihub.new_typed_build')
@mock.patch('kojihub._dml')
@mock.patch('kojihub._singleValue')
@mock.patch('kojihub.get_build')
@mock.patch('kojihub.add_rpm_sig')
@mock.patch('koji.rip_rpm_sighdr')
@mock.patch('kojihub.import_rpm_file')
@mock.patch('kojihub.import_rpm')
@mock.patch('kojihub.QueryProcessor')
@mock.patch('kojihub.context')
@mock.patch('kojihub.new_package')
@mock.patch('koji.get_rpm_header')
@mock.patch('koji.pathinfo.work')
def test_import_build_completed_build(self, work, get_rpm_header,
new_package, context, query,
import_rpm, import_rpm_file,
rip_rpm_sighdr, add_rpm_sig,
get_build, _singleValue, _dml,
new_typed_build, check_volume_policy):
def test_import_build_completed_build(self):
rip_rpm_sighdr.return_value = (0, 0)
self.rip_rpm_sighdr.return_value = (0, 0)
processor = mock.MagicMock()
processor.executeOne.return_value = None
query.return_value = processor
self.QueryProcessor.return_value = processor
context.session.user_id = 99
self.context.session.user_id = 99
work.return_value = '/'
self.pathinfo_work.return_value = '/'
check_volume_policy.return_value = {'id':0, 'name': 'DEFAULT'}
self.check_volume_policy.return_value = {'id': 0, 'name': 'DEFAULT'}
retval = copy.copy(self.rpm_header_retval)
retval.update({
@ -266,7 +74,7 @@ class TestImportBuild(unittest.TestCase):
1022: 'src',
1106: 1,
})
get_rpm_header.return_value = retval
self.get_rpm_header.return_value = retval
binfo = {
'state': koji.BUILD_STATES['COMPLETE'],
'name': 'name',
@ -277,7 +85,7 @@ class TestImportBuild(unittest.TestCase):
# get_build called once to check for existing,
# if it doesn't exist, called another time after creating
# then 3rd later to get the build info
get_build.side_effect = [None, binfo, binfo]
self.get_build.side_effect = [None, binfo, binfo]
kojihub.import_build(self.src_filename, [self.filename])
@ -315,13 +123,29 @@ class TestImportBuild(unittest.TestCase):
'pkg_id': mock.ANY,
'id': mock.ANY,
}
_dml.assert_called_once_with(statement, values)
self._dml.assert_called_once_with(statement, values)
@mock.patch('os.path.exists')
def test_import_build_non_exist_file(self, os_path_exists):
def test_import_build_non_exist_file(self):
uploadpath = koji.pathinfo.work()
os_path_exists.return_value = False
self.os_path_exists.return_value = False
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_build(self.src_filename, [self.filename])
self.assertEqual("No such file: %s/%s" % (uploadpath, self.src_filename),
self.assertEqual(f"No such file: {uploadpath}/{self.src_filename}", str(cm.exception))
def test_import_build_wrong_type_brmap(self):
brmap = 'test-brmap'
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_build(self.src_filename, [self.filename], brmap=brmap)
self.assertEqual(f"Invalid type for value '{brmap}': {type(brmap)}", str(cm.exception))
def test_import_build_wrong_type_srpm(self):
srpm = ['test-srpm']
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_build(srpm, [self.filename])
self.assertEqual(f"Invalid type for value '{srpm}': {type(srpm)}", str(cm.exception))
def test_import_build_wrong_type_rpms(self):
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_build(self.src_filename, self.filename)
self.assertEqual(f"Invalid type for value '{self.filename}': {type(self.filename)}",
str(cm.exception))

View file

@ -0,0 +1,187 @@
import mock
import unittest
import koji
import kojihub
import shutil
import tempfile
import copy
class TestImportRPM(unittest.TestCase):
def setUp(self):
self.exports = kojihub.RootExports()
self.tempdir = tempfile.mkdtemp()
self.filename = self.tempdir + "/name-version-release.arch.rpm"
# Touch a file
with open(self.filename, 'w'):
pass
self.src_filename = self.tempdir + "/name-version-release.src.rpm"
# Touch a file
with open(self.src_filename, 'w'):
pass
self.context = mock.patch('kojihub.context').start()
self.context.session.assertPerm = mock.MagicMock()
self.cursor = mock.MagicMock()
self.rpm_header_retval = {
'filename': 'name-version-release.arch.rpm',
'sourcepackage': 2,
1000: 'name',
1001: 'version',
1002: 'release',
1003: 'epoch',
1006: 'buildtime',
1022: 'arch',
1044: 'name-version-release.arch',
1106: 'sourcepackage',
261: 'payload hash',
}
self.get_build = mock.patch('kojihub.get_build').start()
self.get_rpm_header = mock.patch('koji.get_rpm_header').start()
self.new_typed_build = mock.patch('kojihub.new_typed_build').start()
self._dml = mock.patch('kojihub._dml').start()
self._singleValue = mock.patch('kojihub._singleValue').start()
self.os_path_exists = mock.patch('os.path.exists').start()
self.os_path_basename = mock.patch('os.path.basename').start()
def tearDown(self):
shutil.rmtree(self.tempdir)
mock.patch.stopall()
def test_nonexistant_rpm(self):
with self.assertRaises(koji.GenericError):
kojihub.import_rpm("this does not exist")
def test_import_rpm_failed_build(self):
self.get_rpm_header.return_value = self.rpm_header_retval
self.get_build.return_value = {
'state': koji.BUILD_STATES['FAILED'],
'name': 'name',
'version': 'version',
'release': 'release',
}
with self.assertRaises(koji.GenericError):
kojihub.import_rpm(self.filename)
def test_import_rpm_completed_build(self):
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
self.get_rpm_header.return_value = self.rpm_header_retval
self.get_build.return_value = {
'state': koji.BUILD_STATES['COMPLETE'],
'name': 'name',
'version': 'version',
'release': 'release',
'id': 12345,
}
self._singleValue.return_value = 9876
kojihub.import_rpm(self.filename)
fields = [
'arch',
'build_id',
'buildroot_id',
'buildtime',
'epoch',
'external_repo_id',
'id',
'name',
'payloadhash',
'release',
'size',
'version',
]
statement = 'INSERT INTO rpminfo (%s) VALUES (%s)' % (
", ".join(fields),
", ".join(['%%(%s)s' % field for field in fields])
)
values = {
'build_id': 12345,
'name': 'name',
'arch': 'arch',
'buildtime': 'buildtime',
'payloadhash': '7061796c6f61642068617368',
'epoch': 'epoch',
'version': 'version',
'buildroot_id': None,
'release': 'release',
'external_repo_id': 0,
'id': 9876,
'size': 0,
}
self._dml.assert_called_once_with(statement, values)
def test_import_rpm_completed_source_build(self):
self.os_path_basename.return_value = 'name-version-release.src.rpm'
retval = copy.copy(self.rpm_header_retval)
retval.update({
'filename': 'name-version-release.arch.rpm',
1044: 'name-version-release.src',
1022: 'src',
1106: 1,
})
self.get_rpm_header.return_value = retval
self.get_build.return_value = {
'state': koji.BUILD_STATES['COMPLETE'],
'name': 'name',
'version': 'version',
'release': 'release',
'id': 12345,
}
self._singleValue.return_value = 9876
kojihub.import_rpm(self.src_filename)
fields = [
'arch',
'build_id',
'buildroot_id',
'buildtime',
'epoch',
'external_repo_id',
'id',
'name',
'payloadhash',
'release',
'size',
'version',
]
statement = 'INSERT INTO rpminfo (%s) VALUES (%s)' % (
", ".join(fields),
", ".join(['%%(%s)s' % field for field in fields])
)
values = {
'build_id': 12345,
'name': 'name',
'arch': 'src',
'buildtime': 'buildtime',
'payloadhash': '7061796c6f61642068617368',
'epoch': 'epoch',
'version': 'version',
'buildroot_id': None,
'release': 'release',
'external_repo_id': 0,
'id': 9876,
'size': 0,
}
self._dml.assert_called_once_with(statement, values)
def test_non_exist_file(self):
basename = 'rpm-1-34'
self.os_path_exists.return_value = False
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_rpm(self.filename, basename)
self.assertEqual(f"No such file: {self.filename}", str(cm.exception))
def test_non_exist_build(self):
self.cursor.fetchone.return_value = None
self.context.cnx.cursor.return_value = self.cursor
retval = copy.copy(self.rpm_header_retval)
retval.update({
'filename': 'name-version-release.arch.rpm',
'sourcepackage': 2
})
self.get_rpm_header.return_value = retval
self.os_path_exists.return_value = True
self.os_path_basename.return_value = 'name-version-release.arch.rpm'
kojihub.get_build.return_value = None
with self.assertRaises(koji.GenericError) as cm:
kojihub.import_rpm(self.src_filename)
self.assertEqual("No such build", str(cm.exception))

View file

@ -1,265 +1,224 @@
import mock
from .utils import DBQueryTestCase
import unittest
import koji
import kojihub
QP = kojihub.QueryProcessor
class TestListArchives(DBQueryTestCase):
maxDiff = None
class TestListArchives(unittest.TestCase):
def setUp(self):
self.maxDiff = None
self.get_build = mock.patch('kojihub.get_build').start()
self.get_host = mock.patch('kojihub.get_host').start()
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.get_query).start()
self.queries = []
self.exports = kojihub.RootExports()
def tearDown(self):
mock.patch.stopall()
def get_query(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def test_list_archives_simple(self):
rv = kojihub.list_archives()
kojihub.list_archives()
self.assertEqual(len(self.queries), 1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=[],
values={})
self.assertEqual(rv, [])
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, [])
self.assertEqual(query.joins, ['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
def test_list_archives_strict(self):
@mock.patch('kojihub.QueryProcessor')
def test_list_archives_strict(self, QueryProcessor):
query = QueryProcessor.return_value
query.execute.return_value = None
with self.assertRaises(koji.GenericError) as cm:
kojihub.list_archives(strict=True)
self.assertEqual(cm.exception.args[0], 'No archives found.')
def test_list_archives_buildid(self):
kojihub.list_archives(buildID=1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['build_id = %(build_id)i'],
values={'build_id': 1})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['build_id = %(build_id)i'])
self.assertEqual(query.joins, ['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'build_id': 1})
def test_list_archives_buildrootid(self):
kojihub.list_archives(buildrootID=1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['buildroot_id = %(buildroot_id)i'],
values={'buildroot_id': 1})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['buildroot_id = %(buildroot_id)i'])
self.assertEqual(query.joins, ['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'buildroot_id': 1})
def test_list_archives_componentbuildrootid(self):
kojihub.list_archives(componentBuildrootID=1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'buildroot_archives on archiveinfo.id = buildroot_archives.archive_id'],
clauses=['buildroot_archives.buildroot_id = %(component_buildroot_id)i'],
values={'component_buildroot_id': 1},
colsByAlias={'build_id': 'archiveinfo.build_id',
'type_name': 'archivetypes.name',
'component_buildroot_id': 'buildroot_archives.buildroot_id',
'type_id': 'archiveinfo.type_id',
'checksum': 'archiveinfo.checksum',
'extra': 'archiveinfo.extra',
'filename': 'archiveinfo.filename',
'project': 'buildroot_archives.project_dep',
'type_description': 'archivetypes.description',
'metadata_only': 'archiveinfo.metadata_only',
'type_extensions': 'archivetypes.extensions',
'btype': 'btype.name',
'checksum_type': 'archiveinfo.checksum_type',
'btype_id': 'archiveinfo.btype_id',
'buildroot_id': 'archiveinfo.buildroot_id',
'id': 'archiveinfo.id',
'size': 'archiveinfo.size'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses,
['buildroot_archives.buildroot_id = %(component_buildroot_id)i'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'buildroot_archives on archiveinfo.id = buildroot_archives.archive_id'])
self.assertEqual(query.values, {'component_buildroot_id': 1})
def test_list_archives_imageid(self):
kojihub.list_archives(imageID=1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'archive_components ON archiveinfo.id = archive_components.component_id'],
clauses=['archive_components.archive_id = %(imageID)i'],
values={'imageID': 1})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['archive_components.archive_id = %(imageID)i'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'archive_components ON archiveinfo.id = '
'archive_components.component_id'])
self.assertEqual(query.values, {'imageID': 1})
def test_list_archives_hostid(self):
kojihub.list_archives(hostID=1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'standard_buildroot on archiveinfo.buildroot_id = standard_buildroot.buildroot_id'],
clauses=['standard_buildroot.host_id = %(host_id)i'],
values={'host_id': 1},
colsByAlias={'host_id': 'standard_buildroot.host_id',
'build_id': 'archiveinfo.build_id',
'type_name': 'archivetypes.name',
'type_id': 'archiveinfo.type_id',
'checksum': 'archiveinfo.checksum',
'extra': 'archiveinfo.extra',
'filename': 'archiveinfo.filename',
'type_description': 'archivetypes.description',
'metadata_only': 'archiveinfo.metadata_only',
'type_extensions': 'archivetypes.extensions',
'btype': 'btype.name',
'checksum_type': 'archiveinfo.checksum_type',
'btype_id': 'archiveinfo.btype_id',
'buildroot_id': 'archiveinfo.buildroot_id',
'id': 'archiveinfo.id',
'size': 'archiveinfo.size'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['standard_buildroot.host_id = %(host_id)i'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'standard_buildroot on archiveinfo.buildroot_id = '
'standard_buildroot.buildroot_id'])
self.assertEqual(query.values, {'host_id': 1})
def test_list_archives_filename(self):
kojihub.list_archives(filename='somefile.txt')
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['filename = %(filename)s'],
values={'filename': 'somefile.txt'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['filename = %(filename)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'filename': 'somefile.txt'})
def test_list_archives_size(self):
kojihub.list_archives(size=1231831)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['size = %(size)i'],
values={'size': 1231831})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['size = %(size)i'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'size': 1231831})
def test_list_archives_checksum(self):
kojihub.list_archives(checksum='7873f0a6dbf3abc07724e000ac9b3941')
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['checksum = %(checksum)s'],
values={'checksum': '7873f0a6dbf3abc07724e000ac9b3941'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['checksum = %(checksum)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'checksum': '7873f0a6dbf3abc07724e000ac9b3941'})
def test_list_archives_checksum_type(self):
kojihub.list_archives(checksum_type=koji.CHECKSUM_TYPES['sha256'])
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['checksum_type = %(checksum_type)s'],
values={'checksum_type': koji.CHECKSUM_TYPES['sha256']})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['checksum_type = %(checksum_type)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'checksum_type': koji.CHECKSUM_TYPES['sha256']})
def test_list_archives_archiveid(self):
kojihub.list_archives(archiveID=1)
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['archiveinfo.id = %(archive_id)s'],
values={'archive_id': 1})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['archiveinfo.id = %(archive_id)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'archive_id': 1})
def test_list_archives_type_maven(self):
kojihub.list_archives(type='maven', typeInfo={'group_id': 'gid',
'artifact_id': 'aid',
'version': '1.0.1'})
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'maven_archives ON archiveinfo.id = maven_archives.archive_id'],
clauses=['maven_archives.artifact_id = %(artifact_id)s',
'maven_archives.group_id = %(group_id)s',
'maven_archives.version = %(version)s'],
values={'group_id': 'gid',
'artifact_id': 'aid',
'version': '1.0.1'},
colsByAlias={'group_id': 'maven_archives.group_id',
'artifact_id': 'maven_archives.artifact_id',
'version': 'maven_archives.version',
'build_id': 'archiveinfo.build_id',
'type_name': 'archivetypes.name',
'type_id': 'archiveinfo.type_id',
'checksum': 'archiveinfo.checksum',
'extra': 'archiveinfo.extra',
'filename': 'archiveinfo.filename',
'type_description': 'archivetypes.description',
'metadata_only': 'archiveinfo.metadata_only',
'type_extensions': 'archivetypes.extensions',
'btype': 'btype.name',
'checksum_type': 'archiveinfo.checksum_type',
'btype_id': 'archiveinfo.btype_id',
'buildroot_id': 'archiveinfo.buildroot_id',
'id': 'archiveinfo.id',
'size': 'archiveinfo.size'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['maven_archives.artifact_id = %(artifact_id)s',
'maven_archives.group_id = %(group_id)s',
'maven_archives.version = %(version)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'maven_archives ON archiveinfo.id = maven_archives.archive_id'])
self.assertEqual(query.values, {'group_id': 'gid',
'artifact_id': 'aid',
'version': '1.0.1'})
def test_list_archives_type_win(self):
kojihub.list_archives(type='win', typeInfo={'relpath': 'somerelpath',
'platforms': 'all',
'flags': ['A', 'B']})
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=sorted([
'archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'win_archives ON archiveinfo.id = win_archives.archive_id']),
clauses=sorted([
'win_archives.relpath = %(relpath)s',
r"platforms ~ %(platforms_pattern_0)s",
r"flags ~ %(flags_pattern_0)s",
r"flags ~ %(flags_pattern_1)s"]),
values={'relpath': 'somerelpath',
'flags_pattern_0': '\\mA\\M',
'flags_pattern_1': '\\mB\\M',
'platforms_pattern_0': '\\mall\\M',
},
colsByAlias={'relpath': 'win_archives.relpath',
'platforms': 'win_archives.platforms',
'flags': 'win_archives.flags',
'build_id': 'archiveinfo.build_id',
'type_name': 'archivetypes.name',
'type_id': 'archiveinfo.type_id',
'checksum': 'archiveinfo.checksum',
'extra': 'archiveinfo.extra',
'filename': 'archiveinfo.filename',
'type_description': 'archivetypes.description',
'metadata_only': 'archiveinfo.metadata_only',
'type_extensions': 'archivetypes.extensions',
'btype': 'btype.name',
'checksum_type': 'archiveinfo.checksum_type',
'btype_id': 'archiveinfo.btype_id',
'buildroot_id': 'archiveinfo.buildroot_id',
'id': 'archiveinfo.id',
'size': 'archiveinfo.size'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, sorted(['win_archives.relpath = %(relpath)s',
r"platforms ~ %(platforms_pattern_0)s",
r"flags ~ %(flags_pattern_0)s",
r"flags ~ %(flags_pattern_1)s"]))
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'win_archives ON archiveinfo.id = win_archives.archive_id'])
self.assertEqual(query.values, {'relpath': 'somerelpath',
'flags_pattern_0': '\\mA\\M',
'flags_pattern_1': '\\mB\\M',
'platforms_pattern_0': '\\mall\\M'})
def test_list_archives_type_image(self):
kojihub.list_archives(type='image', typeInfo={'arch': 'i386'})
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'image_archives ON archiveinfo.id = image_archives.archive_id'],
clauses=['image_archives.arch = %(arch)s'],
values={'arch': 'i386'},
colsByAlias={'arch': 'image_archives.arch',
'build_id': 'archiveinfo.build_id',
'type_name': 'archivetypes.name',
'type_id': 'archiveinfo.type_id',
'checksum': 'archiveinfo.checksum',
'extra': 'archiveinfo.extra',
'filename': 'archiveinfo.filename',
'type_description': 'archivetypes.description',
'metadata_only': 'archiveinfo.metadata_only',
'type_extensions': 'archivetypes.extensions',
'btype': 'btype.name',
'checksum_type': 'archiveinfo.checksum_type',
'btype_id': 'archiveinfo.btype_id',
'buildroot_id': 'archiveinfo.buildroot_id',
'id': 'archiveinfo.id',
'size': 'archiveinfo.size'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['image_archives.arch = %(arch)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id',
'image_archives ON archiveinfo.id = image_archives.archive_id'])
self.assertEqual(query.values, {'arch': 'i386'})
@mock.patch('kojihub.lookup_name', return_value={'id': 111, 'name': 'other'})
def test_list_archives_type_others(self, lookup_name):
kojihub.list_archives(type='other')
self.assertLastQueryEqual(tables=['archiveinfo'],
joins=['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'],
clauses=['archiveinfo.btype_id = %(btype_id)s'],
values={'btype_id': 111},
colsByAlias={'build_id': 'archiveinfo.build_id',
'type_name': 'archivetypes.name',
'type_id': 'archiveinfo.type_id',
'checksum': 'archiveinfo.checksum',
'extra': 'archiveinfo.extra',
'filename': 'archiveinfo.filename',
'type_description': 'archivetypes.description',
'metadata_only': 'archiveinfo.metadata_only',
'type_extensions': 'archivetypes.extensions',
'btype': 'btype.name',
'checksum_type': 'archiveinfo.checksum_type',
'btype_id': 'archiveinfo.btype_id',
'buildroot_id': 'archiveinfo.buildroot_id',
'id': 'archiveinfo.id',
'size': 'archiveinfo.size'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['archiveinfo'])
self.assertEqual(query.clauses, ['archiveinfo.btype_id = %(btype_id)s'])
self.assertEqual(query.joins,
['archivetypes on archiveinfo.type_id = archivetypes.id',
'btype ON archiveinfo.btype_id = btype.id'])
self.assertEqual(query.values, {'btype_id': 111})
@mock.patch('kojihub.lookup_name', return_value=None)
def test_list_archives_type_not_found(self, lookup_name):

View file

@ -8,64 +8,58 @@ QP = kojihub.QueryProcessor
class TestListBTypes(unittest.TestCase):
@mock.patch('kojihub.QueryProcessor')
def test_list_btypes(self, QueryProcessor):
def setUp(self):
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.get_query).start()
self.queries = []
self.exports = kojihub.RootExports()
# default query
query = QueryProcessor.return_value
query.execute.return_value = "return value"
ret = kojihub.list_btypes()
QueryProcessor.assert_called_once()
query.execute.assert_called_once()
self.assertEqual(ret, "return value")
def tearDown(self):
mock.patch.stopall()
args, kwargs = QueryProcessor.call_args
def get_query(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def test_list_btypes_default(self):
kojihub.list_btypes()
self.QueryProcessor.assert_called_once()
args, kwargs = self.QueryProcessor.call_args
self.assertEqual(args, ())
qp = QP(**kwargs)
self.assertEqual(qp.tables, ['btype'])
self.assertEqual(qp.columns, ['id', 'name'])
self.assertEqual(qp.clauses, [])
self.assertEqual(qp.joins, None)
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['btype'])
self.assertEqual(query.columns, ['id', 'name'])
self.assertEqual(query.clauses, [])
self.assertEqual(query.joins, None)
QueryProcessor.reset_mock()
def test_list_btypes_by_name(self):
kojihub.list_btypes({'name': 'rpm'})
self.QueryProcessor.assert_called_once()
# query by name
query = QueryProcessor.return_value
query.execute.return_value = "return value"
ret = kojihub.list_btypes({'name': 'rpm'})
QueryProcessor.assert_called_once()
query.execute.assert_called_once()
self.assertEqual(ret, "return value")
args, kwargs = QueryProcessor.call_args
args, kwargs = self.QueryProcessor.call_args
self.assertEqual(args, ())
qp = QP(**kwargs)
self.assertEqual(qp.tables, ['btype'])
self.assertEqual(qp.columns, ['id', 'name'])
self.assertEqual(qp.clauses, ['btype.name = %(name)s'])
self.assertEqual(qp.values, {'name': 'rpm'})
self.assertEqual(qp.joins, None)
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['btype'])
self.assertEqual(query.columns, ['id', 'name'])
self.assertEqual(query.clauses, ['btype.name = %(name)s'])
self.assertEqual(query.values, {'name': 'rpm'})
self.assertEqual(query.joins, None)
QueryProcessor.reset_mock()
def test_list_btypes_by_it_with_opts(self):
kojihub.list_btypes({'id': 1}, {'order': 'id'})
self.QueryProcessor.assert_called_once()
# query by id, with opts
query = QueryProcessor.return_value
query.execute.return_value = "return value"
ret = kojihub.list_btypes({'id': 1}, {'order': 'id'})
QueryProcessor.assert_called_once()
query.execute.assert_called_once()
self.assertEqual(ret, "return value")
args, kwargs = QueryProcessor.call_args
args, kwargs = self.QueryProcessor.call_args
self.assertEqual(args, ())
qp = QP(**kwargs)
self.assertEqual(qp.tables, ['btype'])
self.assertEqual(qp.columns, ['id', 'name'])
self.assertEqual(qp.clauses, ['btype.id = %(id)s'])
self.assertEqual(qp.values, {'id': 1})
self.assertEqual(qp.opts, {'order': 'id'})
self.assertEqual(qp.joins, None)
QueryProcessor.reset_mock()
# query by name
query = self.queries[0]
self.assertEqual(query.tables, ['btype'])
self.assertEqual(query.columns, ['id', 'name'])
self.assertEqual(query.clauses, ['btype.id = %(id)s'])
self.assertEqual(query.values, {'id': 1})
self.assertEqual(query.opts, {'order': 'id'})
self.assertEqual(query.joins, None)

View file

@ -25,6 +25,8 @@ class TestListBuilds(unittest.TestCase):
self.queries = []
self.context = mock.patch('kojihub.context').start()
self.get_package_id = mock.patch('kojihub.get_package_id').start()
self.get_user = mock.patch('kojihub.get_user').start()
self.cursor = mock.MagicMock()
self.build_list = [{'build_id': 9,
'epoch': 0,
@ -41,18 +43,16 @@ class TestListBuilds(unittest.TestCase):
'volume_id': 0,
'volume_name': 'DEFAULT'}]
@mock.patch('kojihub.get_package_id')
def test_wrong_package(self, get_package_id):
def test_wrong_package(self):
package = 'test-package'
get_package_id.return_value = None
self.get_package_id.return_value = None
rv = self.exports.listBuilds(packageID=package)
self.assertEqual(rv, [])
@mock.patch('kojihub.get_package_id')
def test_package_string(self, get_package_id):
def test_package_string(self):
package = 'test-package'
package_id = 1
get_package_id.return_value = package_id
self.get_package_id.return_value = package_id
self.query_executeOne.return_value = None
self.exports.listBuilds(packageID=package)
self.assertEqual(len(self.queries), 1)
@ -76,9 +76,8 @@ class TestListBuilds(unittest.TestCase):
'LEFT JOIN volume ON build.volume_id = volume.id',
'LEFT JOIN users ON build.owner = users.id'])
@mock.patch('kojihub.get_user')
def test_wrong_user(self, get_user):
def test_wrong_user(self):
user = 'test-user'
get_user.return_value = None
self.get_user.return_value = None
rv = self.exports.listBuilds(userID=user)
self.assertEqual(rv, [])

View file

@ -0,0 +1,40 @@
import unittest
import kojihub
import mock
QP = kojihub.QueryProcessor
class TestListPackagesSimple(unittest.TestCase):
def setUp(self):
self.maxDiff = None
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.get_query).start()
self.queries = []
self.exports = kojihub.RootExports()
def tearDown(self):
mock.patch.stopall()
def get_query(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def test_prefix_not_none(self):
self.exports.listPackagesSimple('test-prefix')
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['package'])
self.assertEqual(query.clauses, ["package.name ILIKE %(prefix)s || '%%'"])
self.assertEqual(query.joins, None)
def test_prefix_is_none(self):
self.exports.listPackagesSimple()
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['package'])
self.assertEqual(query.clauses, None)
self.assertEqual(query.joins, None)

View file

@ -1,14 +1,87 @@
import unittest
import mock
import koji
import kojihub
QP = kojihub.QueryProcessor
class TestListRpms(unittest.TestCase):
def setUp(self):
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.get_query).start()
self.queries = []
self.get_build = mock.patch('kojihub.get_build').start()
self.get_host = mock.patch('kojihub.get_host').start()
self._dml = mock.patch('kojihub._dml').start()
self.list_rpms = {'arch': 'x86_64',
'build_id': 1,
'buildroot_id': 2,
'buildtime': 1596090711,
'epoch': 2,
'external_repo_id': 1,
'external_repo_name': 'fedora-34-released',
'extra': None,
'id': 277,
'metadata_only': False,
'name': 'shadow-utils',
'nvr': 'shadow-utils-4.8.1-4.fc33',
'payloadhash': 'c5bfe5267dc6e0ca127092a82b4f260b',
'release': '4.fc33',
'size': 3891272,
'version': '4.8.1'}
def tearDown(self):
mock.patch.stopall()
def get_query(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def test_wrong_type_arches(self):
arches = {'test-arch': 'val'}
with self.assertRaises(koji.GenericError) as cm:
kojihub.list_rpms(arches=arches)
self.assertEqual('Invalid type for "arches" parameter: %s' % type(arches),
str(cm.exception))
self.assertEqual(f'Invalid type for "arches" parameter: {type(arches)}', str(cm.exception))
def test_int_values(self):
build_id = 1
buildroot_id = 1
host_id = 1
arches = 'x86_64'
kojihub.list_rpms(arches=arches, buildID=build_id, buildrootID=buildroot_id,
hostID=host_id)
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['rpminfo'])
self.assertEqual(query.joins,
['LEFT JOIN external_repo ON rpminfo.external_repo_id = external_repo.id',
'standard_buildroot ON rpminfo.buildroot_id = '
'standard_buildroot.buildroot_id'])
self.assertEqual(query.clauses, [
'rpminfo.arch = %(arches)s',
'rpminfo.build_id = %(buildID)i',
'rpminfo.buildroot_id = %(buildrootID)i',
'standard_buildroot.host_id = %(hostID)i',
])
def test_compoenent_buldroot_image_list_arch_values(self):
comp_buildroot_id = 1
image_id = 1
arches = ['x86_64']
kojihub.list_rpms(componentBuildrootID=comp_buildroot_id, imageID=image_id, arches=arches)
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
self.assertEqual(query.tables, ['rpminfo'])
self.assertEqual(query.joins,
['LEFT JOIN external_repo ON rpminfo.external_repo_id = external_repo.id',
'buildroot_listing ON rpminfo.id = buildroot_listing.rpm_id',
'archive_rpm_components ON rpminfo.id = archive_rpm_components.rpm_id'])
self.assertEqual(query.clauses, [
'archive_rpm_components.archive_id = %(imageID)i',
'buildroot_listing.buildroot_id = %(componentBuildrootID)i',
'rpminfo.arch IN %(arches)s',
])

View file

@ -44,12 +44,11 @@ class TestLookupName(unittest.TestCase):
{'id': 'not a valid int'},
['something'],
set(),
]
]
for value in bad_values:
with self.assertRaises(koji.GenericError) as cm:
kojihub.lookup_name('mytable', value)
self.assertEqual('Invalid name or id value: %s' % value,
str(cm.exception))
self.assertEqual(f'Invalid name or id value: {value}', str(cm.exception))
self.assertEqual(len(self.queries), 0)
self.assertEqual(len(self.inserts), 0)
@ -78,7 +77,7 @@ class TestLookupName(unittest.TestCase):
self.assertEqual(len(self.inserts), 0)
def test_query_by_dict(self):
kojihub.lookup_name('some_table', {'id':12345, 'name': 'whatever'})
kojihub.lookup_name('some_table', {'id': 12345, 'name': 'whatever'})
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
clauses = ['(some_table.id = %(some_table_id)s)']
@ -110,7 +109,7 @@ class TestLookupName(unittest.TestCase):
def test_lookup_name_strict(self):
self.query_executeOne.return_value = None
with self.assertRaises(koji.GenericError) as cm:
with self.assertRaises(koji.GenericError):
kojihub.lookup_name('package', 'python', strict=True)
self.assertEqual(len(self.queries), 1)
self.assertEqual(len(self.inserts), 0)
@ -134,7 +133,7 @@ class TestLookupName(unittest.TestCase):
bad_values = [
{'id': 100},
100
]
]
for value in bad_values:
with self.assertRaises(koji.GenericError) as cm:
kojihub.lookup_name('package', value, create=True)

View file

@ -0,0 +1,49 @@
import unittest
import koji
import kojihub
import mock
class TestMaven(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertLogin = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.get_channel = mock.patch('kojihub.get_channel').start()
self.make_task = mock.patch('kojihub.make_task').start()
self.url = 'https://test-url.com'
self.target = 'test-target'
def tearDown(self):
mock.patch.stopall()
def test_maven_not_supported(self):
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.mavenBuild(self.url, self.target)
self.assertEqual("Maven support not enabled", str(cm.exception))
def test_url_not_str(self):
url = ['test-url']
self.context.opts.get.return_value = True
with self.assertRaises(koji.GenericError) as cm:
self.exports.mavenBuild(url, self.target)
self.assertEqual(f"Invalid type for value '{url}': {type(url)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
self.context.opts.get.return_value = True
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.mavenBuild(self.url, self.target, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_channel_not_str(self):
priority = 10
self.context.opts.get.return_value = True
self.get_channel.return_value = {'comment': None, 'description': None, 'enabled': True,
'id': 2, 'name': 'maven'}
self.make_task.return_value = 123
self.exports.mavenBuild(self.url, self.target, priority=priority, channel=2)

View file

@ -6,6 +6,7 @@ import kojihub
IP = kojihub.InsertProcessor
class TestNewBuild(unittest.TestCase):
def setUp(self):
self.get_rpm = mock.patch('kojihub.get_rpm').start()
@ -13,7 +14,7 @@ class TestNewBuild(unittest.TestCase):
self.nextval = mock.patch('kojihub.nextval').start()
self.Savepoint = mock.patch('kojihub.Savepoint').start()
self.InsertProcessor = mock.patch('kojihub.InsertProcessor',
side_effect=self.getInsert).start()
side_effect=self.getInsert).start()
self.inserts = []
self.insert_execute = mock.MagicMock()
self.lookup_package = mock.patch('kojihub.lookup_package').start()
@ -35,7 +36,7 @@ class TestNewBuild(unittest.TestCase):
def test_valid(self):
self.get_build.return_value = None
self._singleValue.return_value = 65 # free build id
self._singleValue.return_value = 65 # free build id
self.new_package.return_value = 54
self.get_user.return_value = {'id': 123}
data = {
@ -99,10 +100,11 @@ class TestNewBuild(unittest.TestCase):
'extra': {'extra_key': 'extra_value'},
}
with self.assertRaises(koji.GenericError):
with self.assertRaises(koji.GenericError) as cm:
kojihub.new_build(data)
self.assertEqual(len(self.inserts), 0)
self.assertEqual("No name or package id provided for build", str(cm.exception))
def test_wrong_owner(self):
self.get_user.side_effect = koji.GenericError
@ -121,7 +123,6 @@ class TestNewBuild(unittest.TestCase):
self.assertEqual(len(self.inserts), 0)
def test_missing_vre(self):
self.get_user.side_effect = koji.GenericError
data = {
'name': 'test_name',
'version': 'test_version',

View file

@ -1,821 +0,0 @@
import mock
import unittest
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestNotifications(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.exports.getUser = mock.MagicMock()
self.exports.hasPerm = mock.MagicMock()
self.exports.getBuildNotification = mock.MagicMock()
self.exports.getBuildNotificationBlock = mock.MagicMock()
def tearDown(self):
mock.patch.stopall()
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_watchers(self, readPackageList, get_user):
# without build / tag_id
build = None
tag_id = None
state = koji.BUILD_STATES['CANCELED']
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, [])
# only query to watchers
self.assertEqual(len(self.queries), 1)
q = self.queries[0]
self.assertEqual(q.columns, ['email', 'user_id'])
self.assertEqual(q.tables, ['build_notifications'])
self.assertEqual(q.clauses, ['package_id IS NULL',
'status = %(users_status)i',
'success_only = FALSE',
'tag_id IS NULL',
'usertype IN %(users_usertypes)s'])
self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id'])
self.assertEqual(q.values['state'], state)
self.assertEqual(q.values['build'], build)
self.assertEqual(q.values['tag_id'], tag_id)
'''
q = self.queries[1]
self.assertEqual(q.columns, ['user_id'])
self.assertEqual(q.tables, ['build_notifications_block'])
self.assertEqual(q.clauses, ['user_id IN %(user_ids)s'])
self.assertEqual(q.joins, [])
self.assertEqual(q.values['user_ids'], None)
'''
readPackageList.assert_not_called()
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_build_without_tag(self, readPackageList, get_user):
### with build without tag
tag_id = None
state = koji.BUILD_STATES['CANCELED']
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
self.queries = []
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, ['owner_name@test.domain.com'])
# there should be only query to watchers
self.assertEqual(len(self.queries), 2)
q = self.queries[0]
self.assertEqual(q.columns, ['email', 'user_id'])
self.assertEqual(q.tables, ['build_notifications'])
self.assertEqual(q.clauses, ['package_id = %(package_id)i OR package_id IS NULL',
'status = %(users_status)i',
'success_only = FALSE',
'tag_id IS NULL',
'usertype IN %(users_usertypes)s'])
self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id'])
self.assertEqual(q.values['package_id'], build['package_id'])
self.assertEqual(q.values['state'], state)
self.assertEqual(q.values['build'], build)
self.assertEqual(q.values['tag_id'], tag_id)
q = self.queries[1]
self.assertEqual(q.columns, ['user_id'])
self.assertEqual(q.tables, ['build_notifications_block'])
self.assertEqual(q.clauses, [
'package_id = %(package_id)i OR package_id IS NULL',
'tag_id IS NULL',
'user_id IN %(user_ids)s',
])
self.assertEqual(q.joins, None)
self.assertEqual(q.values['user_ids'], [5])
readPackageList.assert_not_called()
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_tag_without_build(self, readPackageList, get_user):
### with tag without build makes no sense
build = None
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
self.queries = []
with self.assertRaises(koji.GenericError):
kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(self.queries, [])
readPackageList.assert_not_called()
def set_queries(self, return_values):
self.query_returns = return_values
self.query_returns.reverse()
def getQuery(*args, **kwargs):
q = QP(*args, **kwargs)
q.execute = mock.MagicMock()
q.execute.return_value = self.query_returns.pop()
self.queries.append(q)
return q
self.QueryProcessor.side_effect = getQuery
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_tag_with_build(self, readPackageList, get_user):
### with tag and build
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
readPackageList.return_value = {12345: {'blocked': False, 'owner_id': 'owner_id'}}
get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['NORMAL'],
'usertype': koji.USERTYPES['NORMAL']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(sorted(emails), ['owner_name@test.domain.com', 'pkg_owner_name@test.domain.com'])
# there should be only query to watchers
self.assertEqual(len(self.queries), 2)
q = self.queries[0]
self.assertEqual(q.columns, ['email', 'user_id'])
self.assertEqual(q.tables, ['build_notifications'])
self.assertEqual(q.clauses, ['package_id = %(package_id)i OR package_id IS NULL',
'status = %(users_status)i',
'success_only = FALSE',
'tag_id = %(tag_id)i OR tag_id IS NULL',
'usertype IN %(users_usertypes)s',
])
self.assertEqual(q.joins, ['JOIN users ON build_notifications.user_id = users.id'])
self.assertEqual(q.values['package_id'], build['package_id'])
self.assertEqual(q.values['state'], state)
self.assertEqual(q.values['build'], build)
self.assertEqual(q.values['tag_id'], tag_id)
q = self.queries[1]
self.assertEqual(q.columns, ['user_id'])
self.assertEqual(q.tables, ['build_notifications_block'])
self.assertEqual(q.clauses, [
'package_id = %(package_id)i OR package_id IS NULL',
'tag_id = %(tag_id)i OR tag_id IS NULL',
'user_id IN %(user_ids)s',
])
self.assertEqual(q.joins, None)
self.assertEqual(sorted(q.values['user_ids']), [5, 342])
readPackageList.assert_called_once_with(pkgID=build['package_id'], tagID=tag_id, inherit=True)
get_user.asssert_called_once_with(342, strict=True)
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_blocked_pkg_owner(self, readPackageList, get_user):
# blocked package owner
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['BLOCKED'],
'usertype': koji.USERTYPES['NORMAL']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, ['owner_name@test.domain.com'])
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_optout(self, readPackageList, get_user):
# blocked package owner
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['NORMAL'],
'usertype': koji.USERTYPES['NORMAL']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[{'user_id': 5}]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, [])
@mock.patch('kojihub.get_user')
@mock.patch('kojihub.readPackageList')
def test_get_notification_recipients_machine(self, readPackageList, get_user):
# package owner is machine
build = {'package_id': 12345, 'owner_name': 'owner_name', 'owner_id': 5}
tag_id = 123
state = koji.BUILD_STATES['CANCELED']
get_user.return_value = {
'id': 342,
'name': 'pkg_owner_name',
'status': koji.USER_STATUS['NORMAL'],
'usertype': koji.USERTYPES['HOST']
}
self.set_queries([
[{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
[]
])
emails = kojihub.get_notification_recipients(build, tag_id, state)
self.assertEqual(emails, ['owner_name@test.domain.com'])
#####################
# Create notification
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 1
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = {'id': 2, 'name': 'username'}
self.exports.hasPerm.return_value = True
get_package_id.return_value = package_id
get_tag_id.return_value = tag_id
get_build_notifications.return_value = []
r = self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(r, None)
self.exports.getLoggedInUser.assert_called_once()
self.exports.getUser.asssert_called_once_with(user_id)
self.exports.hasPerm.asssert_called_once_with('admin')
get_package_id.assert_called_once_with(package_id, strict=True)
get_tag_id.assert_called_once_with(tag_id, strict=True)
get_build_notifications.assert_called_once_with(2)
self.assertEqual(len(self.inserts), 1)
insert = self.inserts[0]
self.assertEqual(insert.table, 'build_notifications')
self.assertEqual(insert.data, {
'package_id': package_id,
'user_id': 2,
'tag_id': tag_id,
'success_only': success_only,
'email': 'username@test.domain.com',
})
self.assertEqual(insert.rawdata, {})
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification_unauthentized(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 1
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = None
with self.assertRaises(koji.GenericError):
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification_invalid_user(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 2
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = None
with self.assertRaises(koji.GenericError):
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification_no_perm(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 2
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'b'}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError):
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification_invalid_pkg(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 2
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
get_package_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification_invalid_tag(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 2
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
get_package_id.return_value = package_id
get_tag_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotification_exists(self, get_package_id, get_tag_id,
get_build_notifications):
user_id = 2
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
get_package_id.return_value = package_id
get_tag_id.return_value = tag_id
get_build_notifications.return_value = [{
'package_id': package_id,
'tag_id': tag_id,
'success_only': success_only,
}]
with self.assertRaises(koji.GenericError):
self.exports.createNotification(user_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
#####################
# Delete notification
@mock.patch('kojihub._dml')
def test_deleteNotification(self, _dml):
user_id = 752
n_id = 543
self.exports.getBuildNotification.return_value = {'user_id': user_id}
self.exports.deleteNotification(n_id)
self.exports.getBuildNotification.assert_called_once_with(n_id, strict=True)
self.exports.getLoggedInUser.assert_called_once_with()
_dml.assert_called_once()
def test_deleteNotification_missing(self):
n_id = 543
self.exports.getBuildNotification.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.deleteNotification(n_id)
self.exports.getBuildNotification.assert_called_once_with(n_id, strict=True)
def test_deleteNotification_not_logged(self):
user_id = 752
n_id = 543
self.exports.getBuildNotification.return_value = {'user_id': user_id}
self.exports.getLoggedInUser.return_value = None
#self.set_queries = ([
# [{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
#])
with self.assertRaises(koji.GenericError):
self.exports.deleteNotification(n_id)
self.exports.getBuildNotification.assert_called_once_with(n_id, strict=True)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
self.assertEqual(len(self.queries), 0)
@mock.patch('kojihub._dml')
def test_deleteNotification_no_perm(self, _dml):
user_id = 752
n_id = 543
self.exports.getBuildNotification.return_value = {'user_id': user_id}
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError):
self.exports.deleteNotification(n_id)
self.exports.getBuildNotification.assert_called_once_with(n_id, strict=True)
_dml.assert_not_called()
#####################
# Update notification
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_updateNotification(self, get_package_id, get_tag_id,
get_build_notifications):
n_id = 5432
user_id = 1
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = True
get_package_id.return_value = package_id
get_tag_id.return_value = tag_id
get_build_notifications.return_value = [{
'tag_id': tag_id,
'user_id': user_id,
'package_id': package_id,
'success_only': not success_only,
}]
self.exports.getBuildNotification.return_value = {'user_id': user_id}
r = self.exports.updateNotification(n_id, package_id, tag_id, success_only)
self.assertEqual(r, None)
self.exports.getLoggedInUser.assert_called_once()
self.exports.hasPerm.asssert_called_once_with('admin')
get_package_id.assert_called_once_with(package_id, strict=True)
get_tag_id.assert_called_once_with(tag_id, strict=True)
get_build_notifications.assert_called_once_with(user_id)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 1)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_updateNotification_not_logged(self, get_package_id, get_tag_id,
get_build_notifications):
n_id = 5432
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = None
with self.assertRaises(koji.GenericError):
self.exports.updateNotification(n_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_updateNotification_missing(self, get_package_id, get_tag_id,
get_build_notifications):
n_id = 5432
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getBuildNotification.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.updateNotification(n_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_updateNotification_no_perm(self, get_package_id, get_tag_id,
get_build_notifications):
n_id = 5432
user_id = 1
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 132}
self.exports.getBuildNotification.return_value = {'user_id': user_id}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError):
self.exports.updateNotification(n_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_updateNotification_exists(self, get_package_id, get_tag_id,
get_build_notifications):
n_id = 5432
user_id = 1
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = True
get_package_id.return_value = package_id
get_tag_id.return_value = tag_id
get_build_notifications.return_value = [{
'tag_id': tag_id,
'user_id': user_id,
'package_id': package_id,
'success_only': success_only,
}]
self.exports.getBuildNotification.return_value = {'user_id': user_id}
with self.assertRaises(koji.GenericError):
self.exports.updateNotification(n_id, package_id, tag_id, success_only)
self.exports.getLoggedInUser.assert_called_once()
self.exports.hasPerm.asssert_called_once_with('admin')
get_package_id.assert_called_once_with(package_id, strict=True)
get_tag_id.assert_called_once_with(tag_id, strict=True)
get_build_notifications.assert_called_once_with(user_id)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
@mock.patch('kojihub.get_build_notifications')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_updateNotification_not_logged(self, get_package_id, get_tag_id,
get_build_notifications):
n_id = 5432
user_id = 1
package_id = 234
tag_id = 345
success_only = True
self.exports.getLoggedInUser.return_value = None
with self.assertRaises(koji.GenericError):
self.exports.updateNotification(n_id, package_id, tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
###########################
# Create notification block
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 1
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = {'id': 2, 'name': 'username'}
self.exports.hasPerm.return_value = True
get_package_id.return_value = package_id
get_tag_id.return_value = tag_id
get_build_notification_blocks.return_value = []
r = self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(r, None)
self.exports.getLoggedInUser.assert_called_once()
self.exports.getUser.asssert_called_once_with(user_id)
self.exports.hasPerm.asssert_called_once_with('admin')
get_package_id.assert_called_once_with(package_id, strict=True)
get_tag_id.assert_called_once_with(tag_id, strict=True)
get_build_notification_blocks.assert_called_once_with(2)
self.assertEqual(len(self.inserts), 1)
insert = self.inserts[0]
self.assertEqual(insert.table, 'build_notifications_block')
self.assertEqual(insert.data, {
'package_id': package_id,
'user_id': 2,
'tag_id': tag_id,
})
self.assertEqual(insert.rawdata, {})
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock_unauthentized(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 1
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = None
with self.assertRaises(koji.GenericError):
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock_invalid_user(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 2
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getUser.return_value = None
with self.assertRaises(koji.GenericError):
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock_no_perm(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 2
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = {'id': 1, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'b'}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError):
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock_invalid_pkg(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 2
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
get_package_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock_invalid_tag(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 2
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
get_package_id.return_value = package_id
get_tag_id.side_effect = ValueError
with self.assertRaises(ValueError):
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(len(self.inserts), 0)
@mock.patch('kojihub.get_build_notification_blocks')
@mock.patch('kojihub.get_tag_id')
@mock.patch('kojihub.get_package_id')
def test_createNotificationBlock_exists(self, get_package_id, get_tag_id,
get_build_notification_blocks):
user_id = 2
package_id = 234
tag_id = 345
self.exports.getLoggedInUser.return_value = {'id': 2, 'name': 'a'}
self.exports.getUser.return_value = {'id': 2, 'name': 'a'}
get_package_id.return_value = package_id
get_tag_id.return_value = tag_id
get_build_notification_blocks.return_value = [{
'package_id': package_id,
'tag_id': tag_id,
}]
with self.assertRaises(koji.GenericError):
self.exports.createNotificationBlock(user_id, package_id, tag_id)
self.assertEqual(len(self.inserts), 0)
###########################
# Delete notification block
@mock.patch('kojihub._dml')
def test_deleteNotificationBlock(self, _dml):
user_id = 752
n_id = 543
self.exports.getBuildNotificationBlock.return_value = {'user_id': user_id}
self.exports.deleteNotificationBlock(n_id)
self.exports.getBuildNotificationBlock.assert_called_once_with(n_id, strict=True)
self.exports.getLoggedInUser.assert_called_once_with()
_dml.assert_called_once()
def test_deleteNotificationBlock_missing(self):
n_id = 543
self.exports.getBuildNotificationBlock.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.deleteNotificationBlock(n_id)
self.exports.getBuildNotificationBlock.assert_called_once_with(n_id, strict=True)
def test_deleteNotificationBlock_not_logged(self):
user_id = 752
n_id = 543
self.exports.getBuildNotificationBlock.return_value = {'user_id': user_id}
self.exports.getLoggedInUser.return_value = None
#self.set_queries = ([
# [{'user_id': 5, 'email': 'owner_name@%s' % self.context.opts['EmailDomain']}],
#])
with self.assertRaises(koji.GenericError):
self.exports.deleteNotificationBlock(n_id)
self.exports.getBuildNotificationBlock.assert_called_once_with(n_id, strict=True)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
self.assertEqual(len(self.queries), 0)
@mock.patch('kojihub._dml')
def test_deleteNotificationBlock_no_perm2(self, _dml):
user_id = 752
n_id = 543
self.exports.getBuildNotificationBlock.return_value = {'user_id': user_id}
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError):
self.exports.deleteNotificationBlock(n_id)
self.exports.getBuildNotificationBlock.assert_called_once_with(n_id, strict=True)
_dml.assert_not_called()

View file

@ -0,0 +1,13 @@
import unittest
import koji
import kojihub
class TestRepoDelete(unittest.TestCase):
def test_repo_delete_wrong_type_typeID(self):
repo_id = 'test-repo-id'
with self.assertRaises(koji.ParameterError) as cm:
kojihub.repo_delete(repo_id)
self.assertEqual(f"Invalid type for value '{repo_id}': {type(repo_id)}", str(cm.exception))

View file

@ -0,0 +1,13 @@
import unittest
import koji
import kojihub
class TestRepoInit(unittest.TestCase):
def test_repo_init_wrong_type_typeID(self):
task_id = 'test-task_id'
with self.assertRaises(koji.ParameterError) as cm:
kojihub.repo_init('test-tag', task_id)
self.assertEqual(f"Invalid type for value '{task_id}': {type(task_id)}", str(cm.exception))

View file

@ -0,0 +1,13 @@
import unittest
import koji
import kojihub
class TestRepoSetState(unittest.TestCase):
def test_set_state_wrong_type_typeID(self):
repo_id = 'test-repo-id'
with self.assertRaises(koji.ParameterError) as cm:
kojihub.repo_set_state(repo_id, 'failed')
self.assertEqual(f"Invalid type for value '{repo_id}': {type(repo_id)}", str(cm.exception))

View file

@ -26,6 +26,7 @@ class TestRepoFunctions(unittest.TestCase):
self.updates = []
self._dml = mock.patch('kojihub._dml').start()
self.exports = kojihub.RootExports()
self.get_tag = mock.patch('kojihub.get_tag').start()
def tearDown(self):
mock.patch.stopall()
@ -83,7 +84,8 @@ class TestRepoFunctions(unittest.TestCase):
'state': 0,
'task_id': 15,
'create_event': 32,
'creation_time': datetime.datetime(2021, 3, 30, 12, 34, 5, 204023, tzinfo=datetime.timezone.utc),
'creation_time': datetime.datetime(2021, 3, 30, 12, 34, 5, 204023,
tzinfo=datetime.timezone.utc),
'create_ts': 1617107645.204023,
'tag_id': 3,
'tag_name': 'test-tag',
@ -92,8 +94,8 @@ class TestRepoFunctions(unittest.TestCase):
rv = kojihub.repo_info(3)
self.assertEqual(rv, repo_row)
def test_get_repo(self):
rv = self.exports.getRepo(2)
def test_get_repo_default(self):
self.exports.getRepo(2)
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
# make sure the following does not error
@ -105,3 +107,17 @@ class TestRepoFunctions(unittest.TestCase):
self.assertEqual(query.joins, ['events ON repo.create_event = events.id'])
self.assertEqual(query.clauses, ['repo.dist is false', 'repo.state = %(state)s',
'repo.tag_id = %(id)i'])
def test_get_repo_with_dist_and_event(self):
self.exports.getRepo(2, event=111, dist=True)
self.assertEqual(len(self.queries), 1)
query = self.queries[0]
# make sure the following does not error
str(query)
self.assertEqual(query.tables, ['repo'])
columns = ['repo.id', 'repo.state', 'repo.task_id', 'repo.create_event',
'EXTRACT(EPOCH FROM events.time)', 'repo.dist', 'events.time']
self.assertEqual(set(query.columns), set(columns))
self.assertEqual(query.joins, ['events ON repo.create_event = events.id'])
self.assertEqual(query.clauses, ['create_event <= %(event)i', 'repo.dist is true',
'repo.tag_id = %(id)i'])

View file

@ -2,6 +2,7 @@ import unittest
import mock
import koji
import kojihub
@ -13,12 +14,18 @@ class TestRestartHosts(unittest.TestCase):
self.context.session.assertPerm = mock.MagicMock()
self.make_task = mock.patch('kojihub.make_task').start()
def options_is_none(self):
def test_options_is_none(self):
self.make_task.return_value = 13
rv = self.exports.restartHosts()
self.assertEqual(rv, 13)
def options_is_not_none(self):
def test_options_is_not_none(self):
self.make_task.return_value = 13
rv = self.exports.restartHosts(options={'opt': 'open'})
self.assertEqual(rv, 13)
def test_options_wrong_type(self):
options = 'test-options'
with self.assertRaises(koji.ParameterError) as ex:
self.exports.restartHosts(options=options)
self.assertEqual(f"Invalid type of options: {type(options)}", str(ex.exception))

View file

@ -18,4 +18,4 @@ class TestSearch(unittest.TestCase):
type = 'test-type'
with self.assertRaises(koji.GenericError) as cm:
self.exports.search('item', type, 'glob')
self.assertEqual("No such search type: %s" % type, str(cm.exception))
self.assertEqual(f"No such search type: {type}", str(cm.exception))

View file

@ -252,16 +252,22 @@ class TestGetTag(unittest.TestCase):
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
self.tagname = 'test-tag'
def test_get_tag_invalid_taginfo(self):
taginfo = {'test-tag': 'value'}
with self.assertRaises(koji.GenericError) as ex:
kojihub.get_tag(taginfo, strict=True)
self.assertEqual("Invalid name or id value: %s" % taginfo, str(ex.exception))
self.assertEqual(f"Invalid name or id value: {taginfo}", str(ex.exception))
def test_get_tag_non_exist_tag(self):
taginfo = 'test-tag'
self.query_executeOne.return_value = None
with self.assertRaises(koji.GenericError) as ex:
kojihub.get_tag(taginfo, strict=True)
self.assertEqual("No such tagInfo: '%s'" % taginfo, str(ex.exception))
kojihub.get_tag(self.tagname, strict=True)
self.assertEqual(f"No such tagInfo: '{self.tagname}'", str(ex.exception))
def test_get_tag_wrong_event(self):
event = 'unsupported-event'
with self.assertRaises(koji.GenericError) as ex:
kojihub.get_tag(self.tagname, event=event)
self.assertEqual(f"Invalid event: '{event}'", str(ex.exception))

View file

@ -0,0 +1,148 @@
import mock
import unittest
import koji
import kojihub
QP = kojihub.QueryProcessor
IP = kojihub.InsertProcessor
UP = kojihub.UpdateProcessor
class TestUpdateNotifications(unittest.TestCase):
def getInsert(self, *args, **kwargs):
insert = IP(*args, **kwargs)
insert.execute = mock.MagicMock()
self.inserts.append(insert)
return insert
def getQuery(self, *args, **kwargs):
query = QP(*args, **kwargs)
query.execute = mock.MagicMock()
self.queries.append(query)
return query
def getUpdate(self, *args, **kwargs):
update = UP(*args, **kwargs)
update.execute = mock.MagicMock()
self.updates.append(update)
return update
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.context.opts = {
'EmailDomain': 'test.domain.com',
'NotifyOnSuccess': True,
}
self.QueryProcessor = mock.patch('kojihub.QueryProcessor',
side_effect=self.getQuery).start()
self.queries = []
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.get_build_notifications = mock.patch('kojihub.get_build_notifications').start()
self.get_tag_id = mock.patch('kojihub.get_tag_id').start()
self.get_package_id = mock.patch('kojihub.get_package_id').start()
self.exports = kojihub.RootExports()
self.exports.getLoggedInUser = mock.MagicMock()
self.exports.hasPerm = mock.MagicMock()
self.exports.getBuildNotification = mock.MagicMock()
self.user_id = 1
self.n_id = 5432
self.package_id = 234
self.tag_id = 345
def tearDown(self):
mock.patch.stopall()
def test_updateNotification(self):
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = True
self.get_package_id.return_value = self.package_id
self.get_tag_id.return_value = self.tag_id
self.get_build_notifications.return_value = [{
'tag_id': self.tag_id,
'user_id': self.user_id,
'package_id': self.package_id,
'success_only': not success_only,
}]
self.exports.getBuildNotification.return_value = {'user_id': self.user_id}
r = self.exports.updateNotification(self.n_id, self.package_id, self.tag_id, success_only)
self.assertEqual(r, None)
self.exports.getLoggedInUser.assert_called_once()
self.exports.hasPerm.asssert_called_once_with('admin')
self.get_package_id.assert_called_once_with(self.package_id, strict=True)
self.get_tag_id.assert_called_once_with(self.tag_id, strict=True)
self.get_build_notifications.assert_called_once_with(self.user_id)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 1)
def test_updateNotification_not_logged(self):
success_only = True
self.exports.getLoggedInUser.return_value = None
with self.assertRaises(koji.GenericError) as cm:
self.exports.updateNotification(self.n_id, self.package_id, self.tag_id, success_only)
self.assertEqual('Not logged-in', str(cm.exception))
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
def test_updateNotification_missing(self):
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.getBuildNotification.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
self.exports.updateNotification(self.n_id, self.package_id, self.tag_id, success_only)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
def test_updateNotification_no_perm(self):
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 132}
self.exports.getBuildNotification.return_value = {'user_id': self.user_id}
self.exports.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.updateNotification(self.n_id, self.package_id, self.tag_id, success_only)
self.assertEqual(f'user 132 cannot update notifications for user {self.user_id}',
str(cm.exception))
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)
def test_updateNotification_exists(self):
success_only = True
self.exports.getLoggedInUser.return_value = {'id': 1}
self.exports.hasPerm.return_value = True
self.get_package_id.return_value = self.package_id
self.get_tag_id.return_value = self.tag_id
self.get_build_notifications.return_value = [{
'tag_id': self.tag_id,
'user_id': self.user_id,
'package_id': self.package_id,
'success_only': success_only,
}]
self.exports.getBuildNotification.return_value = {'user_id': self.user_id}
with self.assertRaises(koji.GenericError) as cm:
self.exports.updateNotification(self.n_id, self.package_id, self.tag_id, success_only)
self.assertEqual('notification already exists', str(cm.exception))
self.exports.getLoggedInUser.assert_called_once()
self.exports.hasPerm.asssert_called_once_with('admin')
self.get_package_id.assert_called_once_with(self.package_id, strict=True)
self.get_tag_id.assert_called_once_with(self.tag_id, strict=True)
self.get_build_notifications.assert_called_once_with(self.user_id)
self.assertEqual(len(self.inserts), 0)
self.assertEqual(len(self.updates), 0)

View file

@ -0,0 +1,68 @@
import unittest
import koji
import kojihub
import mock
class TestWinBuild(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertLogin = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.get_channel = mock.patch('kojihub.get_channel').start()
self.assert_policy = mock.patch('kojihub.assert_policy').start()
self.get_build_target = mock.patch('kojihub.get_build_target').start()
self.make_task = mock.patch('kojihub.make_task').start()
self.vm = 'test-vm'
self.url = 'https://test-url.com'
self.target = 'test-target'
self.targetinfo = {'build_tag': 444,
'build_tag_name': 'test-tag',
'dest_tag': 445,
'dest_tag_name': 'dest-test-tag',
'id': 1,
'name': self.target}
def tearDown(self):
mock.patch.stopall()
def test_win_not_supported(self):
self.context.opts.get.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.winBuild(self.vm, self.url, self.target)
self.assertEqual("Windows support not enabled", str(cm.exception))
def test_vm_wrong_type(self):
vm = ['test-vm']
self.context.opts.get.return_value = True
with self.assertRaises(koji.GenericError) as cm:
self.exports.winBuild(vm, self.url, self.target)
self.assertEqual(f"Invalid type for value '{vm}': {type(vm)}", str(cm.exception))
def test_url_wrong_type(self):
url = ['test-url']
self.context.opts.get.return_value = True
with self.assertRaises(koji.GenericError) as cm:
self.exports.winBuild(self.vm, url, self.target)
self.assertEqual(f"Invalid type for value '{url}': {type(url)}", str(cm.exception))
def test_priority_without_admin(self):
priority = -10
self.context.opts.get.return_value = True
self.get_build_target.return_value = self.targetinfo
self.assert_policy.return_value = True
self.context.session.hasPerm.return_value = False
with self.assertRaises(koji.GenericError) as cm:
self.exports.winBuild(self.vm, self.url, self.target, priority=priority)
self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
def test_channel_not_str(self):
self.context.opts.get.return_value = True
self.get_build_target.return_value = self.targetinfo
self.assert_policy.return_value = True
self.make_task.return_value = 123
self.get_channel.return_value = {'comment': None, 'description': None, 'enabled': True,
'id': 1, 'name': 'vm'}
self.exports.winBuild(self.vm, self.url, self.target, channel=1, priority=10)

View file

@ -0,0 +1,56 @@
import unittest
import koji
import kojihub
import mock
class TestWrapperRPM(unittest.TestCase):
def setUp(self):
self.context = mock.patch('kojihub.context').start()
self.exports = kojihub.RootExports()
self.context.session.assertLogin = mock.MagicMock()
self.context.session.hasPerm = mock.MagicMock()
self.get_channel = mock.patch('kojihub.get_channel').start()
self.exports.getBuild = mock.MagicMock()
self.make_task = mock.patch('kojihub.make_task').start()
self.list_rpms = mock.patch('kojihub.list_rpms').start()
self.exports.getTag = mock.MagicMock()
self.exports.getBuildTarget = mock.MagicMock()
self.exports.getRepo = mock.MagicMock()
self.build = 'testbuild-1-1.4'
self.target = 'test-target'
self.url = 'https://test-url.com'
self.buildinfo = {'name': 'testbuild', 'version': '1', 'release': '1.4',
'nvr': self.build, 'id': 123}
self.targetinfo = {'build_tag': 444,
'build_tag_name': 'test-tag',
'dest_tag': 445,
'dest_tag_name': 'dest-test-tag',
'id': 1,
'name': self.target}
self.taginfo = {'id': 159, 'name': 'test-tag'}
self.repoinfo = {'id': 753}
def tearDown(self):
mock.patch.stopall()
def test_url_wrong_type(self):
url = ['test-url']
self.context.opts.get.return_value = True
with self.assertRaises(koji.GenericError) as cm:
self.exports.wrapperRPM(self.build, url, self.target)
self.assertEqual(f"Invalid type for value '{url}': {type(url)}", str(cm.exception))
def test_channel_not_str(self):
priority = 10
self.context.opts.get.return_value = True
self.exports.getBuild.return_value = self.buildinfo
self.list_rpms.return_value = []
self.exports.getBuildTarget.return_value = self.targetinfo
self.exports.getRepo.return_value = self.taginfo
self.exports.getRepo.return_value = self.repoinfo
self.make_task.return_value = 123
self.get_channel.return_value = {'comment': None, 'description': None, 'enabled': True,
'id': 2, 'name': 'maven'}
self.exports.wrapperRPM(self.build, self.url, self.target, priority=priority, channel=2)

View file

@ -0,0 +1,23 @@
import unittest
import mock
import koji
import kojihub
class TestWriteSignedRPM(unittest.TestCase):
def setUp(self):
self.get_rpm = mock.patch('kojihub.get_rpm').start()
def tearDown(self):
mock.patch.stopall()
def test_write_signed_rpm_not_internal_rpm(self):
sigkey = 'test-sigkey'
rpm_id = 1
rpminfo = {'external_repo_id': 1, 'external_repo_name': 'test-external-repo'}
self.get_rpm.return_value = rpminfo
with self.assertRaises(koji.GenericError) as cm:
kojihub.write_signed_rpm(rpm_id, sigkey)
self.assertEqual(f"Not an internal rpm: {rpm_id} (from {rpminfo['external_repo_name']})",
str(cm.exception))

View file

@ -48,8 +48,8 @@ class TestRunrootHub(unittest.TestCase):
context.handlers = mock.MagicMock()
context.handlers.call = mock.MagicMock()
context.handlers.call.side_effect = [
{'id': 2, 'name': 'runroot'}, # getChannel
[ # listHosts
{'id': 2, 'name': 'runroot'}, # getChannel
[ # listHosts
{
'arches': 'i386 x86_64',
'capacity': 20.0,
@ -105,8 +105,8 @@ class TestRunrootHub(unittest.TestCase):
context.handlers = mock.MagicMock()
context.handlers.call = mock.MagicMock()
context.handlers.call.side_effect = [
{'id': 2, 'name': 'runroot'}, # getChannel
[ # listHosts
{'id': 2, 'name': 'runroot'}, # getChannel
[ # listHosts
{
'arches': 'i386 x86_64',
'capacity': 20.0,
@ -147,3 +147,31 @@ class TestRunrootHub(unittest.TestCase):
mock.call('listHosts', channelID=2, enabled=True),
])
make_task.assert_not_called()
@mock.patch('kojihub.get_channel')
@mock.patch('kojihub.get_tag')
@mock.patch('kojihub.make_task')
@mock.patch('runroot_hub.context')
def test_non_exist_channel(self, context, make_task, get_tag, get_channel):
context.session.assertPerm = mock.MagicMock()
get_channel.side_effect = koji.GenericError
with self.assertRaises(koji.GenericError):
runroot_hub.runroot(tagInfo='some_tag', arch='x86_64', command='ls',
channel='non-exist-channel')
make_task.assert_not_called()
get_tag.assert_not_called()
@mock.patch('kojihub.get_channel')
@mock.patch('kojihub.get_tag')
@mock.patch('kojihub.make_task')
@mock.patch('runroot_hub.context')
def test_commang_wrong_format(self, context, make_task, get_tag, get_channel):
context.session.assertPerm = mock.MagicMock()
command = ['ls']
with self.assertRaises(koji.GenericError) as ex:
runroot_hub.runroot(tagInfo='some_tag', arch='x86_64', command=command,
channel='non-exist-channel')
self.assertEqual(f"Invalid type for value '{command}': {type(command)}", str(ex.exception))
make_task.assert_not_called()
get_tag.assert_not_called()
get_channel.assert_not_called()

View file

@ -168,6 +168,8 @@ def get_options():
# figure out actions
actions = ('prune', 'trash', 'delete', 'salvage')
if options.action:
if not isinstance(options.action, str):
raise koji.ParameterError('Invalid type of action: %s' % type(options.action))
options.action = options.action.lower().replace(',', ' ').split()
for x in options.action:
if x not in actions:
@ -177,6 +179,9 @@ def get_options():
# split patterns for unprotected keys
if options.unprotected_keys:
if not isinstance(options.unprotected_keys, str):
raise koji.ParameterError('Invalid type of unprotected_keys: %s'
% type(options.unprotected_keys))
options.unprotected_key_patterns = options.unprotected_keys.replace(',', ' ').split()
else:
options.unprotected_key_patterns = []
@ -250,10 +255,15 @@ def check_tag(name):
Returns True if we should process the tag, False otherwise
"""
if options.ignore_tags:
if not isinstance(options.ignore_tags, list):
raise koji.ParameterError('Invalid type of ignore_tags: %s'
% type(options.ignore_tags))
for pattern in options.ignore_tags:
if fnmatch.fnmatch(name, pattern):
return False
if options.tag_filter:
if not isinstance(options.tag_filter, list):
raise koji.ParameterError('Invalid type of tag_filter: %s' % type(options.tag_filter))
for pattern in options.tag_filter:
if fnmatch.fnmatch(name, pattern):
return True
@ -270,6 +280,8 @@ def check_package(name):
Returns True if we should process the package, False otherwise
"""
if options.pkg_filter:
if not isinstance(options.pkg_filter, list):
raise koji.ParameterError('Invalid type of pkg_filter: %s' % type(options.pkg_filter))
for pattern in options.pkg_filter:
if fnmatch.fnmatch(name, pattern):
return True
@ -417,13 +429,21 @@ Build: %%(name)s-%%(version)s-%%(release)s
msg['Subject'] = "1 build marked for deletion"
else:
msg['Subject'] = "%i builds marked for deletion" % len(builds)
if not isinstance(options.from_addr, str):
raise koji.ParameterError('Invalid type of from_addr: %s' % type(options.from_addr))
msg['From'] = options.from_addr
if not isinstance(options.email_domain, str):
raise koji.ParameterError('Invalid type of email_domain: %s' % type(options.email_domain))
msg['To'] = "%s@%s" % (owner_name, options.email_domain) # XXX!
emails = [msg['To']]
if options.cc_addr:
if not isinstance(options.cc_addr, str):
raise koji.ParameterError('Invalid type of cc_addr: %s' % type(options.cc_addr))
msg['Cc'] = ','.join(options.cc_addr)
emails += options.cc_addr
if options.bcc_addr:
if not isinstance(options.bcc_addr, str):
raise koji.ParameterError('Invalid type of bcc_addr: %s' % type(options.bcc_addr))
emails += options.bcc_addr
msg['X-Koji-Builder'] = owner_name
if options.test:
@ -894,6 +914,9 @@ def handle_prune():
bypass = False
if taginfo['locked']:
if options.bypass_locks:
if not isinstance(options.bypass_locks, list):
raise koji.ParameterError('Invalid type of bypass_locks: %s'
% type(options.bypass_locks))
for pattern in options.bypass_locks:
if fnmatch.fnmatch(tagname, pattern):
bypass = True

View file

@ -389,6 +389,8 @@ class TrackedBuild(object):
log("Downloading %s" % url)
# XXX - this is not really the right place for this
resp = request_with_retry().get(url, stream=True)
if not isinstance(options.workpath, str):
raise koji.ParameterError('Invalid type of workpath: %s' % type(options.workpath))
fn = "%s/%s.src.rpm" % (options.workpath, self.nvr)
koji.ensuredir(os.path.dirname(fn))
try:

View file

@ -141,6 +141,11 @@ def activate_session(session):
elif options.keytab and options.principal:
try:
if options.keytab and options.principal:
if not isinstance(options.keytab, str):
raise koji.ParameterError('Invalid type of keytab: %s' % type(options.keytab))
if not isinstance(options.principal, str):
raise koji.ParameterError('Invalid type of principal: %s'
% type(options.principal))
session.gssapi_login(
principal=options.principal,
keytab=options.keytab,