PR#199 CLI plugins

Merges #199
https://pagure.io/koji/pull-request/199
Fixes #193
https://pagure.io/koji/issue/193
This commit is contained in:
Mike McLean 2017-06-16 11:02:21 -04:00
commit 9cfadf7529
43 changed files with 8623 additions and 8167 deletions

View file

@ -66,7 +66,7 @@ git-clean:
test:
coverage erase
PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. coverage run \
PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/.:plugins/cli/.:cli/. coverage run \
--source . /usr/bin/nosetests
coverage report
coverage html
@ -74,7 +74,7 @@ test:
test3:
coverage erase
PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/. coverage3 run \
PYTHONPATH=hub/.:plugins/hub/.:plugins/builder/.:plugins/cli/.:cli/. coverage3 run \
--rcfile .coveragerc3 --source . \
/usr/bin/nosetests-3 \
tests/test_lib tests/test_cli

View file

@ -1,3 +1,12 @@
SUBDIRS=koji_cli
PYTHON=python
PACKAGE = $(shell basename `pwd`)
PYVER := $(shell $(PYTHON) -c 'import sys; print("%.3s" %(sys.version))')
PYSYSDIR := $(shell $(PYTHON) -c 'import sys; print(sys.prefix)')
PYLIBDIR = $(PYSYSDIR)/lib/python$(PYVER)
PKGDIR = $(PYLIBDIR)/site-packages
FILES = koji
_default:
@ -13,7 +22,11 @@ install:
exit 1; \
fi
for d in $(SUBDIRS); do make DESTDIR=$(DESTDIR) \
-C $$d install; [ $$? = 0 ] || exit 1; done
mkdir -p $(DESTDIR)/usr/bin
install -p -m 755 $(FILES) $(DESTDIR)/usr/bin
mkdir -p $(DESTDIR)/etc/koji.conf.d
install -p -m 644 koji.conf $(DESTDIR)/etc/koji.conf
install -p -m 644 koji.conf $(DESTDIR)/etc/koji.conf

7547
cli/koji

File diff suppressed because it is too large Load diff

View file

@ -32,3 +32,6 @@
;certificate of the CA that issued the HTTP server certificate
;serverca = ~/.koji/serverca.crt
;enabled plugins for CLI, runroot and save_failed_tree are available
;plugins =

28
cli/koji_cli/Makefile Normal file
View file

@ -0,0 +1,28 @@
PYFILES = $(wildcard *.py)
PYTHON=python
PACKAGE = $(shell basename `pwd`)
PYVER := $(shell $(PYTHON) -c 'import sys; print("%.3s" % (sys.version))')
PYSYSDIR := $(shell $(PYTHON) -c 'import sys; print(sys.prefix)')
PYLIBDIR = $(PYSYSDIR)/lib/python$(PYVER)
PKGDIR = $(PYLIBDIR)/site-packages/$(PACKAGE)
_default:
@echo "nothing to make. try make install"
clean:
rm -f *.o *.so *.pyc *~
install:
@if [ "$(DESTDIR)" = "" ]; then \
echo " "; \
echo "ERROR: A destdir is required"; \
exit 1; \
fi
mkdir -p $(DESTDIR)/$(PKGDIR)
for p in $(PYFILES) ; do \
install -p -m 644 $$p $(DESTDIR)/$(PKGDIR)/$$p; \
done
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/$(PKGDIR)', 1, '$(PYDIR)', 1)"

0
cli/koji_cli/__init__.py Normal file
View file

6931
cli/koji_cli/commands.py Normal file

File diff suppressed because it is too large Load diff

525
cli/koji_cli/lib.py Normal file
View file

@ -0,0 +1,525 @@
# coding=utf-8
from __future__ import absolute_import
from __future__ import division
import optparse
import os
import random
import six
import socket
import string
import sys
import time
from six.moves import range
try:
import krbV
except ImportError: # pragma: no cover
krbV = None
import koji
# fix OptionParser for python 2.3 (optparse verion 1.4.1+)
# code taken from optparse version 1.5a2
OptionParser = optparse.OptionParser
if optparse.__version__ == "1.4.1+": # pragma: no cover
def _op_error(self, msg):
self.print_usage(sys.stderr)
msg = "%s: error: %s\n" % (self._get_prog_name(), msg)
if msg:
sys.stderr.write(msg)
sys.exit(2)
OptionParser.error = _op_error
greetings = ('hello', 'hi', 'yo', "what's up", "g'day", 'back to work',
'bonjour',
'hallo',
'ciao',
'hola',
u'olá',
u'dobrý den',
u'zdravstvuite',
u'góðan daginn',
'hej',
'tervehdys',
u'grüezi',
u'céad míle fáilte',
u'hylô',
u'bună ziua',
u'jó napot',
'dobre dan',
u'你好',
u'こんにちは',
u'नमस्कार',
u'안녕하세요')
ARGMAP = {'None': None,
'True': True,
'False': False}
def _(args):
"""Stub function for translation"""
return args
def arg_filter(arg):
try:
return int(arg)
except ValueError:
pass
try:
return float(arg)
except ValueError:
pass
if arg in ARGMAP:
return ARGMAP[arg]
#handle lists/dicts?
return arg
categories = {
'admin' : 'admin commands',
'build' : 'build commands',
'search' : 'search commands',
'download' : 'download commands',
'monitor' : 'monitor commands',
'info' : 'info commands',
'bind' : 'bind commands',
'misc' : 'miscellaneous commands',
}
def get_epilog_str(progname=None):
if progname is None:
progname = os.path.basename(sys.argv[0]) or 'koji'
categories_ordered=', '.join(sorted(['all'] + list(categories.keys())))
epilog_str = '''
Try "%(progname)s --help" for help about global options
Try "%(progname)s help" to get all available commands
Try "%(progname)s <command> --help" for help about the options of a particular command
Try "%(progname)s help <category>" to get commands under a particular category
Available categories are: %(categories)s
''' % ({'progname': progname, 'categories': categories_ordered})
return _(epilog_str)
def ensure_connection(session):
try:
ret = session.getAPIVersion()
except six.moves.xmlrpc_client.ProtocolError:
error(_("Error: Unable to connect to server"))
if ret != koji.API_VERSION:
warn(_("WARNING: The server is at API version %d and the client is at %d" % (ret, koji.API_VERSION)))
def print_task_headers():
"""Print the column headers"""
print("ID Pri Owner State Arch Name")
def print_task(task,depth=0):
"""Print a task"""
task = task.copy()
task['state'] = koji.TASK_STATES.get(task['state'],'BADSTATE')
fmt = "%(id)-8s %(priority)-4s %(owner_name)-20s %(state)-8s %(arch)-10s "
if depth:
indent = " "*(depth-1) + " +"
else:
indent = ''
label = koji.taskLabel(task)
print(''.join([fmt % task, indent, label]))
def print_task_recurse(task,depth=0):
"""Print a task and its children"""
print_task(task,depth)
for child in task.get('children',()):
print_task_recurse(child,depth+1)
def parse_arches(arches, to_list=False):
"""Parse comma or space-separated list of arches and return
only space-separated one."""
arches = arches.replace(',', ' ').split()
if to_list:
return arches
else:
return ' '.join(arches)
class TaskWatcher(object):
def __init__(self,task_id,session,level=0,quiet=False):
self.id = task_id
self.session = session
self.info = None
self.level = level
self.quiet = quiet
#XXX - a bunch of this stuff needs to adapt to different tasks
def str(self):
if self.info:
label = koji.taskLabel(self.info)
return "%s%d %s" % (' ' * self.level, self.id, label)
else:
return "%s%d" % (' ' * self.level, self.id)
def __str__(self):
return self.str()
def get_failure(self):
"""Print infomation about task completion"""
if self.info['state'] != koji.TASK_STATES['FAILED']:
return ''
error = None
try:
self.session.getTaskResult(self.id)
except (six.moves.xmlrpc_client.Fault,koji.GenericError) as e:
error = e
if error is None:
# print("%s: complete" % self.str())
# We already reported this task as complete in update()
return ''
else:
return '%s: %s' % (error.__class__.__name__, str(error).strip())
def update(self):
"""Update info and log if needed. Returns True on state change."""
if self.is_done():
# Already done, nothing else to report
return False
last = self.info
self.info = self.session.getTaskInfo(self.id, request=True)
if self.info is None:
if not self.quiet:
print("No such task id: %i" % self.id)
sys.exit(1)
state = self.info['state']
if last:
#compare and note status changes
laststate = last['state']
if laststate != state:
if not self.quiet:
print("%s: %s -> %s" % (self.str(), self.display_state(last), self.display_state(self.info)))
return True
return False
else:
# First time we're seeing this task, so just show the current state
if not self.quiet:
print("%s: %s" % (self.str(), self.display_state(self.info)))
return False
def is_done(self):
if self.info is None:
return False
state = koji.TASK_STATES[self.info['state']]
return (state in ['CLOSED','CANCELED','FAILED'])
def is_success(self):
if self.info is None:
return False
state = koji.TASK_STATES[self.info['state']]
return (state == 'CLOSED')
def display_state(self, info):
# We can sometimes be passed a task that is not yet open, but
# not finished either. info would be none.
if not info:
return 'unknown'
if info['state'] == koji.TASK_STATES['OPEN']:
if info['host_id']:
host = self.session.getHost(info['host_id'])
return 'open (%s)' % host['name']
else:
return 'open'
elif info['state'] == koji.TASK_STATES['FAILED']:
return 'FAILED: %s' % self.get_failure()
else:
return koji.TASK_STATES[info['state']].lower()
def display_tasklist_status(tasks):
free = 0
open = 0
failed = 0
done = 0
for task_id in tasks.keys():
status = tasks[task_id].info['state']
if status == koji.TASK_STATES['FAILED']:
failed += 1
elif status == koji.TASK_STATES['CLOSED'] or status == koji.TASK_STATES['CANCELED']:
done += 1
elif status == koji.TASK_STATES['OPEN'] or status == koji.TASK_STATES['ASSIGNED']:
open += 1
elif status == koji.TASK_STATES['FREE']:
free += 1
print(" %d free %d open %d done %d failed" % (free, open, done, failed))
def display_task_results(tasks):
for task in [task for task in tasks.values() if task.level == 0]:
state = task.info['state']
task_label = task.str()
if state == koji.TASK_STATES['CLOSED']:
print('%s completed successfully' % task_label)
elif state == koji.TASK_STATES['FAILED']:
print('%s failed' % task_label)
elif state == koji.TASK_STATES['CANCELED']:
print('%s was canceled' % task_label)
else:
# shouldn't happen
print('%s has not completed' % task_label)
def watch_tasks(session, tasklist, quiet=False, poll_interval=60):
if not tasklist:
return
if not quiet:
print("Watching tasks (this may be safely interrupted)...")
sys.stdout.flush()
rv = 0
try:
tasks = {}
for task_id in tasklist:
tasks[task_id] = TaskWatcher(task_id,session,quiet=quiet)
while True:
all_done = True
for task_id, task in list(tasks.items()):
changed = task.update()
if not task.is_done():
all_done = False
else:
if changed:
# task is done and state just changed
if not quiet:
display_tasklist_status(tasks)
if not task.is_success():
rv = 1
for child in session.getTaskChildren(task_id):
child_id = child['id']
if not child_id in list(tasks.keys()):
tasks[child_id] = TaskWatcher(child_id, session, task.level + 1, quiet=quiet)
tasks[child_id].update()
# If we found new children, go through the list again,
# in case they have children also
all_done = False
if all_done:
if not quiet:
print('')
display_task_results(tasks)
break
sys.stdout.flush()
time.sleep(poll_interval)
except KeyboardInterrupt:
if tasks and not quiet:
progname = os.path.basename(sys.argv[0]) or 'koji'
tlist = ['%s: %s' % (t.str(), t.display_state(t.info))
for t in tasks.values() if not t.is_done()]
print( \
"""Tasks still running. You can continue to watch with the '%s watch-task' command.
Running Tasks:
%s""" % (progname, '\n'.join(tlist)))
raise
return rv
def watch_logs(session, tasklist, opts, poll_interval):
print("Watching logs (this may be safely interrupted)...")
def _isDone(session, taskId):
info = session.getTaskInfo(taskId)
if info is None:
print("No such task id: %i" % taskId)
sys.exit(1)
state = koji.TASK_STATES[info['state']]
return (state in ['CLOSED','CANCELED','FAILED'])
offsets = {}
for task_id in tasklist:
offsets[task_id] = {}
lastlog = None
while True:
for task_id in tasklist[:]:
if _isDone(session, task_id):
tasklist.remove(task_id)
output = list_task_output_all_volumes(session, task_id)
# convert to list of (file, volume)
files = []
for filename, volumes in six.iteritems(output):
files += [(filename, volume) for volume in volumes]
if opts.log:
logs = [file_volume for file_volume in files if file_volume[0] == opts.log]
else:
logs = [file_volume for file_volume in files if file_volume[0].endswith('log')]
taskoffsets = offsets[task_id]
for log, volume in logs:
contents = 'placeholder'
while contents:
if (log, volume) not in taskoffsets:
taskoffsets[(log, volume)] = 0
contents = session.downloadTaskOutput(task_id, log, taskoffsets[(log, volume)], 16384, volume=volume)
taskoffsets[(log, volume)] += len(contents)
if contents:
currlog = "%d:%s:%s:" % (task_id, volume, log)
if currlog != lastlog:
if lastlog:
sys.stdout.write("\n")
sys.stdout.write("==> %s <==\n" % currlog)
lastlog = currlog
sys.stdout.write(contents.decode('utf8'))
if not tasklist:
break
time.sleep(poll_interval)
def list_task_output_all_volumes(session, task_id):
"""List task output with all volumes, or fake it"""
try:
return session.listTaskOutput(task_id, all_volumes=True)
except koji.GenericError as e:
if 'got an unexpected keyword argument' not in str(e):
raise
# otherwise leave off the option and fake it
output = session.listTaskOutput(task_id)
return dict([fn, ['DEFAULT']] for fn in output)
def _unique_path(prefix):
"""Create a unique path fragment by appending a path component
to prefix. The path component will consist of a string of letter and numbers
that is unlikely to be a duplicate, but is not guaranteed to be unique."""
# Use time() in the dirname to provide a little more information when
# browsing the filesystem.
# For some reason repr(time.time()) includes 4 or 5
# more digits of precision than str(time.time())
return '%s/%r.%s' % (prefix, time.time(),
''.join([random.choice(string.ascii_letters) for i in range(8)]))
def _format_size(size):
if (size / 1073741824 >= 1):
return "%0.2f GiB" % (size / 1073741824.0)
if (size / 1048576 >= 1):
return "%0.2f MiB" % (size / 1048576.0)
if (size / 1024 >=1):
return "%0.2f KiB" % (size / 1024.0)
return "%0.2f B" % (size)
def _format_secs(t):
h = t / 3600
t %= 3600
m = t / 60
s = t % 60
return "%02d:%02d:%02d" % (h, m, s)
def _progress_callback(uploaded, total, piece, time, total_time):
if total == 0:
percent_done = 0.0
else:
percent_done = float(uploaded)/float(total)
percent_done_str = "%02d%%" % (percent_done * 100)
data_done = _format_size(uploaded)
elapsed = _format_secs(total_time)
speed = "- B/sec"
if (time):
if (uploaded != total):
speed = _format_size(float(piece)/float(time)) + "/sec"
else:
speed = _format_size(float(total)/float(total_time)) + "/sec"
# write formated string and flush
sys.stdout.write("[% -36s] % 4s % 8s % 10s % 14s\r" % ('='*(int(percent_done*36)), percent_done_str, elapsed, data_done, speed))
sys.stdout.flush()
def _running_in_bg():
try:
return (not os.isatty(0)) or (os.getpgrp() != os.tcgetpgrp(0))
except OSError:
return True
def linked_upload(localfile, path, name=None):
"""Link a file into the (locally writable) workdir, bypassing upload"""
old_umask = os.umask(0o02)
try:
if name is None:
name = os.path.basename(localfile)
dest_dir = os.path.join(koji.pathinfo.work(), path)
dst = os.path.join(dest_dir, name)
koji.ensuredir(dest_dir)
# fix uid/gid to keep httpd happy
st = os.stat(koji.pathinfo.work())
os.chown(dest_dir, st.st_uid, st.st_gid)
print("Linking rpm to: %s" % dst)
os.link(localfile, dst)
finally:
os.umask(old_umask)
def error(msg=None, code=1):
if msg:
sys.stderr.write(msg + "\n")
sys.stderr.flush()
sys.exit(code)
def warn(msg):
sys.stderr.write(msg + "\n")
sys.stderr.flush()
def has_krb_creds():
if krbV is None:
return False
try:
ctx = krbV.default_context()
ccache = ctx.default_ccache()
ccache.principal()
return True
except krbV.Krb5Error:
return False
def activate_session(session, options):
"""Test and login the session is applicable"""
if options.authtype == "noauth" or options.noauth:
#skip authentication
pass
elif options.authtype == "ssl" or os.path.isfile(options.cert) and options.authtype is None:
# authenticate using SSL client cert
session.ssl_login(options.cert, None, options.serverca, proxyuser=options.runas)
elif options.authtype == "password" or options.user and options.authtype is None:
# authenticate using user/password
session.login()
elif options.authtype == "kerberos" or has_krb_creds() and options.authtype is None:
try:
if options.keytab and options.principal:
session.krb_login(principal=options.principal, keytab=options.keytab, proxyuser=options.runas)
else:
session.krb_login(proxyuser=options.runas)
except socket.error as e:
warn(_("Could not connect to Kerberos authentication service: %s") % e.args[1])
except Exception as e:
if krbV is not None and isinstance(e, krbV.Krb5Error):
error(_("Kerberos authentication failed: %s (%s)") % (e.args[1], e.args[0]))
else:
raise
if not options.noauth and options.authtype != "noauth" and not session.logged_in:
error(_("Unable to log in, no authentication methods available"))
ensure_connection(session)
if options.debug:
print("successfully connected to hub")

View file

@ -188,3 +188,63 @@ tagging a build:
::
$ koji tag-build mytag mypkg-1.0-1
New command for CLI
-------------------
When you add new XMLRPC call or just wanted to do some more complicated
things with API, you can benefit from writing a new command for CLI.
Most simple command would look like this:
::
from koji.plugin import export_cli
@export_cli
def anon_handle_echo(options, session, args):
usage = _("usage: %prog echo <message>")
parser = OptionParser(usage=usage)
(opts, args) = parser.parse_args(args)
print(args[0])
`@export_cli` is decorator which will register plugin's command with name
derived from name of the function. Function name needs to follow one rule: It
has to start with `anon_handle_` or `handle_`. Rest of the name is name of
the command. First one will not authenticate against hub (user can still override
this behaviour with `--force-auth` or `--mine` options where it is relevant)
- it is simply same as using `--noath` option. Second variant doesn't presume
anything about authentication.
Compared to this simple example is real usage with API calls. Koji provides
some important functions via client library `koji_cli.lib` which can be
imported and used inside command's function. Feel free to examine, what is
provided there. Some notable examples are:
* `activate_session(session, options)` - It is needed to authenticate
against hub. Both parameters are same as those passed to handler.
* `watch_tasks(session, tasklist, quiet=False, poll_interval=60)` - It is
the same function used e.g. in `build` command for waiting for spawned
tasks.
* `list_task_output_all_volumes(session, task_id)` - wrapper function for
`listTaskOutput` with different versions of hub.
Final command has to be saved in python system-wide library path - e.g. in
`/usr/lib/python3.4/site-packages/koji_cli_plugins`. Filename doesn't matter
as all files in this directory are searched for `@export_cli` macros. Note,
that python 3 variant of CLI is looking to different directory than python 2
one.
CLI plugins structure will be extended (made configurable and allowing more
than just adding commands - e.g. own authentication methods, etc.) in future.
Pull requests
^^^^^^^^^^^^^
These plugins have to be written in python 2.6+/3.x compatible way. We are
using `six` library to support this, so we will also prefer pull requests
written this way. CLI (and client library) is meant to be fully compatible
with python 3 from koji 1.13.
Tests are also recommended for PR. For example one see
`tests/test_plugins/test_runroot_cli.py`.

View file

@ -93,6 +93,26 @@ Requires: python%{python3_pkgversion}-six
desc
%endif
%package -n python2-%{name}-cli-plugins
Summary: Koji client plugins
Group: Applications/Internet
License: LGPLv2
Requires: %{name} = %{version}-%{release}
%description -n python2-%{name}-cli-plugins
Plugins to the koji command-line interface
%if 0%{with python3}
%package -n python3-%{name}-cli-plugins
Summary: Koji client plugins
Group: Applications/Internet
License: LGPLv2
Requires: %{name} = %{version}-%{release}
%description -n python3-%{name}-cli-plugins
Plugins to the koji command-line interface
%endif
%package hub
Summary: Koji XMLRPC interface
Group: Applications/Internet
@ -257,6 +277,10 @@ make DESTDIR=$RPM_BUILD_ROOT %{?install_opt} install
%if 0%{with python3}
cd koji
make DESTDIR=$RPM_BUILD_ROOT PYTHON=python3 %{?install_opt} install
cd ../cli
make DESTDIR=$RPM_BUILD_ROOT PYTHON=python3 %{?install_opt} install
cd ../plugins
make DESTDIR=$RPM_BUILD_ROOT PYTHON=python3 %{?install_opt} install
# alter python interpreter in koji CLI
sed -i 's/\#\!\/usr\/bin\/python/\#\!\/usr\/bin\/python3/' $RPM_BUILD_ROOT/usr/bin/koji
%endif
@ -274,10 +298,28 @@ rm -rf $RPM_BUILD_ROOT
%files -n python2-%{name}
%defattr(-,root,root)
%{python2_sitelib}/%{name}
%{python2_sitelib}/koji_cli
%if 0%{with python3}
%files -n python%{python3_pkgversion}-koji
%{python3_sitelib}/%{name}
%{python3_sitelib}/koji_cli
%endif
%files -n python2-%{name}-cli-plugins
%defattr(-,root,root)
%{python2_sitelib}/koji_cli_plugins
# we don't have config files for default plugins yet
#%%dir %{_sysconfdir}/koji/plugins
#%%config(noreplace) %{_sysconfdir}/koji/plugins/*.conf
%if 0%{with python3}
%files -n python%{python3_pkgversion}-%{name}-cli-plugins
%defattr(-,root,root)
%{python3_sitelib}/koji_cli_plugins
# we don't have config files for default plugins yet
#%%dir %{_sysconfdir}/koji/plugins
#%%config(noreplace) %{_sysconfdir}/koji/plugins/*.conf
%endif
%files hub

View file

@ -2,7 +2,7 @@ PYTHON=python
PACKAGE = $(shell basename `pwd`)
ifeq ($(PYTHON), python3)
# for python3 we fully support only basic library + CLI
PYFILES = __init__.py util.py
PYFILES = __init__.py util.py plugin.py
PYSCRIPTS =
SUBDIRS =
else

View file

@ -2680,7 +2680,8 @@ class ClientSession(object):
if volume and volume != 'DEFAULT':
dlopts['volume'] = volume
result = self.callMethod('downloadTaskOutput', taskID, fileName, **dlopts)
return base64.decodestring(result)
return base64.decodestring(result.encode('ascii'))
class DBHandler(logging.Handler):
"""

View file

@ -105,6 +105,15 @@ def export(f):
setattr(f, 'exported', True)
return f
def export_cli(f):
"""a decorator that marks a function as exported for CLI
intended to be used by plugins
the HandlerRegistry will export the function under its own name
"""
setattr(f, 'exported_cli', True)
return f
def export_as(alias):
"""returns a decorator that marks a function as exported and gives it an alias

View file

@ -1,10 +1,19 @@
PYTHON=python
PYVER := $(shell $(PYTHON) -c 'import sys; print("%.3s" %(sys.version))')
PYSYSDIR := $(shell $(PYTHON) -c 'import sys; print(sys.prefix)')
PYLIBDIR = $(PYSYSDIR)/lib/python$(PYVER)
PKGDIR = $(PYLIBDIR)/site-packages
CLIPLUGINDIR = $(PKGDIR)/koji_cli_plugins
HUBPLUGINDIR = /usr/lib/koji-hub-plugins
BUILDERPLUGINDIR = /usr/lib/koji-builder-plugins
CLIFILES = $(wildcard cli/*.py)
HUBFILES = $(wildcard hub/*.py)
BUILDERFILES = $(wildcard builder/*.py)
CLICONFDIR = /etc/koji/plugins
HUBCONFDIR = /etc/koji-hub/plugins
BUILDERCONFDIR = /etc/kojid/plugins
CLICONFFILES = $(wildcard cli/*.conf)
HUBCONFFILES = $(wildcard hub/*.conf)
BUILDERCONFFILES = $(wildcard builder/*.conf)
@ -20,14 +29,23 @@ install:
echo "ERROR: A destdir is required"; \
exit 1; \
fi
if [ "$(PYTHON)" == "python" ] ; then \
mkdir -p $(DESTDIR)/$(HUBPLUGINDIR); \
mkdir -p $(DESTDIR)/$(BUILDERPLUGINDIR); \
install -p -m 644 $(HUBFILES) $(DESTDIR)/$(HUBPLUGINDIR); \
install -p -m 644 $(BUILDERFILES) $(DESTDIR)/$(BUILDERPLUGINDIR); \
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/$(HUBPLUGINDIR)', 1, '$(HUBPLUGINDIR)', 1)"; \
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/$(BUILDERPLUGINDIR)', 1, '$(BUILDERPLUGINDIR)', 1)"; \
mkdir -p $(DESTDIR)/$(HUBCONFDIR); \
mkdir -p $(DESTDIR)/$(BUILDERCONFDIR); \
install -p -m 644 $(HUBCONFFILES) $(DESTDIR)/$(HUBCONFDIR); \
install -p -m 644 $(BUILDERCONFFILES) $(DESTDIR)/$(BUILDERCONFDIR); \
fi
mkdir -p $(DESTDIR)/$(HUBPLUGINDIR)
mkdir -p $(DESTDIR)/$(BUILDERPLUGINDIR)
install -p -m 644 $(HUBFILES) $(DESTDIR)/$(HUBPLUGINDIR)
install -p -m 644 $(BUILDERFILES) $(DESTDIR)/$(BUILDERPLUGINDIR)
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/$(HUBPLUGINDIR)', 1, '$(HUBPLUGINDIR)', 1)"
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/$(BUILDERPLUGINDIR)', 1, '$(BUILDERPLUGINDIR)', 1)"
mkdir -p $(DESTDIR)/$(HUBCONFDIR)
mkdir -p $(DESTDIR)/$(BUILDERCONFDIR)
install -p -m 644 $(HUBCONFFILES) $(DESTDIR)/$(HUBCONFDIR)
install -p -m 644 $(BUILDERCONFFILES) $(DESTDIR)/$(BUILDERCONFDIR)
mkdir -p $(DESTDIR)/$(CLIPLUGINDIR)
install -p -m 644 $(CLIFILES) $(DESTDIR)/$(CLIPLUGINDIR)
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/$(CLIPLUGINDIR)', 1, '$(CLIPLUGINDIR)', 1)"
mkdir -p $(DESTDIR)/$(CLICONFDIR)
ifneq "$(CLICONFFILES)" ""
install -p -m 644 $(CLICONFFILES) $(DESTDIR)/$(CLICONFDIR)
endif

84
plugins/cli/runroot.py Normal file
View file

@ -0,0 +1,84 @@
import sys
import time
import koji
from koji.plugin import export_cli
from koji_cli.lib import _, activate_session, OptionParser, list_task_output_all_volumes
@export_cli
def handle_runroot(options, session, args):
"[admin] Run a command in a buildroot"
usage = _("usage: %prog runroot [options] <tag> <arch> <command>")
usage += _("\n(Specify the --help global option for a list of other help options)")
parser = OptionParser(usage=usage)
parser.disable_interspersed_args()
parser.add_option("-p", "--package", action="append", default=[], help=_("make sure this package is in the chroot"))
parser.add_option("-m", "--mount", action="append", default=[], help=_("mount this directory read-write in the chroot"))
parser.add_option("--skip-setarch", action="store_true", default=False,
help=_("bypass normal setarch in the chroot"))
parser.add_option("-w", "--weight", type='int', help=_("set task weight"))
parser.add_option("--channel-override", help=_("use a non-standard channel"))
parser.add_option("--task-id", action="store_true", default=False,
help=_("Print the ID of the runroot task"))
parser.add_option("--use-shell", action="store_true", default=False,
help=_("Run command through a shell, otherwise uses exec"))
parser.add_option("--new-chroot", action="store_true", default=False,
help=_("Run command with the --new-chroot (systemd-nspawn) option to mock"))
parser.add_option("--repo-id", type="int", help=_("ID of the repo to use"))
(opts, args) = parser.parse_args(args)
if len(args) < 3:
parser.error(_("Incorrect number of arguments"))
activate_session(session, options)
tag = args[0]
arch = args[1]
if opts.use_shell:
# everything must be correctly quoted
command = ' '.join(args[2:])
else:
command = args[2:]
try:
kwargs = { 'channel': opts.channel_override,
'packages': opts.package,
'mounts': opts.mount,
'repo_id': opts.repo_id,
'skip_setarch': opts.skip_setarch,
'weight': opts.weight }
# Only pass this kwarg if it is true - this prevents confusing older
# builders with a different function signature
if opts.new_chroot:
kwargs['new_chroot'] = True
task_id = session.runroot(tag, arch, command, **kwargs)
except koji.GenericError as e:
if 'Invalid method' in str(e):
print("* The runroot plugin appears to not be installed on the"
" koji hub. Please contact the administrator.")
raise
if opts.task_id:
print(task_id)
try:
while True:
# wait for the task to finish
if session.taskFinished(task_id):
break
time.sleep(options.poll_interval)
except KeyboardInterrupt:
# this is probably the right thing to do here
print("User interrupt: canceling runroot task")
session.cancelTask(task_id)
raise
output = list_task_output_all_volumes(session, task_id)
if 'runroot.log' in output:
for volume in output['runroot.log']:
log = session.downloadTaskOutput(task_id, 'runroot.log', volume=volume)
sys.stdout.write(log)
info = session.getTaskInfo(task_id)
if info is None:
sys.exit(1)
state = koji.TASK_STATES[info['state']]
if state in ('FAILED', 'CANCELED'):
sys.exit(1)
return

View file

@ -0,0 +1,67 @@
import koji
from koji.plugin import export_cli
from koji_cli.lib import _, activate_session, OptionParser, watch_tasks
@export_cli
def handle_save_failed_tree(options, session, args):
"Create tarball with whole buildtree"
usage = _("usage: %prog save-failed-tree [options] ID")
usage += _("\n(Specify the --help global option for a list of other help options)")
parser = OptionParser(usage=usage)
parser.add_option("-f", "--full", action="store_true", default=False,
help=_("Download whole tree, if not specified, only builddir will be downloaded"))
parser.add_option("-t", "--task", action="store_const", dest="mode",
const="task", default="task",
help=_("Treat ID as a task ID (the default)"))
parser.add_option("-r", "--buildroot", action="store_const", dest="mode",
const="buildroot",
help=_("Treat ID as a buildroot ID"))
parser.add_option("--quiet", action="store_true", default=options.quiet,
help=_("Do not print the task information"))
parser.add_option("--nowait", action="store_true",
help=_("Don't wait on build"))
(opts, args) = parser.parse_args(args)
if len(args) != 1:
parser.error(_("List exactly one task or buildroot ID"))
try:
id_val = int(args[0])
except ValueError:
parser.error(_("ID must be an integer"))
activate_session(session, options)
if opts.mode == "buildroot":
br_id = id_val
else:
brs = [b['id'] for b in session.listBuildroots(taskID=id_val)]
if not brs:
print(_("No buildroots for task %s") % id_val)
return 1
br_id = max(brs)
if len(brs) > 1:
print(_("Multiple buildroots for task. Choosing last one (%s)") % br_id)
try:
task_id = session.saveFailedTree(br_id, opts.full)
except koji.GenericError as e:
m = str(e)
if 'Invalid method' in m:
print(_("* The save_failed_tree plugin appears to not be "
"installed on the koji hub. Please contact the "
"administrator."))
return 1
raise
if not opts.quiet:
print(_("Created task %s for buildroot %s") % (task_id, br_id))
print("Task info: %s/taskinfo?taskID=%s"
% (options.weburl, task_id))
if opts.nowait:
return
else:
session.logout()
watch_tasks(session, [task_id], quiet=opts.quiet, poll_interval=options.poll_interval)

104
split_cli.py Executable file
View file

@ -0,0 +1,104 @@
#!/usr/bin/python
import imp
import inspect
import koji
import os.path
import sys
filename = sys.argv[1]
fo = file(filename)
mod = imp.load_module('some_code', fo, fo.name, ('.py', 'U', 1))
fo.close()
destdir = sys.argv[2]
if not os.path.isdir(destdir):
raise Exception("Not a directory" % destdir)
def get_dest(name, obj):
dest = None
if name in ['get_options', 'handle_help', 'list_commands']:
dest = 'cli/koji'
elif name in ['handle_runroot', 'handle_save_failed_tree']:
dest = 'plugins/cli/' + name[7:] + '.py'
elif name.startswith('handle_') or name.startswith('anon_handle'):
dest = 'cli/koji_cli/commands.py'
elif inspect.isclass(obj):
dest = 'cli/koji_cli/lib.py'
elif name.startswith('print_group_'):
dest = 'cli/koji_cli/commands.py'
elif name.startswith('_import_comps'):
dest = 'cli/koji_cli/commands.py'
elif not name.startswith('_'):
dest = 'cli/koji_cli/lib.py'
elif name in ['_unique_path', '_format_size', '_format_secs',
'_progress_callback', '_running_in_bg', '_']:
dest = 'cli/koji_cli/lib.py'
elif name.startswith('_'):
dest = 'cli/koji_cli/commands.py'
return dest
order = []
modfile = inspect.getsourcefile(mod)
sys.stderr.write("Module file: %r\n" % modfile)
for name in vars(mod):
obj = getattr(mod, name)
if inspect.isclass(obj) or inspect.isfunction(obj):
try:
objfile = inspect.getsourcefile(obj)
except TypeError as ex:
sys.stderr.write("Skipping %s from %s\n" % (name, obj))
continue
if objfile != modfile:
sys.stderr.write("Skipping %s from %s\n" % (name, inspect.getfile(obj)))
continue
data = inspect.getsourcelines(obj)
lineno = data[1]
order.append((lineno, data[0], name, obj))
dests = set()
for (lineno, source, name, obj) in sorted(order):
dest = get_dest(name, obj)
dests.add(dest)
outfiles = {}
for dest in dests:
if dest:
fn = os.path.join(destdir, dest)
outfiles[dest] = file(fn, 'w')
orig = file(filename).readlines()
ofs = 0
last_dest = None
for (lineno, source, name, obj) in sorted(order):
lineno -= 1 # make 0-indexed
dest = get_dest(name, obj)
if dest is None:
# the _ functions go different places
# defer (treat as intermediate content)
continue
if lineno > ofs:
# intermediate content
if last_dest == dest:
fo = outfiles[dest]
else:
fo = outfiles['cli/koji']
for line in orig[ofs:lineno]:
fo.write(line)
fo = outfiles[dest]
for line in source:
fo.write(line)
ofs = lineno + len(source)
last_dest = dest
sys.stderr.write('Orig: %i lines, ofs: %i\n' % (len(orig), ofs))
if len(orig) > ofs:
sys.stderr.write('Writing tail\n')
fo = outfiles['cli/koji']
for line in orig[ofs:]:
fo.write(line)
for dest in outfiles:
outfiles[dest].close()
open('cli/koji_cli/__init__.py', 'a+').close()

View file

@ -51,7 +51,6 @@ admin commands:
restart-hosts Restart enabled hosts
revoke-cg-access Remove a user from a content generator
revoke-permission Revoke a permission from a user
runroot Run a command in a buildroot
set-build-volume Move a build to a different volume
set-pkg-arches Set the list of extra arches for a package
set-pkg-owner Set the owner for a package

View file

@ -51,7 +51,6 @@ admin commands:
restart-hosts Restart enabled hosts
revoke-cg-access Remove a user from a content generator
revoke-permission Revoke a permission from a user
runroot Run a command in a buildroot
set-build-volume Move a build to a different volume
set-pkg-arches Set the list of extra arches for a package
set-pkg-owner Set the owner for a package
@ -121,7 +120,6 @@ miscellaneous commands:
dist-repo Create a yum repo with distribution options
import-comps Import group/package information from a comps file
moshimoshi Introduce yourself
save-failed-tree Create tarball with whole buildtree
monitor commands:
wait-repo Wait for a repo to be regenerated

View file

@ -1,18 +1,14 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_add_group
class TestAddGroup(unittest.TestCase):
@ -20,7 +16,7 @@ class TestAddGroup(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_group(self, activate_session_mock, stdout):
tag = 'tag'
group = 'group'
@ -35,13 +31,13 @@ class TestAddGroup(unittest.TestCase):
{'name': 'otherGroup', 'group_id': 'otherGroupId'}]
# Run it and check immediate output
rv = cli.handle_add_group(options, session, arguments)
rv = handle_add_group(options, session, arguments)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.hasPerm.assert_called_once_with('admin')
session.getTag.assert_called_once_with(tag)
session.getTagGroups.assert_called_once_with(tag, inherit=False)
@ -49,7 +45,7 @@ class TestAddGroup(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_group_dupl(self, activate_session_mock, stdout):
tag = 'tag'
group = 'group'
@ -64,13 +60,13 @@ class TestAddGroup(unittest.TestCase):
{'name': 'group', 'group_id': 'groupId'}]
# Run it and check immediate output
rv = cli.handle_add_group(options, session, arguments)
rv = handle_add_group(options, session, arguments)
actual = stdout.getvalue()
expected = 'Group group already exists for tag tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.hasPerm.assert_called_once_with('admin')
session.getTag.assert_called_once_with(tag)
session.getTagGroups.assert_called_once_with(tag, inherit=False)
@ -79,7 +75,7 @@ class TestAddGroup(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_group_help(
self,
activate_session_mock,
@ -93,7 +89,7 @@ class TestAddGroup(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
rv = cli.handle_add_group(options, session, arguments)
rv = handle_add_group(options, session, arguments)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -115,7 +111,7 @@ class TestAddGroup(unittest.TestCase):
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_group_no_perm(self, activate_session_mock, stdout):
tag = 'tag'
group = 'group'
@ -127,13 +123,13 @@ class TestAddGroup(unittest.TestCase):
session.hasPerm.return_value = False
# Run it and check immediate output
rv = cli.handle_add_group(options, session, arguments)
rv = handle_add_group(options, session, arguments)
actual = stdout.getvalue()
expected = 'This action requires admin privileges\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.hasPerm.assert_called_once_with('admin')
session.getTag.assert_not_called()
session.getTagGroups.assert_not_called()
@ -141,7 +137,7 @@ class TestAddGroup(unittest.TestCase):
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_group_no_tag(self, activate_session_mock, stdout):
tag = 'tag'
group = 'group'
@ -154,13 +150,13 @@ class TestAddGroup(unittest.TestCase):
session.getTag.return_value = None
# Run it and check immediate output
rv = cli.handle_add_group(options, session, arguments)
rv = handle_add_group(options, session, arguments)
actual = stdout.getvalue()
expected = 'Unknown tag: tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.hasPerm.assert_called_once_with('admin')
session.getTag.assert_called_once_with(tag)
session.getTagGroups.assert_not_called()

View file

@ -1,15 +1,11 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_add_host
class TestAddHost(unittest.TestCase):
@ -17,7 +13,7 @@ class TestAddHost(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host(self, activate_session_mock, stdout):
host = 'host'
host_id = 1
@ -36,18 +32,18 @@ class TestAddHost(unittest.TestCase):
# Run it and check immediate output
# args: host, arch1, arch2, --krb-principal=krb
# expected: success
rv = cli.handle_add_host(options, session, arguments)
rv = handle_add_host(options, session, arguments)
actual = stdout.getvalue()
expected = 'host added: id 1\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.addHost.assert_called_once_with(host, arches, **kwargs)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_no_krb_principal(
self, activate_session_mock, stdout):
host = 'host'
@ -63,18 +59,18 @@ class TestAddHost(unittest.TestCase):
# Run it and check immediate output
# args: host, arch1, arch2
# expected: success
rv = cli.handle_add_host(options, session, arguments)
rv = handle_add_host(options, session, arguments)
actual = stdout.getvalue()
expected = 'host added: id 1\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.addHost.assert_called_once_with(host, arches)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_dupl(self, activate_session_mock, stdout):
host = 'host'
host_id = 1
@ -90,19 +86,19 @@ class TestAddHost(unittest.TestCase):
# Run it and check immediate output
# args: host, arch1, arch2, --krb-principal=krb
# expected: failed, host already exists
rv = cli.handle_add_host(options, session, arguments)
rv = handle_add_host(options, session, arguments)
actual = stdout.getvalue()
expected = 'host is already in the database\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.addHost.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_help(self, activate_session_mock, stderr, stdout):
arguments = []
options = mock.MagicMock()
@ -113,7 +109,7 @@ class TestAddHost(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_add_host(options, session, arguments)
handle_add_host(options, session, arguments)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -132,7 +128,7 @@ class TestAddHost(unittest.TestCase):
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_failed(self, activate_session_mock, stdout):
host = 'host'
arches = ['arch1', 'arch2']
@ -150,12 +146,12 @@ class TestAddHost(unittest.TestCase):
# Run it and check immediate output
# args: host, arch1, arch2, --krb-principal=krb
# expected: failed
cli.handle_add_host(options, session, arguments)
handle_add_host(options, session, arguments)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.addHost.assert_called_once_with(host, arches, **kwargs)

View file

@ -1,15 +1,12 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_add_host_to_channel
class TestAddHostToChannel(unittest.TestCase):
@ -17,7 +14,7 @@ class TestAddHostToChannel(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_to_channel(self, activate_session_mock, stdout):
host = 'host'
host_info = mock.ANY
@ -34,19 +31,19 @@ class TestAddHostToChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel
# expected: success
rv = cli.handle_add_host_to_channel(options, session, args)
rv = handle_add_host_to_channel(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(channel)
session.getHost.assert_called_once_with(host)
session.addHostToChannel.assert_called_once_with(host, channel)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_to_channel_list(
self, activate_session_mock, stdout):
list_arg = '--list'
@ -61,12 +58,12 @@ class TestAddHostToChannel(unittest.TestCase):
# Run it and check immediate output
# args: --list
# expected: list all channel names
rv = cli.handle_add_host_to_channel(options, session, args)
rv = handle_add_host_to_channel(options, session, args)
actual = stdout.getvalue()
expected = 'channel1\nchannel2\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.listChannels.assert_called_once()
session.getChannel.assert_not_called()
session.getHost.assert_not_called()
@ -74,7 +71,7 @@ class TestAddHostToChannel(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_to_channel_new(
self, activate_session_mock, stdout):
host = 'host'
@ -92,12 +89,12 @@ class TestAddHostToChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel, --new
# expected: success
rv = cli.handle_add_host_to_channel(options, session, args)
rv = handle_add_host_to_channel(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_not_called()
session.getHost.assert_called_once_with(host)
session.addHostToChannel.assert_called_once_with(
@ -105,7 +102,7 @@ class TestAddHostToChannel(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_to_channel_no_channel(
self, activate_session_mock, stdout):
host = 'host'
@ -121,19 +118,19 @@ class TestAddHostToChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel
# expected: failed, channel not found
rv = cli.handle_add_host_to_channel(options, session, args)
rv = handle_add_host_to_channel(options, session, args)
actual = stdout.getvalue()
expected = 'No such channel: channel\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(channel)
session.getHost.assert_not_called()
session.addHostToChannel.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_to_channel_no_host(
self, activate_session_mock, stdout):
host = 'host'
@ -151,12 +148,12 @@ class TestAddHostToChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel
# expected: success
rv = cli.handle_add_host_to_channel(options, session, args)
rv = handle_add_host_to_channel(options, session, args)
actual = stdout.getvalue()
expected = 'No such host: host\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(channel)
session.getHost.assert_called_once_with(host)
session.addHostToChannel.assert_not_called()
@ -164,7 +161,7 @@ class TestAddHostToChannel(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_host_to_channel_help(
self, activate_session_mock, stderr, stdout):
args = []
@ -178,7 +175,7 @@ class TestAddHostToChannel(unittest.TestCase):
# args: _empty_
# expected: failed, help msg shows
with self.assertRaises(SystemExit) as cm:
cli.handle_add_host_to_channel(options, session, args)
handle_add_host_to_channel(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,16 +1,14 @@
from __future__ import absolute_import
import unittest
import os
import sys
import mock
import os
import six
import sys
import unittest
from mock import call
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_add_pkg
class TestAddPkg(unittest.TestCase):
@ -19,7 +17,7 @@ class TestAddPkg(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_pkg(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -49,12 +47,12 @@ class TestAddPkg(unittest.TestCase):
# Run it and check immediate output
# args: --owner, --extra-arches='arch1,arch2 arch3, arch4', tag, package
# expected: success
rv = cli.handle_add_pkg(options, session, args)
rv = handle_add_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'Adding 1 packages to tag tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getUser.assert_called_once_with(owner)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_called_once_with(tagID=dsttag['id'])
@ -64,7 +62,7 @@ class TestAddPkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_pkg_multi_pkg(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -92,12 +90,12 @@ class TestAddPkg(unittest.TestCase):
# args: --owner, --extra-arches='arch1,arch2 arch3, arch4',
# tag, package1, package2, package3
# expected: success
rv = cli.handle_add_pkg(options, session, args)
rv = handle_add_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'Package package2 already exists in tag tag\nAdding 2 packages to tag tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
self.assertEqual(session.mock_calls,
[call.getUser(owner),
call.getTag(tag),
@ -108,7 +106,7 @@ class TestAddPkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_pkg_owner_no_exists(
self, activate_session_mock, stdout):
tag = 'tag'
@ -130,7 +128,7 @@ class TestAddPkg(unittest.TestCase):
# args: --owner, --extra-arches='arch1,arch2 arch3, arch4',
# tag, package1, package2, package3
# expected: failed: owner does not exist
rv = cli.handle_add_pkg(options, session, args)
rv = handle_add_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'User owner does not exist\n'
self.assertMultiLineEqual(actual, expected)
@ -141,7 +139,7 @@ class TestAddPkg(unittest.TestCase):
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_pkg_tag_no_exists(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = None
@ -165,12 +163,12 @@ class TestAddPkg(unittest.TestCase):
# tag, package1, package2, package3
# expected: failed: tag does not exist
with self.assertRaises(SystemExit) as cm:
cli.handle_add_pkg(options, session, args)
handle_add_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'No such tag: tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
self.assertEqual(session.mock_calls,
[call.getUser(owner),
call.getTag(tag)])
@ -178,7 +176,7 @@ class TestAddPkg(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_pkg_no_owner(
self, activate_session_mock, stderr, stdout):
tag = 'tag'
@ -194,7 +192,7 @@ class TestAddPkg(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_add_pkg(options, session, args)
handle_add_pkg(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -216,7 +214,7 @@ class TestAddPkg(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_add_pkg_no_arg(
self, activate_session_mock, stderr, stdout):
args = []
@ -228,7 +226,7 @@ class TestAddPkg(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_add_pkg(options, session, args)
handle_add_pkg(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,16 +1,13 @@
from __future__ import absolute_import
import unittest
import os
import sys
import mock
import os
import six
import sys
import unittest
from mock import call
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_block_pkg
class TestBlockPkg(unittest.TestCase):
@ -19,7 +16,7 @@ class TestBlockPkg(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_block_pkg(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -36,12 +33,12 @@ class TestBlockPkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package
# expected: success
rv = cli.handle_block_pkg(options, session, args)
rv = handle_block_pkg(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_called_once_with(
tagID=dsttag['id'], inherited=True)
@ -51,7 +48,7 @@ class TestBlockPkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_block_pkg_multi_pkg(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -72,12 +69,12 @@ class TestBlockPkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package1, package2, package3
# expected: success
rv = cli.handle_block_pkg(options, session, args)
rv = handle_block_pkg(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
self.assertEqual(
session.mock_calls, [
call.getTag(tag), call.listPackages(
@ -89,7 +86,7 @@ class TestBlockPkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_block_pkg_no_package(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -108,12 +105,12 @@ class TestBlockPkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package1, package2, package3
# expected: failed: can not find package2 under tag
rv = cli.handle_block_pkg(options, session, args)
rv = handle_block_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'Package package2 doesn\'t exist in tag tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_called_once_with(
tagID=dsttag['id'], inherited=True)
@ -122,7 +119,7 @@ class TestBlockPkg(unittest.TestCase):
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_block_pkg_tag_no_exists(
self, activate_session_mock, stdout):
tag = 'tag'
@ -138,12 +135,12 @@ class TestBlockPkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package1, package2, package3
# expected: failed: tag does not exist
rv = cli.handle_block_pkg(options, session, args)
rv = handle_block_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'No such tag: tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_not_called()
session.packageListBlock.assert_not_called()
@ -151,7 +148,7 @@ class TestBlockPkg(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_block_pkg_help(
self, activate_session_mock, stderr, stdout):
args = []
@ -164,7 +161,7 @@ class TestBlockPkg(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_block_pkg(options, session, args)
handle_block_pkg(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,15 +1,11 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_build, _progress_callback
class TestBuild(unittest.TestCase):
# Show long diffs in error output...
@ -20,14 +16,15 @@ class TestBuild(unittest.TestCase):
self.options = mock.MagicMock()
self.options.quiet = None
self.options.weburl = 'weburl'
self.options.poll_interval = 0
# Mock out the xmlrpc server
self.session = mock.MagicMock()
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_from_srpm(
self,
watch_tasks_mock,
@ -51,7 +48,7 @@ class TestBuild(unittest.TestCase):
# Run it and check immediate output
# args: target, srpm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Uploading srpm: srpm
@ -60,25 +57,26 @@ Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_called_once_with('cli-build')
self.assertEqual(running_in_bg_mock.call_count, 2)
self.session.uploadWrapper.assert_called_once_with(
source, 'random_path', callback=cli._progress_callback)
source, 'random_path', callback=_progress_callback)
self.session.build.assert_called_once_with(
'random_path/' + source, target, opts, priority=priority)
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_from_scm(
self,
watch_tasks_mock,
@ -102,14 +100,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target, http://scm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_not_called()
@ -119,15 +117,16 @@ Task info: weburl/taskinfo?taskID=1
source, target, opts, priority=priority)
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_no_arg(
self,
watch_tasks_mock,
@ -141,7 +140,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_build(self.options, self.session, args)
handle_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -167,10 +166,10 @@ Task info: weburl/taskinfo?taskID=1
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_help(
self,
watch_tasks_mock,
@ -184,7 +183,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_build(self.options, self.session, args)
handle_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = """Usage: %s build [options] target <srpm path or scm url>
@ -221,10 +220,10 @@ Options:
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_arch_override_denied(
self,
watch_tasks_mock,
@ -241,7 +240,7 @@ Options:
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_build(self.options, self.session, args)
handle_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -266,10 +265,10 @@ Options:
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_none_tag(
self,
watch_tasks_mock,
@ -289,14 +288,14 @@ Options:
# Run it and check immediate output
# args: --repo-id=2, nOne, http://scm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_not_called()
self.session.getTag.assert_not_called()
unique_path_mock.assert_not_called()
@ -307,14 +306,15 @@ Task info: weburl/taskinfo?taskID=1
source, None, opts, priority=priority)
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_target_not_found(
self,
watch_tasks_mock,
@ -334,7 +334,7 @@ Task info: weburl/taskinfo?taskID=1
# args: target, http://scm
# expected: failed, target not found
with self.assertRaises(SystemExit) as cm:
cli.handle_build(self.options, self.session, args)
handle_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s build [options] target <srpm path or scm url>
(Specify the --help global option for a list of other help options)
@ -343,7 +343,7 @@ Task info: weburl/taskinfo?taskID=1
""" % (progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_not_called()
unique_path_mock.assert_not_called()
@ -355,10 +355,10 @@ Task info: weburl/taskinfo?taskID=1
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_dest_tag_not_found(
self,
watch_tasks_mock,
@ -382,7 +382,7 @@ Task info: weburl/taskinfo?taskID=1
# args: target, http://scm
# expected: failed, dest_tag not found
with self.assertRaises(SystemExit) as cm:
cli.handle_build(self.options, self.session, args)
handle_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s build [options] target <srpm path or scm url>
(Specify the --help global option for a list of other help options)
@ -391,7 +391,7 @@ Task info: weburl/taskinfo?taskID=1
""" % (progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_not_called()
@ -403,10 +403,10 @@ Task info: weburl/taskinfo?taskID=1
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_dest_tag_locked(
self,
watch_tasks_mock,
@ -430,7 +430,7 @@ Task info: weburl/taskinfo?taskID=1
# args: target, http://scm
# expected: failed, dest_tag is locked
with self.assertRaises(SystemExit) as cm:
cli.handle_build(self.options, self.session, args)
handle_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s build [options] target <srpm path or scm url>
(Specify the --help global option for a list of other help options)
@ -439,7 +439,7 @@ Task info: weburl/taskinfo?taskID=1
""" % (progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_not_called()
@ -451,10 +451,10 @@ Task info: weburl/taskinfo?taskID=1
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_arch_override(
self,
watch_tasks_mock,
@ -484,14 +484,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --arch-override=somearch, --scratch, target, http://scm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_not_called()
@ -502,14 +502,15 @@ Task info: weburl/taskinfo?taskID=1
source, target, opts, priority=priority)
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_background(
self,
watch_tasks_mock,
@ -533,14 +534,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --background, target, http://scm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_not_called()
@ -550,14 +551,15 @@ Task info: weburl/taskinfo?taskID=1
source, target, opts, priority=priority)
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=True)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=True)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_running_in_bg(
self,
watch_tasks_mock,
@ -581,7 +583,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target, srpm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Uploading srpm: srpm
@ -590,7 +592,7 @@ Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_called_once_with('cli-build')
@ -605,10 +607,10 @@ Task info: weburl/taskinfo?taskID=1
self.assertIsNone(rv)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_noprogress(
self,
watch_tasks_mock,
@ -632,7 +634,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --noprogress, target, srpm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Uploading srpm: srpm
@ -641,7 +643,7 @@ Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_called_once_with('cli-build')
@ -653,14 +655,15 @@ Task info: weburl/taskinfo?taskID=1
'random_path/' + source, target, opts, priority=priority)
self.session.logout.assert_called_once()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_quiet(
self,
watch_tasks_mock,
@ -685,12 +688,12 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --quiet, target, srpm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = '\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_called_once_with('cli-build')
@ -702,14 +705,15 @@ Task info: weburl/taskinfo?taskID=1
'random_path/' + source, target, opts, priority=priority)
self.session.logout.assert_called_once()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=quiet)
self.session, [task_id], quiet=quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_wait(
self,
watch_tasks_mock,
@ -734,7 +738,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --wait, target, srpm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Uploading srpm: srpm
@ -743,26 +747,27 @@ Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_called_once_with('cli-build')
# the second one won't be executed when wait==False
self.assertEqual(running_in_bg_mock.call_count, 1)
self.session.uploadWrapper.assert_called_once_with(
source, 'random_path', callback=cli._progress_callback)
source, 'random_path', callback=_progress_callback)
self.session.build.assert_called_once_with(
'random_path/' + source, target, opts, priority=priority)
self.session.logout.assert_called_once()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._unique_path', return_value='random_path')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._unique_path', return_value='random_path')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_nowait(
self,
watch_tasks_mock,
@ -786,7 +791,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --nowait, target, srpm
# expected: success
rv = cli.handle_build(self.options, self.session, args)
rv = handle_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Uploading srpm: srpm
@ -795,14 +800,14 @@ Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag)
unique_path_mock.assert_called_once_with('cli-build')
# the second one won't be executed when wait==False
self.assertEqual(running_in_bg_mock.call_count, 1)
self.session.uploadWrapper.assert_called_once_with(
source, 'random_path', callback=cli._progress_callback)
source, 'random_path', callback=_progress_callback)
self.session.build.assert_called_once_with(
'random_path/' + source, target, opts, priority=priority)
self.session.logout.assert_not_called()

View file

@ -1,15 +1,12 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_chain_build
class TestChainBuild(unittest.TestCase):
# Show long diffs in error output...
@ -20,13 +17,14 @@ class TestChainBuild(unittest.TestCase):
self.options = mock.MagicMock()
self.options.quiet = None
self.options.weburl = 'weburl'
self.options.poll_interval = 0
# Mock out the xmlrpc server
self.session = mock.MagicMock()
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build(self, watch_tasks_mock, running_in_bg_mock,
activate_session_mock, stdout):
target = 'target'
@ -63,14 +61,14 @@ class TestChainBuild(unittest.TestCase):
# Run it and check immediate output
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: success
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_called_once_with(build_tag_id)
@ -79,14 +77,15 @@ Task info: weburl/taskinfo?taskID=1
running_in_bg_mock.assert_called_once()
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_no_arg(
self,
watch_tasks_mock,
@ -99,7 +98,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -124,9 +123,9 @@ Task info: weburl/taskinfo?taskID=1
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_help(
self,
watch_tasks_mock,
@ -139,7 +138,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = """Usage: %s chain-build [options] target URL [URL2 [:] URL3 [:] URL4 ...]
@ -167,9 +166,9 @@ Options:
self.assertEqual(cm.exception.code, 0)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_target_not_found(
self,
watch_tasks_mock,
@ -196,7 +195,7 @@ Options:
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed, target not found
with self.assertRaises(SystemExit) as cm:
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s chain-build [options] target URL [URL2 [:] URL3 [:] URL4 ...]
(Specify the --help global option for a list of other help options)
@ -205,7 +204,7 @@ Options:
""" % (progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_not_called()
self.session.getFullInheritance.assert_not_called()
@ -216,9 +215,9 @@ Options:
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_dest_tag_locked(
self,
watch_tasks_mock,
@ -255,7 +254,7 @@ Options:
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed, dest_tag is locked
with self.assertRaises(SystemExit) as cm:
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s chain-build [options] target URL [URL2 [:] URL3 [:] URL4 ...]
(Specify the --help global option for a list of other help options)
@ -264,7 +263,7 @@ Options:
""" % (progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_not_called()
@ -275,9 +274,9 @@ Options:
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_dest_tag_not_inherited_by_build_tag(
self, watch_tasks_mock, running_in_bg_mock, activate_session_mock, stdout):
target = 'target'
@ -310,14 +309,14 @@ Options:
# Run it and check immediate output
# args: target, target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed, dest_tag is not in build_tag's inheritance
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Packages in destination tag dest_tag are not inherited by build tag build_tag
Target target is not usable for a chain-build
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_called_once_with(build_tag_id)
@ -327,9 +326,9 @@ Target target is not usable for a chain-build
watch_tasks_mock.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_invalidated_src(
self,
watch_tasks_mock,
@ -365,12 +364,12 @@ Target target is not usable for a chain-build
# Run it and check immediate output
# args: target badnvr : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed, src is neither scm nor good n-v-r
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = '"badnvr" is not a SCM URL or package N-V-R\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(
dest_tag_id, strict=True)
@ -395,7 +394,7 @@ Target target is not usable for a chain-build
args = [target] + source_args
# args: target path/n-v-r : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = '"path/n-v-r" is not a SCM URL or package N-V-R\n'
self.assertMultiLineEqual(actual, expected)
@ -413,7 +412,7 @@ Target target is not usable for a chain-build
args = [target] + source_args
# args: target badn-vr : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = '"badn-vr" is not a SCM URL or package N-V-R\n'
self.assertMultiLineEqual(actual, expected)
@ -431,7 +430,7 @@ Target target is not usable for a chain-build
args = [target] + source_args
# args: target badn-v-r.rpm : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: failed
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = '"badn-v-r.rpm" is not a SCM URL or package N-V-R\n'
self.assertMultiLineEqual(actual, expected)
@ -445,7 +444,7 @@ Target target is not usable for a chain-build
# args: target http://scm
# expected: failed, only one src found
with self.assertRaises(SystemExit) as cm:
cli.handle_chain_build(self.options, self.session, args)
handle_chain_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s chain-build [options] target URL [URL2 [:] URL3 [:] URL4 ...]
(Specify the --help global option for a list of other help options)
@ -457,9 +456,9 @@ If there are no dependencies, use the build command instead
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_background(
self,
watch_tasks_mock,
@ -500,14 +499,14 @@ If there are no dependencies, use the build command instead
# Run it and check immediate output
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: success
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_called_once_with(build_tag_id)
@ -516,13 +515,14 @@ Task info: weburl/taskinfo?taskID=1
running_in_bg_mock.assert_called_once()
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_quiet(
self,
watch_tasks_mock,
@ -564,12 +564,12 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: success
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_called_once_with(build_tag_id)
@ -578,13 +578,14 @@ Task info: weburl/taskinfo?taskID=1
running_in_bg_mock.assert_called_once()
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=True)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=True)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_running_in_bg(
self,
watch_tasks_mock,
@ -625,14 +626,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: success
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_called_once_with(build_tag_id)
@ -644,9 +645,9 @@ Task info: weburl/taskinfo?taskID=1
self.assertIsNone(rv)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_chain_build_nowait(
self,
watch_tasks_mock,
@ -687,14 +688,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target http://scm1 : http://scm2 http://scm3 n-v-r-1 : n-v-r-2 n-v-r-3
# expected: success
rv = cli.handle_chain_build(self.options, self.session, args)
rv = handle_chain_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id, strict=True)
self.session.getFullInheritance.assert_called_once_with(build_tag_id)

View file

@ -1,16 +1,12 @@
from __future__ import absolute_import
import unittest
import os
import sys
import mock
import os
import six
import sys
import unittest
from mock import call
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_edit_host
class TestEditHost(unittest.TestCase):
@ -18,7 +14,7 @@ class TestEditHost(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_host(self, activate_session_mock, stdout):
host = 'host'
host_info = mock.ANY
@ -45,19 +41,19 @@ class TestEditHost(unittest.TestCase):
# args: host, --arches='arch1 arch2', --capacity=0.22,
# --description=description, --comment=comment
# expected: success
rv = cli.handle_edit_host(options, session, args)
rv = handle_edit_host(options, session, args)
actual = stdout.getvalue()
expected = 'Edited host\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.editHost.assert_called_once_with(host, **kwargs)
self.assertEqual(session.multiCall.call_count, 2)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_host_failed(self, activate_session_mock, stdout):
host = 'host'
host_info = mock.ANY
@ -84,19 +80,19 @@ class TestEditHost(unittest.TestCase):
# args: host, --arches='arch1 arch2', --capacity=0.22,
# --description=description, --comment=comment
# expected: failed - session.editHost == False
rv = cli.handle_edit_host(options, session, args)
rv = handle_edit_host(options, session, args)
actual = stdout.getvalue()
expected = 'No changes made to host\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.editHost.assert_called_once_with(host, **kwargs)
self.assertEqual(session.multiCall.call_count, 2)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_multi_host(self, activate_session_mock, stdout):
hosts = ['host1', 'host2']
host_infos = [mock.ANY, mock.ANY]
@ -124,12 +120,12 @@ class TestEditHost(unittest.TestCase):
# args: host1, host2, --arches='arch1 arch2', --capacity=0.22,
# --description=description, --comment=comment
# expected: success
rv = cli.handle_edit_host(options, session, args)
rv = handle_edit_host(options, session, args)
actual = stdout.getvalue()
expected = 'Edited host1\nEdited host2\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
self.assertEqual(session.mock_calls,
[call.getHost(hosts[0]),
call.getHost(hosts[1]),
@ -143,7 +139,7 @@ class TestEditHost(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_host_no_arg(
self, activate_session_mock, stderr, stdout):
args = []
@ -158,7 +154,7 @@ class TestEditHost(unittest.TestCase):
# args: _empty_
# expected: failed - should specify host
with self.assertRaises(SystemExit) as cm:
cli.handle_edit_host(options, session, args)
handle_edit_host(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -178,7 +174,7 @@ class TestEditHost(unittest.TestCase):
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_host_no_host(self, activate_session_mock, stdout):
host = 'host'
host_info = None
@ -201,14 +197,14 @@ class TestEditHost(unittest.TestCase):
# args: host, --arches='arch1 arch2', --capacity=0.22,
# --description=description, --comment=comment
# expected: failed -- getHost() == None
rv = cli.handle_edit_host(options, session, args)
rv = handle_edit_host(options, session, args)
actual = stdout.getvalue()
expected = """Host host does not exist
No changes made, please correct the command line
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.editHost.assert_not_called()
self.assertEqual(session.multiCall.call_count, 1)

View file

@ -1,15 +1,12 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_edit_tag
progname = os.path.basename(sys.argv[0]) or 'koji'
@ -19,7 +16,7 @@ class TestEditTag(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_tag(self, activate_session_mock, stdout):
tag = 'tag'
arches = 'arch1 arch2'
@ -61,12 +58,12 @@ class TestEditTag(unittest.TestCase):
# --rename=tag2 --maven-support --include-all
# -x extraA=A -x extraB=True -r extraC -r extraD
# expected: success
rv = cli.handle_edit_tag(options, session, args)
rv = handle_edit_tag(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.editTag2.assert_called_once_with(tag, **opts)
self.assertEqual(rv, None)
@ -86,18 +83,18 @@ class TestEditTag(unittest.TestCase):
# Run it and check immediate output
# args: tag --no-perm --unlock --no-maven-support --no-include-all
# expected: success
rv = cli.handle_edit_tag(options, session, args)
rv = handle_edit_tag(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.editTag2.assert_called_once_with(tag, **opts)
self.assertEqual(rv, None)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_tag_help(self, activate_session_mock, stderr, stdout):
args = ['--help']
options = mock.MagicMock()
@ -109,7 +106,7 @@ class TestEditTag(unittest.TestCase):
# args: --help
# expected: failed, help info shows
with self.assertRaises(SystemExit) as cm:
cli.handle_edit_tag(options, session, args)
handle_edit_tag(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = """Usage: %s edit-tag [options] name
@ -144,7 +141,7 @@ Options:
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_edit_tag_no_arg(self, activate_session_mock, stderr, stdout):
args = []
options = mock.MagicMock()
@ -156,7 +153,7 @@ Options:
# args: --help
# expected: failed, help info shows
with self.assertRaises(SystemExit) as cm:
cli.handle_edit_tag(options, session, args)
handle_edit_tag(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,11 +1,10 @@
from __future__ import absolute_import
import json
import unittest
import os
import sys
import mock
import os
import six
from . import loadcli
import sys
import unittest
try:
import libcomps
@ -16,18 +15,19 @@ try:
except ImportError:
yumcomps = None
cli = loadcli.cli
import koji_cli.commands
from koji_cli.commands import handle_import_comps, _import_comps,\
_import_comps_alt
class TestImportComps(unittest.TestCase):
# Show long diffs in error output...
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.libcomps')
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._import_comps')
@mock.patch('koji_cli._import_comps_alt')
@mock.patch('koji_cli.commands.libcomps')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._import_comps')
@mock.patch('koji_cli.commands._import_comps_alt')
def test_handle_import_comps_libcomps(
self,
mock_import_comps_alt,
@ -50,13 +50,13 @@ class TestImportComps(unittest.TestCase):
# Run it and check immediate output
# args: ./data/comps-example.xml, tag
# expected: success
rv = cli.handle_import_comps(options, session, args)
rv = handle_import_comps(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
mock_activate_session.assert_called_once_with(session)
mock_activate_session.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
mock_import_comps.assert_called_once_with(
session, filename, tag, kwargs)
@ -64,11 +64,11 @@ class TestImportComps(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.libcomps', new=None)
@mock.patch('koji_cli.yumcomps', create=True)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._import_comps')
@mock.patch('koji_cli._import_comps_alt')
@mock.patch('koji_cli.commands.libcomps', new=None)
@mock.patch('koji_cli.commands.yumcomps', create=True)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._import_comps')
@mock.patch('koji_cli.commands._import_comps_alt')
def test_handle_import_comps_yumcomps(
self,
mock_import_comps_alt,
@ -91,13 +91,13 @@ class TestImportComps(unittest.TestCase):
# Run it and check immediate output
# args: --force, ./data/comps-example.xml, tag
# expected: success
rv = cli.handle_import_comps(options, session, args)
rv = handle_import_comps(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
mock_activate_session.assert_called_once_with(session)
mock_activate_session.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
mock_import_comps.assert_not_called()
mock_import_comps_alt.assert_called_once_with(
@ -105,11 +105,11 @@ class TestImportComps(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.libcomps', new=None)
@mock.patch('koji_cli.yumcomps', new=None, create=True)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._import_comps')
@mock.patch('koji_cli._import_comps_alt')
@mock.patch('koji_cli.commands.libcomps', new=None)
@mock.patch('koji_cli.commands.yumcomps', new=None, create=True)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._import_comps')
@mock.patch('koji_cli.commands._import_comps_alt')
def test_handle_import_comps_comps_na(
self,
mock_import_comps_alt,
@ -129,22 +129,22 @@ class TestImportComps(unittest.TestCase):
# Run it and check immediate output
# args: --force, ./data/comps-example.xml, tag
# expected: failed, no comps available
rv = cli.handle_import_comps(options, session, args)
rv = handle_import_comps(options, session, args)
actual = stdout.getvalue()
expected = 'comps module not available\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
mock_activate_session.assert_called_once_with(session)
mock_activate_session.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
mock_import_comps.assert_not_called()
mock_import_comps_alt.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._import_comps')
@mock.patch('koji_cli._import_comps_alt')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._import_comps')
@mock.patch('koji_cli.commands._import_comps_alt')
def test_handle_import_comps_tag_not_exists(
self,
mock_import_comps_alt,
@ -164,13 +164,13 @@ class TestImportComps(unittest.TestCase):
# Run it and check immediate output
# args: ./data/comps-example.xml, tag
# expected: failed: tag does not exist
rv = cli.handle_import_comps(options, session, args)
rv = handle_import_comps(options, session, args)
actual = stdout.getvalue()
expected = 'No such tag: tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
mock_activate_session.assert_called_once_with(session)
mock_activate_session.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
mock_import_comps.assert_not_called()
mock_import_comps_alt.assert_not_called()
@ -178,9 +178,9 @@ class TestImportComps(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._import_comps')
@mock.patch('koji_cli._import_comps_alt')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._import_comps')
@mock.patch('koji_cli.commands._import_comps_alt')
def test_handle_import_comps_help(
self,
mock_import_comps_alt, mock_import_comps,
@ -196,7 +196,7 @@ class TestImportComps(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
rv = cli.handle_import_comps(options, session, args)
rv = handle_import_comps(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -224,7 +224,7 @@ class TestImportComps(unittest.TestCase):
calls_file = os.path.dirname(
__file__) + '/data/comps-example.libcomps.calls'
self._test_import_comps(
cli._import_comps,
_import_comps,
comps_file,
stdout_file,
calls_file,
@ -239,7 +239,7 @@ class TestImportComps(unittest.TestCase):
calls_file = os.path.dirname(
__file__) + '/data/comps-sample.libcomps.calls'
self._test_import_comps(
cli._import_comps,
_import_comps,
comps_file,
stdout_file,
calls_file,
@ -247,8 +247,8 @@ class TestImportComps(unittest.TestCase):
@unittest.skipIf(yumcomps is None, "No yum.comps")
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.libcomps', new=None)
@mock.patch('koji_cli.yumcomps', create=True, new=yumcomps)
@mock.patch('koji_cli.commands.libcomps', new=None)
@mock.patch('koji_cli.commands.yumcomps', create=True, new=yumcomps)
def test_import_comps_yumcomps(self, stdout):
comps_file = os.path.dirname(__file__) + '/data/comps-example.xml'
stdout_file = os.path.dirname(
@ -256,7 +256,7 @@ class TestImportComps(unittest.TestCase):
calls_file = os.path.dirname(
__file__) + '/data/comps-example.yumcomps.calls'
self._test_import_comps(
cli._import_comps_alt,
_import_comps_alt,
comps_file,
stdout_file,
calls_file,
@ -264,8 +264,8 @@ class TestImportComps(unittest.TestCase):
@unittest.skipIf(yumcomps is None, "No yum.comps")
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.libcomps', new=None)
@mock.patch('koji_cli.yumcomps', create=True, new=yumcomps)
@mock.patch('koji_cli.commands.libcomps', new=None)
@mock.patch('koji_cli.commands.yumcomps', create=True, new=yumcomps)
def test_import_comps_sample_yumcomps(self, stdout):
comps_file = os.path.dirname(__file__) + '/data/comps-sample.xml'
stdout_file = os.path.dirname(
@ -273,7 +273,7 @@ class TestImportComps(unittest.TestCase):
calls_file = os.path.dirname(
__file__) + '/data/comps-sample.yumcomps.calls'
self._test_import_comps(
cli._import_comps_alt,
_import_comps_alt,
comps_file,
stdout_file,
calls_file,
@ -342,20 +342,20 @@ def generate_out_calls():
comps_file = path + '/data/comps-example.xml'
stdout_file = path + '/data/comps-example.libcomps.out'
calls_file = path + '/data/comps-example.libcomps.calls'
_generate_out_calls(cli._import_comps, comps_file, stdout_file, calls_file)
_generate_out_calls(_import_comps, comps_file, stdout_file, calls_file)
comps_file = path + '/data/comps-sample.xml'
stdout_file = path + '/data/comps-sample.libcomps.out'
calls_file = path + '/data/comps-sample.libcomps.calls'
_generate_out_calls(cli._import_comps, comps_file, stdout_file, calls_file)
_generate_out_calls(_import_comps, comps_file, stdout_file, calls_file)
cli.yumcomps = yumcomps
koji_cli.commands.yumcomps = yumcomps
comps_file = path + '/data/comps-example.xml'
stdout_file = path + '/data/comps-example.yumcomps.out'
calls_file = path + '/data/comps-example.yumcomps.calls'
_generate_out_calls(
cli._import_comps_alt,
_import_comps_alt,
comps_file,
stdout_file,
calls_file)
@ -364,7 +364,7 @@ def generate_out_calls():
stdout_file = path + '/data/comps-sample.yumcomps.out'
calls_file = path + '/data/comps-sample.yumcomps.calls'
_generate_out_calls(
cli._import_comps_alt,
_import_comps_alt,
comps_file,
stdout_file,
calls_file)

View file

@ -5,37 +5,28 @@ from six.moves import StringIO
import koji
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import anon_handle_list_channels
class TestListChannels(unittest.TestCase):
def setUp(self):
self.options = mock.MagicMock()
self.options.quiet = True
self.session = mock.MagicMock()
self.session.getAPIVersion.return_value = koji.API_VERSION
self.args = mock.MagicMock()
self.original_parser = cli.OptionParser
cli.OptionParser = mock.MagicMock()
self.parser = cli.OptionParser.return_value
cli.options = self.options # globals!!!
def tearDown(self):
cli.OptionParser = self.original_parser
self.args = []
@mock.patch('sys.stdout', new_callable=StringIO)
def test_list_channels(self, stdout):
options = mock.MagicMock()
options.quiet = True
self.parser.parse_args.return_value = [options, []]
# mock xmlrpc
@mock.patch('koji_cli.commands.activate_session')
def test_list_channels(self, activate_session_mock, stdout):
self.session.listChannels.return_value = [
{'id': 1, 'name': 'default'},
{'id': 2, 'name': 'test'},
]
self.session.multiCall.return_value = [[[1,2,3]], [[4,5]]]
cli.anon_handle_list_channels(self.options, self.session, self.args)
anon_handle_list_channels(self.options, self.session, self.args)
actual = stdout.getvalue()
expected = 'successfully connected to hub\ndefault 3\ntest 2\n'
expected = 'default 3\ntest 2\n'
self.assertMultiLineEqual(actual, expected)
activate_session_mock.assert_called_once_with(self.session, self.options)

View file

@ -1,8 +1,8 @@
from __future__ import absolute_import
import mock
import os
import unittest
import six
import unittest
from . import loadcli
cli = loadcli.cli

View file

@ -1,15 +1,13 @@
from __future__ import absolute_import
import mock
import optparse
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
import optparse
cli = loadcli.cli
from koji_cli.commands import handle_maven_build
EMPTY_BUILD_OPTS = {
'specfile': None,
@ -40,13 +38,14 @@ class TestMavenBuild(unittest.TestCase):
self.options = mock.MagicMock()
self.options.quiet = None
self.options.weburl = 'weburl'
self.options.poll_interval = 0
# Mock out the xmlrpc server
self.session = mock.MagicMock()
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build(self, watch_tasks_mock, running_in_bg_mock,
activate_session_mock, stdout):
target = 'target'
@ -66,14 +65,14 @@ class TestMavenBuild(unittest.TestCase):
# Run it and check immediate output
# args: target http://scm
# expected: success
rv = cli.handle_maven_build(self.options, self.session, args)
rv = handle_maven_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
self.session.mavenBuild.assert_called_once_with(
@ -81,14 +80,15 @@ Task info: weburl/taskinfo?taskID=1
running_in_bg_mock.assert_called_once()
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_no_arg(
self,
watch_tasks_mock,
@ -101,7 +101,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -126,9 +126,9 @@ Task info: weburl/taskinfo?taskID=1
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_no_arg_with_ini(
self,
watch_tasks_mock,
@ -141,7 +141,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''
@ -166,9 +166,9 @@ Task info: weburl/taskinfo?taskID=1
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_help(
self,
watch_tasks_mock,
@ -181,7 +181,7 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = """Usage: %s maven-build [options] target URL
@ -233,9 +233,9 @@ Options:
self.assertEqual(cm.exception.code, 0)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_target_not_found(
self,
watch_tasks_mock,
@ -254,7 +254,7 @@ Options:
# args: target http://scm
# expected: failed, target not found
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s maven-build [options] target URL
%s maven-build --ini=CONFIG... [options] target
@ -264,7 +264,7 @@ Options:
""" % (progname, progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_not_called()
running_in_bg_mock.assert_not_called()
@ -274,9 +274,9 @@ Options:
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_dest_tag_not_found(
self,
watch_tasks_mock,
@ -299,7 +299,7 @@ Options:
# args: target http://scm
# expected: failed, dest_tag not found
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s maven-build [options] target URL
%s maven-build --ini=CONFIG... [options] target
@ -309,7 +309,7 @@ Options:
""" % (progname, progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
running_in_bg_mock.assert_not_called()
@ -319,9 +319,9 @@ Options:
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_dest_tag_locked(
self,
watch_tasks_mock,
@ -344,7 +344,7 @@ Options:
# args: target http://scm
# expected: failed, dest_tag is locked
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s maven-build [options] target URL
%s maven-build --ini=CONFIG... [options] target
@ -354,7 +354,7 @@ Options:
""" % (progname, progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
running_in_bg_mock.assert_not_called()
@ -365,7 +365,7 @@ Options:
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch(
'koji.util.parse_maven_param',
return_value={
@ -375,8 +375,8 @@ Options:
'pkg1',
'pkg2']}})
@mock.patch('koji.util.maven_opts')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_inis(
self,
watch_tasks_mock,
@ -415,14 +415,14 @@ Options:
# Run it and check immediate output
# args: --ini=config1.ini --ini=config2.ini --section=section target
# expected: success
rv = cli.handle_maven_build(self.options, self.session, args)
rv = handle_maven_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
parse_maven_param_mock.assert_called_once_with(
@ -433,7 +433,8 @@ Task info: weburl/taskinfo?taskID=1
running_in_bg_mock.assert_called_once()
self.session.logout.assert_called_once()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=build_opts.quiet)
self.session, [task_id], quiet=build_opts.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
stdout.seek(0)
@ -452,7 +453,7 @@ Task info: weburl/taskinfo?taskID=1
# args: --ini=config1.ini --ini=config2.ini --section=section target
# expected: failed, no type == 'maven' found
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s maven-build [options] target URL
%s maven-build --ini=CONFIG... [options] target
@ -480,7 +481,7 @@ Task info: weburl/taskinfo?taskID=1
# args: --ini=config1.ini --ini=config2.ini --section=section target
# expected: failed, ValueError raised when parsing .ini files
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s maven-build [options] target URL
%s maven-build --ini=CONFIG... [options] target
@ -497,11 +498,11 @@ Task info: weburl/taskinfo?taskID=1
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji.util.parse_maven_param')
@mock.patch('koji.util.maven_opts')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_invalid_scm(
self,
watch_tasks_mock,
@ -527,7 +528,7 @@ Task info: weburl/taskinfo?taskID=1
# args: target badscm
# expected: failed, scm is invalid
with self.assertRaises(SystemExit) as cm:
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
actual = stderr.getvalue()
expected = """Usage: %s maven-build [options] target URL
%s maven-build --ini=CONFIG... [options] target
@ -537,7 +538,7 @@ Task info: weburl/taskinfo?taskID=1
""" % (progname, progname, progname)
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
parse_maven_param_mock.assert_not_called()
@ -549,11 +550,11 @@ Task info: weburl/taskinfo?taskID=1
self.assertEqual(cm.exception.code, 2)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji.util.parse_maven_param')
@mock.patch('koji.util.maven_opts', return_value={})
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_build_other_params(
self,
watch_tasks_mock,
@ -585,14 +586,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --debug --skip-tag --background target http://scm
# expected: success
rv = cli.handle_maven_build(self.options, self.session, args)
rv = handle_maven_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
parse_maven_param_mock.assert_not_called()
@ -602,7 +603,8 @@ Task info: weburl/taskinfo?taskID=1
source, target, opts, priority=priority)
self.session.logout.assert_called_once()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=build_opts['quiet'])
self.session, [task_id], quiet=build_opts['quiet'],
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
stdout.seek(0)
@ -624,16 +626,16 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --debug --skip-tag --background -Mtest -Mtest2=val target http://scm
# expected: success
cli.handle_maven_build(self.options, self.session, args)
handle_maven_build(self.options, self.session, args)
self.assertMultiLineEqual(actual, expected)
maven_opts_mock.assert_called_once_with(build_opts, scratch=scratch)
self.session.mavenBuild.assert_called_once_with(
source, target, opts, priority=priority)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_quiet(
self,
watch_tasks_mock,
@ -658,12 +660,12 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: --quiet target http://scm
# expected: success
rv = cli.handle_maven_build(self.options, self.session, args)
rv = handle_maven_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
self.session.mavenBuild.assert_called_once_with(
@ -671,13 +673,14 @@ Task info: weburl/taskinfo?taskID=1
running_in_bg_mock.assert_called_once()
self.session.logout.assert_called()
watch_tasks_mock.assert_called_once_with(
self.session, [task_id], quiet=self.options.quiet)
self.session, [task_id], quiet=self.options.quiet,
poll_interval=self.options.poll_interval)
self.assertEqual(rv, 0)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli._running_in_bg', return_value=True)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji_cli.commands._running_in_bg', return_value=True)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_quiet(
self,
watch_tasks_mock,
@ -701,14 +704,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target http://scm
# expected: success
rv = cli.handle_maven_build(self.options, self.session, args)
rv = handle_maven_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
self.session.mavenBuild.assert_called_once_with(
@ -719,11 +722,11 @@ Task info: weburl/taskinfo?taskID=1
self.assertIsNone(rv)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
@mock.patch('koji.util.parse_maven_param')
@mock.patch('koji.util.maven_opts', return_value={})
@mock.patch('koji_cli._running_in_bg', return_value=False)
@mock.patch('koji_cli.watch_tasks', return_value=0)
@mock.patch('koji_cli.commands._running_in_bg', return_value=False)
@mock.patch('koji_cli.commands.watch_tasks', return_value=0)
def test_handle_maven_build_nowait(
self,
watch_tasks_mock,
@ -752,14 +755,14 @@ Task info: weburl/taskinfo?taskID=1
# Run it and check immediate output
# args: target http://scm
# expected: success
rv = cli.handle_maven_build(self.options, self.session, args)
rv = handle_maven_build(self.options, self.session, args)
actual = stdout.getvalue()
expected = """Created task: 1
Task info: weburl/taskinfo?taskID=1
"""
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
activate_session_mock.assert_called_once_with(self.session, self.options)
self.session.getBuildTarget.assert_called_once_with(target)
self.session.getTag.assert_called_once_with(dest_tag_id)
parse_maven_param_mock.assert_not_called()

View file

@ -1,14 +1,11 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_remove_channel
class TestRemoveChannel(unittest.TestCase):
@ -17,7 +14,7 @@ class TestRemoveChannel(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_channel(self, activate_session_mock, stdout):
channel = 'channel'
channel_info = mock.ANY
@ -31,18 +28,18 @@ class TestRemoveChannel(unittest.TestCase):
# Run it and check immediate output
# args: channel
# expected: success
rv = cli.handle_remove_channel(options, session, args)
rv = handle_remove_channel(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(channel)
session.removeChannel.assert_called_once_with(channel, force=None)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_channel_force(self, activate_session_mock, stdout):
channel = 'channel'
channel_info = mock.ANY
@ -57,18 +54,18 @@ class TestRemoveChannel(unittest.TestCase):
# Run it and check immediate output
# args: --force, channel
# expected: success
rv = cli.handle_remove_channel(options, session, args)
rv = handle_remove_channel(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(channel)
session.removeChannel.assert_called_once_with(channel, force=True)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_channel_no_channel(
self, activate_session_mock, stdout):
channel = 'channel'
@ -83,19 +80,19 @@ class TestRemoveChannel(unittest.TestCase):
# Run it and check immediate output
# args: channel
# expected: failed: no such channel
rv = cli.handle_remove_channel(options, session, args)
rv = handle_remove_channel(options, session, args)
actual = stdout.getvalue()
expected = 'No such channel: channel\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(channel)
session.removeChannel.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_channel_help(
self, activate_session_mock, stderr, stdout):
args = []
@ -107,7 +104,7 @@ class TestRemoveChannel(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_remove_channel(options, session, args)
handle_remove_channel(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,15 +1,11 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_remove_host_from_channel
class TestRemoveHostFromChannel(unittest.TestCase):
@ -17,7 +13,7 @@ class TestRemoveHostFromChannel(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_host_from_channel(
self, activate_session_mock, stdout):
host = 'host'
@ -35,19 +31,19 @@ class TestRemoveHostFromChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel
# expected: success
rv = cli.handle_remove_host_from_channel(options, session, args)
rv = handle_remove_host_from_channel(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.listChannels.assert_called_once_with(host_info['id'])
session.removeHostFromChannel.assert_called_once_with(host, channel)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_host_from_channel_no_host(
self, activate_session_mock, stdout):
host = 'host'
@ -63,19 +59,19 @@ class TestRemoveHostFromChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel
# expected: failed: no such host
rv = cli.handle_remove_host_from_channel(options, session, args)
rv = handle_remove_host_from_channel(options, session, args)
actual = stdout.getvalue()
expected = 'No such host: host\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.listChannels.assert_not_called()
session.removeHostFromChannel.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_host_from_channel_not_a_member(
self, activate_session_mock, stdout):
host = 'host'
@ -94,12 +90,12 @@ class TestRemoveHostFromChannel(unittest.TestCase):
# Run it and check immediate output
# args: host, channel
# expected: success: host isn't belong to channel
rv = cli.handle_remove_host_from_channel(options, session, args)
rv = handle_remove_host_from_channel(options, session, args)
actual = stdout.getvalue()
expected = 'Host host is not a member of channel channel\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getHost.assert_called_once_with(host)
session.listChannels.assert_called_once_with(host_info['id'])
session.removeHostFromChannel.assert_not_called()
@ -107,7 +103,7 @@ class TestRemoveHostFromChannel(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_host_from_channel_help(
self, activate_session_mock, stderr, stdout):
args = []
@ -121,7 +117,7 @@ class TestRemoveHostFromChannel(unittest.TestCase):
# args: _empty_
# expected: failed, help msg shows
with self.assertRaises(SystemExit) as cm:
cli.handle_remove_host_from_channel(options, session, args)
handle_remove_host_from_channel(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,17 +1,13 @@
from __future__ import absolute_import
import unittest
import os
import sys
import mock
import os
import six
import sys
import unittest
from mock import call
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_remove_pkg
class TestRemovePkg(unittest.TestCase):
@ -19,7 +15,7 @@ class TestRemovePkg(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_pkg(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -37,12 +33,12 @@ class TestRemovePkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package
# expected: success
rv = cli.handle_remove_pkg(options, session, args)
rv = handle_remove_pkg(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_called_once_with(
tagID=dsttag['id'])
@ -52,7 +48,7 @@ class TestRemovePkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_pkg_multi_pkg(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -74,12 +70,12 @@ class TestRemovePkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package1, package2, package3
# expected: success
rv = cli.handle_remove_pkg(options, session, args)
rv = handle_remove_pkg(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
self.assertEqual(
session.mock_calls, [
call.getTag(tag), call.listPackages(
@ -91,7 +87,7 @@ class TestRemovePkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_pkg_force(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -113,12 +109,12 @@ class TestRemovePkg(unittest.TestCase):
# Run it and check immediate output
# args: --force, tag, package1, package2, package3
# expected: success
rv = cli.handle_remove_pkg(options, session, args)
rv = handle_remove_pkg(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
self.assertEqual(
session.mock_calls, [
call.getTag(tag), call.listPackages(
@ -130,7 +126,7 @@ class TestRemovePkg(unittest.TestCase):
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_pkg_no_package(self, activate_session_mock, stdout):
tag = 'tag'
dsttag = {'name': tag, 'id': 1}
@ -149,12 +145,12 @@ class TestRemovePkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package1, package2, package3
# expected: failed: can not find package2 under tag
rv = cli.handle_remove_pkg(options, session, args)
rv = handle_remove_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'Package package2 is not in tag tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_called_once_with(
tagID=dsttag['id'])
@ -163,7 +159,7 @@ class TestRemovePkg(unittest.TestCase):
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_pkg_tag_no_exists(
self, activate_session_mock, stdout):
tag = 'tag'
@ -179,12 +175,12 @@ class TestRemovePkg(unittest.TestCase):
# Run it and check immediate output
# args: tag, package1, package2, package3
# expected: failed: tag does not exist
rv = cli.handle_remove_pkg(options, session, args)
rv = handle_remove_pkg(options, session, args)
actual = stdout.getvalue()
expected = 'No such tag: tag\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getTag.assert_called_once_with(tag)
session.listPackages.assert_not_called()
session.packageListRemove.assert_not_called()
@ -192,7 +188,7 @@ class TestRemovePkg(unittest.TestCase):
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_remove_pkg_help(
self, activate_session_mock, stderr, stdout):
args = []
@ -205,7 +201,7 @@ class TestRemovePkg(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_remove_pkg(options, session, args)
handle_remove_pkg(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -1,14 +1,11 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
import six
from . import loadcli
cli = loadcli.cli
from koji_cli.commands import handle_rename_channel
class TestRenameChannel(unittest.TestCase):
@ -17,7 +14,7 @@ class TestRenameChannel(unittest.TestCase):
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_rename_channel(self, activate_session_mock, stdout):
old_name = 'old_name'
new_name = 'new_name'
@ -32,18 +29,18 @@ class TestRenameChannel(unittest.TestCase):
# Run it and check immediate output
# args: old_name, new_name
# expected: success
rv = cli.handle_rename_channel(options, session, args)
rv = handle_rename_channel(options, session, args)
actual = stdout.getvalue()
expected = ''
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(old_name)
session.renameChannel.assert_called_once_with(old_name, new_name)
self.assertNotEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_rename_channel_no_channel(
self, activate_session_mock, stdout):
old_name = 'old_name'
@ -59,19 +56,19 @@ class TestRenameChannel(unittest.TestCase):
# Run it and check immediate output
# args: old_name, new_name
# expected: failed: no such channel
rv = cli.handle_rename_channel(options, session, args)
rv = handle_rename_channel(options, session, args)
actual = stdout.getvalue()
expected = 'No such channel: old_name\n'
self.assertMultiLineEqual(actual, expected)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(session)
activate_session_mock.assert_called_once_with(session, options)
session.getChannel.assert_called_once_with(old_name)
session.renameChannel.assert_not_called()
self.assertEqual(rv, 1)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('sys.stderr', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.commands.activate_session')
def test_handle_rename_channel_help(
self, activate_session_mock, stderr, stdout):
args = []
@ -83,7 +80,7 @@ class TestRenameChannel(unittest.TestCase):
# Run it and check immediate output
with self.assertRaises(SystemExit) as cm:
cli.handle_rename_channel(options, session, args)
handle_rename_channel(options, session, args)
actual_stdout = stdout.getvalue()
actual_stderr = stderr.getvalue()
expected_stdout = ''

View file

@ -3,41 +3,38 @@ import unittest
import mock
from . import loadcli
cli = loadcli.cli
from koji_cli.lib import _running_in_bg
class TestRunningInBg(unittest.TestCase):
@mock.patch('koji_cli.os')
@mock.patch('koji_cli.lib.os')
def test_running_in_bg(self, os_mock):
os_mock.isatty.return_value = False
self.assertTrue(cli._running_in_bg())
self.assertTrue(_running_in_bg())
os_mock.isatty.return_value = True
os_mock.getpgrp.return_value = 0
os_mock.tcgetpgrp.return_value = 1
self.assertTrue(cli._running_in_bg())
self.assertTrue(_running_in_bg())
os_mock.tcgetpgrp.return_value = 0
self.assertFalse(cli._running_in_bg())
self.assertFalse(_running_in_bg())
os_mock.reset_mock()
os_mock.tcgetpgrp.side_effect = OSError
self.assertTrue(cli._running_in_bg())
self.assertTrue(_running_in_bg())
os_mock.isatty.assert_called()
os_mock.getpgrp.assert_called()
os_mock.tcgetpgrp.assert_called()
os_mock.reset_mock()
os_mock.getpgrp.side_effect = OSError
self.assertTrue(cli._running_in_bg())
self.assertTrue(_running_in_bg())
os_mock.isatty.assert_called()
os_mock.getpgrp.assert_called()
os_mock.tcgetpgrp.assert_not_called()
os_mock.reset_mock()
os_mock.isatty.side_effect = OSError
self.assertTrue(cli._running_in_bg())
self.assertTrue(_running_in_bg())
os_mock.isatty.assert_called()
os_mock.getpgrp.assert_not_called()
os_mock.tcgetpgrp.assert_not_called()

View file

@ -1,21 +1,18 @@
from __future__ import absolute_import
import unittest
from . import loadcli
from six.moves import range
cli = loadcli.cli
from koji_cli.lib import _unique_path
class TestUniquePath(unittest.TestCase):
def test_unique_path(self):
for i in range(1000):
self.assertNotEqual(
cli._unique_path('prefix'),
cli._unique_path('prefix'))
_unique_path('prefix'),
_unique_path('prefix'))
self.assertRegexpMatches(
cli._unique_path('prefix'),
_unique_path('prefix'),
'^prefix/\d{10}\.\d{1,7}\.[a-zA-Z]{8}$')
if __name__ == '__main__':

View file

@ -1,41 +1,37 @@
from __future__ import absolute_import
import unittest
import mock
import sys
import six
import unittest
from . import loadcli
cli = loadcli.cli
from koji_cli.lib import _format_size, _format_secs, _progress_callback
class TestUploadProgressCallBack(unittest.TestCase):
maxDiff = None
def test_format_size(self):
self.assertEqual(cli._format_size(2000000000), '1.86 GiB')
self.assertEqual(cli._format_size(1073741824), '1.00 GiB')
self.assertEqual(cli._format_size(3000000), '2.86 MiB')
self.assertEqual(cli._format_size(1048576), '1.00 MiB')
self.assertEqual(cli._format_size(4000), '3.91 KiB')
self.assertEqual(cli._format_size(1024), '1.00 KiB')
self.assertEqual(cli._format_size(500), '500.00 B')
self.assertEqual(_format_size(2000000000), '1.86 GiB')
self.assertEqual(_format_size(1073741824), '1.00 GiB')
self.assertEqual(_format_size(3000000), '2.86 MiB')
self.assertEqual(_format_size(1048576), '1.00 MiB')
self.assertEqual(_format_size(4000), '3.91 KiB')
self.assertEqual(_format_size(1024), '1.00 KiB')
self.assertEqual(_format_size(500), '500.00 B')
def test_format_secs(self):
self.assertEqual(cli._format_secs(0), '00:00:00')
self.assertEqual(cli._format_secs(60), '00:01:00')
self.assertEqual(cli._format_secs(3600), '01:00:00')
self.assertEqual(cli._format_secs(7283294), '2023:08:14')
self.assertEqual(cli._format_secs(1234), '00:20:34')
self.assertEqual(cli._format_secs(4321), '01:12:01')
self.assertEqual(cli._format_secs(4321.567), '01:12:01')
self.assertEqual(_format_secs(0), '00:00:00')
self.assertEqual(_format_secs(60), '00:01:00')
self.assertEqual(_format_secs(3600), '01:00:00')
self.assertEqual(_format_secs(7283294), '2023:08:14')
self.assertEqual(_format_secs(1234), '00:20:34')
self.assertEqual(_format_secs(4321), '01:12:01')
self.assertEqual(_format_secs(4321.567), '01:12:01')
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_progress_callback(self, stdout):
cli._progress_callback(12300, 234000, 5670, 80, 900)
cli._progress_callback(45600, 234000, 5670, 0, 900)
cli._progress_callback(234000, 234000, 5670, 80, 900)
_progress_callback(12300, 234000, 5670, 80, 900)
_progress_callback(45600, 234000, 5670, 0, 900)
_progress_callback(234000, 234000, 5670, 80, 900)
self.assertMultiLineEqual(
stdout.getvalue(),
'[= ] 05% 00:15:00 12.01 KiB 70.88 B/sec\r'

View file

@ -1,49 +1,38 @@
from __future__ import absolute_import
import mock
import os
import six
import sys
import unittest
import os
import sys
import mock
from mock import call
from . import loadcli
from six.moves import range
import six
cli = loadcli.cli
from koji_cli.lib import watch_tasks
class TestWatchTasks(unittest.TestCase):
def setUp(self):
self.options = mock.MagicMock()
cli.options = self.options
self.session = mock.MagicMock(name='sessionMock')
self.args = mock.MagicMock()
self.original_parser = cli.OptionParser
cli.OptionParser = mock.MagicMock()
self.parser = cli.OptionParser.return_value
def tearDown(self):
cli.OptionParser = self.original_parser
# Show long diffs in error output...
maxDiff = None
@mock.patch('sys.stdout', new_callable=six.StringIO)
def test_watch_tasks_no_tasklist(self, stdout):
returned = cli.watch_tasks(self.session, [])
returned = watch_tasks(self.session, [], poll_interval=0)
actual = stdout.getvalue()
expected = ""
self.assertIsNone(returned)
self.assertEqual(actual, expected)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.TaskWatcher')
@mock.patch('koji_cli.display_tasklist_status')
@mock.patch('koji_cli.display_task_results')
@mock.patch('koji_cli.lib.TaskWatcher')
@mock.patch('koji_cli.lib.display_tasklist_status')
@mock.patch('koji_cli.lib.display_task_results')
def test_watch_tasks(self, dtrMock, dtsMock, twClzMock, stdout):
self.options.poll_interval = 0
manager = mock.MagicMock()
@ -78,7 +67,7 @@ class TestWatchTasks(unittest.TestCase):
return rt
twClzMock.side_effect = side_effect
rv = cli.watch_tasks(self.session, list(range(2)), quiet=False)
rv = watch_tasks(self.session, list(range(2)), quiet=False, poll_interval=0)
actual = stdout.getvalue()
self.assertMultiLineEqual(
actual, "Watching tasks (this may be safely interrupted)...\n\n")
@ -171,9 +160,9 @@ class TestWatchTasks(unittest.TestCase):
])
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.TaskWatcher')
@mock.patch('koji_cli.display_tasklist_status')
@mock.patch('koji_cli.display_task_results')
@mock.patch('koji_cli.lib.TaskWatcher')
@mock.patch('koji_cli.lib.display_tasklist_status')
@mock.patch('koji_cli.lib.display_task_results')
def test_watch_tasks_with_keyboardinterrupt(
self, dtrMock, dtsMock, twClzMock, stdout):
"""Raise KeyboardInterrupt inner watch_tasks.
@ -217,7 +206,7 @@ class TestWatchTasks(unittest.TestCase):
twClzMock.side_effect = side_effect
with self.assertRaises(KeyboardInterrupt):
cli.watch_tasks(self.session, list(range(2)), quiet=False)
watch_tasks(self.session, list(range(2)), quiet=False, poll_interval=0)
actual = stdout.getvalue()
self.assertMultiLineEqual(

View file

@ -0,0 +1,28 @@
import os
import sys
def load_plugin(plugin_type, plugin_name):
# We have to do this craziness because 'import koji' is ambiguous. Is it the
# koji module, or the koji cli module. Jump through hoops accordingly.
# https://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path
mod_name = "%s_%s" % (plugin_name, plugin_type)
CLI_FILENAME = os.path.join(
os.path.dirname(__file__),
"../../plugins",
plugin_type,
"%s.py" % plugin_name)
sys.path = [os.path.dirname(CLI_FILENAME),
os.path.join(os.path.dirname(__file__), "../..", plugin_type)] + \
sys.path
if sys.version_info[0] >= 3:
import importlib.machinery
loader = importlib.machinery.SourceFileLoader(mod_name, CLI_FILENAME)
spec = importlib.util.spec_from_loader(loader.name, loader)
kojid = importlib.util.module_from_spec(spec)
spec.loader.exec_module(kojid)
loader.exec_module(kojid)
sys.modules[mod_name] = kojid
else:
import imp
plugin = imp.load_source(mod_name, CLI_FILENAME)
return plugin

View file

@ -1,15 +1,12 @@
from __future__ import absolute_import
import os
import sys
import unittest
import koji
import six
import mock
import six
import unittest
from . import loadcli
cli = loadcli.cli
import koji
from . import load_plugin
runroot = load_plugin.load_plugin('cli', 'runroot')
class TestListCommands(unittest.TestCase):
@ -18,13 +15,8 @@ class TestListCommands(unittest.TestCase):
self.session = mock.MagicMock()
self.session.getAPIVersion.return_value = koji.API_VERSION
self.args = mock.MagicMock()
self.original_parser = cli.OptionParser
cli.OptionParser = mock.MagicMock()
self.parser = cli.OptionParser.return_value
cli.options = self.options # globals!!!
def tearDown(self):
cli.OptionParser = self.original_parser
runroot.OptionParser = mock.MagicMock()
self.parser = runroot.OptionParser.return_value
# Show long diffs in error output...
maxDiff = None
@ -46,7 +38,7 @@ class TestListCommands(unittest.TestCase):
self.session.runroot.return_value = 1
# Run it and check immediate output
cli.handle_runroot(self.options, self.session, self.args)
runroot.handle_runroot(self.options, self.session, self.args)
actual = stdout.getvalue()
actual = actual.replace('nosetests', 'koji')
expected = 'successfully connected to hub\n1\ntask output'

View file

@ -1,31 +1,27 @@
from __future__ import absolute_import
import unittest
import koji
import mock
import six
import StringIO
import unittest
from . import loadcli
cli = loadcli.cli
import koji
import load_plugin
save_failed_tree = load_plugin.load_plugin('cli', 'save_failed_tree')
class TestSaveFailedTree(unittest.TestCase):
def setUp(self):
self.options = mock.MagicMock()
self.session = mock.MagicMock()
self.args = mock.MagicMock()
self.original_parser = cli.OptionParser
cli.OptionParser = mock.MagicMock()
self.parser = cli.OptionParser.return_value
cli.options = self.options # globals!!!
def tearDown(self):
cli.OptionParser = self.original_parser
self.parser = mock.MagicMock()
save_failed_tree.activate_session = mock.MagicMock()
save_failed_tree.OptionParser = mock.MagicMock()
save_failed_tree.watch_tasks = mock.MagicMock()
self.parser = save_failed_tree.OptionParser.return_value
# Show long diffs in error output...
maxDiff = None
@mock.patch('koji_cli.activate_session')
def test_handle_save_failed_tree_simple(self, activate_session_mock):
def test_handle_save_failed_tree_simple(self ):
# koji save-failed-tree 123456
task_id = 123456
broot_id = 321
@ -41,15 +37,14 @@ class TestSaveFailedTree(unittest.TestCase):
self.session.saveFailedTree.return_value = 123
# Run it and check immediate output
cli.handle_save_failed_tree(self.options, self.session, self.args)
save_failed_tree.handle_save_failed_tree(options, self.session, self.args)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
save_failed_tree.activate_session.assert_called_once_with(self.session, options)
self.session.listBuildroots.assert_called_once_with(taskID=task_id)
self.session.saveFailedTree.assert_called_once_with(broot_id, options.full)
@mock.patch('koji_cli.activate_session')
def test_handle_save_failed_tree_buildroots(self, activate_session_mock):
def test_handle_save_failed_tree_buildroots(self):
# koji save-failed-tree --buildroot 123456
broot_id = 321
arguments = [broot_id]
@ -65,16 +60,15 @@ class TestSaveFailedTree(unittest.TestCase):
self.session.saveFailedTree.return_value = 123
# Run it and check immediate output
cli.handle_save_failed_tree(self.options, self.session, self.args)
save_failed_tree.handle_save_failed_tree(options, self.session, self.args)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
save_failed_tree.activate_session.assert_called_once_with(self.session, options)
self.session.listBuildroots.assert_not_called()
self.session.saveFailedTree.assert_called_once_with(broot_id, options.full)
@mock.patch('koji_cli.activate_session')
def test_handle_save_failed_tree_full(self, activate_session_mock):
def test_handle_save_failed_tree_full(self):
# koji save-failed-tree 123456 --full
task_id = 123456
broot_id = 321
@ -90,16 +84,14 @@ class TestSaveFailedTree(unittest.TestCase):
self.session.saveFailedTree.return_value = 123
# Run it and check immediate output
cli.handle_save_failed_tree(self.options, self.session, self.args)
save_failed_tree.handle_save_failed_tree(options, self.session, self.args)
# Finally, assert that things were called as we expected.
activate_session_mock.assert_called_once_with(self.session)
save_failed_tree.activate_session.assert_called_once_with(self.session, options)
self.session.listBuildroots.assert_called_once_with(taskID=task_id)
self.session.saveFailedTree.assert_called_once_with(broot_id, options.full)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.watch_tasks')
def test_handle_save_failed_tree_wait(self, watch_tasks_mock, activate_session_mock):
def test_handle_save_failed_tree_wait(self):
# koji save-failed-tree 123456 --full
task_id = 123456
broot_id = 321
@ -117,20 +109,19 @@ class TestSaveFailedTree(unittest.TestCase):
self.session.saveFailedTree.return_value = spawned_id
# Run it and check immediate output
cli.handle_save_failed_tree(self.options, self.session, self.args)
save_failed_tree.handle_save_failed_tree(options, self.session, self.args)
# Finally, assert that things were called as we expected.
self.session.listBuildroots.assert_called_once_with(taskID=task_id)
self.session.saveFailedTree.assert_called_once_with(broot_id, options.full)
activate_session_mock.assert_called_once_with(self.session)
save_failed_tree.activate_session.assert_called_once_with(self.session, options)
self.session.logout.assert_called_once_with()
watch_tasks_mock.assert_called_once_with(self.session, [spawned_id],
quiet=options.quiet)
save_failed_tree.watch_tasks.assert_called_once_with(self.session, [spawned_id],
poll_interval=options.poll_interval,
quiet=options.quiet)
@mock.patch('sys.stdout', new_callable=six.StringIO)
@mock.patch('koji_cli.activate_session')
@mock.patch('koji_cli.watch_tasks')
def test_handle_save_failed_tree_errors(self, watch_tasks_mock, activate_session_mock, stdout):
@mock.patch('sys.stdout', new_callable=StringIO.StringIO)
def test_handle_save_failed_tree_errors(self, stdout):
# koji save-failed-tree 123 456
arguments = [123, 456]
options = mock.MagicMock()
@ -139,26 +130,26 @@ class TestSaveFailedTree(unittest.TestCase):
self.session.getAPIVersion.return_value = koji.API_VERSION
self.session.listBuildroots.return_value = [{'id': 321}]
self.assertRaises(Exception, cli.handle_save_failed_tree,
self.options, self.session, self.args)
self.assertRaises(Exception, save_failed_tree.handle_save_failed_tree,
options, self.session, self.args)
arguments = ["text"]
self.parser.parse_args.return_value = [options, arguments]
self.assertRaises(Exception, cli.handle_save_failed_tree, self.options,
self.assertRaises(Exception, save_failed_tree.handle_save_failed_tree, options,
self.session, self.args)
cli.logger = mock.MagicMock()
save_failed_tree.logger = mock.MagicMock()
# plugin not installed
arguments = [123]
self.parser.parse_args.return_value = [options, arguments]
self.session.saveFailedTree.side_effect = koji.GenericError("Invalid method")
cli.handle_save_failed_tree(self.options, self.session, self.args)
save_failed_tree.handle_save_failed_tree(options, self.session, self.args)
actual = stdout.getvalue()
self.assertTrue('The save_failed_tree plugin appears to not be installed' in actual)
# Task which is not FAILED, disabled in config, wrong owner
self.session.saveFailedTree.side_effect = koji.PreBuildError('placeholder')
with self.assertRaises(koji.PreBuildError) as cm:
cli.handle_save_failed_tree(self.options, self.session, self.args)
save_failed_tree.handle_save_failed_tree(options, self.session, self.args)
e = cm.exception
self.assertEqual(e, self.session.saveFailedTree.side_effect)