293 lines
12 KiB
Python
293 lines
12 KiB
Python
from __future__ import absolute_import
|
|
|
|
import os
|
|
import unittest
|
|
|
|
import mock
|
|
import six
|
|
|
|
import koji
|
|
from koji_cli.commands import handle_image_build_indirection, _build_image_indirection
|
|
from . import utils
|
|
|
|
if six.PY2:
|
|
ConfigParser = six.moves.configparser.SafeConfigParser
|
|
else:
|
|
ConfigParser = six.moves.configparser.ConfigParser
|
|
|
|
|
|
TASK_OPTIONS = {
|
|
"background": True,
|
|
"config": "build-image-config.conf",
|
|
"name": "image",
|
|
"version": "26",
|
|
"release": "1",
|
|
"arch": "x86_64 i386",
|
|
"target": "target",
|
|
"base_image_task": 2,
|
|
"base_image_build": None,
|
|
"utility_image_task": 4,
|
|
"utility_image_build": None,
|
|
"indirection_template": "template",
|
|
"indirection_template_url": "git://git.github.org/git/",
|
|
"results_loc": "results",
|
|
"scratch": None,
|
|
"wait": False,
|
|
"noprogress": None,
|
|
"skip_tag": False,
|
|
}
|
|
|
|
|
|
class Options(object):
|
|
def __init__(self, init_dict):
|
|
for k, v in init_dict.items():
|
|
setattr(self, k, v)
|
|
|
|
|
|
class TestBuildImageIndirection(utils.CliTestCase):
|
|
def setUp(self):
|
|
self.maxDiff = None
|
|
self.task_id = 1001
|
|
self.weburl = 'https://web.url'
|
|
self.options = mock.MagicMock()
|
|
self.options.quiet = False
|
|
self.options.weburl = self.weburl
|
|
self.session = mock.MagicMock()
|
|
self.activate_session = mock.patch('koji_cli.commands.activate_session').start()
|
|
self.unique_path = mock.patch('koji_cli.commands.unique_path').start()
|
|
|
|
self.task_opts = Options(TASK_OPTIONS)
|
|
|
|
self.build_target = {
|
|
'id': 1,
|
|
'name': 'target',
|
|
'dest_tag': 1,
|
|
'build_tag': 2,
|
|
'build_tag_name': 'target-build',
|
|
'dest_tag_name': 'target'
|
|
}
|
|
|
|
self.dest_tag = {'id': 1, 'name': 'dest-tag', 'arch': 'x86_64'}
|
|
|
|
self.session.getBuildTarget.return_value = self.build_target
|
|
self.session.getTag.return_value = self.dest_tag
|
|
self.session.buildImageIndirection.return_value = self.task_id
|
|
self.unique_path.return_value = '/path/to/cli-image-indirection'
|
|
|
|
self.configparser = mock.patch('six.moves.configparser.ConfigParser').start()
|
|
|
|
def tearDown(self):
|
|
mock.patch.stopall()
|
|
|
|
def test_build_image_indirection(self):
|
|
"""Test _build_image_indirection function"""
|
|
expected = "Created task: %d" % self.task_id + "\n"
|
|
expected += "Task info: %s/taskinfo?taskID=%s" % (self.weburl, self.task_id) + "\n"
|
|
|
|
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assert_console_message(stdout, expected)
|
|
|
|
def test_build_image_indirection_with_scratch(self):
|
|
"""Test _build_image_indirection function with scratch option"""
|
|
expected = "\n"
|
|
expected += "Created task: %d" % self.task_id + "\n"
|
|
expected += "Task info: %s/taskinfo?taskID=%s" % (self.weburl, self.task_id) + "\n"
|
|
|
|
self.task_opts.indirection_template_url = None
|
|
self.task_opts.scratch = True
|
|
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assert_console_message(stdout, expected)
|
|
|
|
def test_build_image_indirection_with_noprogress(self):
|
|
"""Test _build_image_indirection function with noprogress option"""
|
|
expected = "\n"
|
|
expected += "Created task: %d" % self.task_id + "\n"
|
|
expected += "Task info: %s/taskinfo?taskID=%s" % (self.weburl, self.task_id) + "\n"
|
|
|
|
self.task_opts.indirection_template_url = None
|
|
self.task_opts.scratch = True
|
|
self.task_opts.noprogress = True
|
|
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assert_console_message(stdout, expected)
|
|
args, kwargs = self.session.uploadWrapper.call_args
|
|
self.assertEqual(kwargs['callback'], None)
|
|
|
|
def test_build_image_indirection_expections(self):
|
|
"""Test _build_image_indirection all exceptions"""
|
|
|
|
# Case 1. sanity check for utility image options
|
|
self.task_opts.utility_image_task = None
|
|
self.task_opts.utility_image_build = None
|
|
expected = "You must specify either a utility-image task or build ID/NVR"
|
|
with self.assertRaises(koji.GenericError) as cm:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assertEqual(str(cm.exception), expected)
|
|
self.activate_session.assert_not_called()
|
|
|
|
# Case 2. sanity check for base image options
|
|
self.task_opts.utility_image_build = 'image-utils-26.1'
|
|
self.task_opts.base_image_task = None
|
|
self.task_opts.base_image_build = None
|
|
expected = "You must specify either a base-image task or build ID/NVR"
|
|
with self.assertRaises(koji.GenericError) as cm:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assertEqual(str(cm.exception), expected)
|
|
self.activate_session.assert_not_called()
|
|
|
|
self.task_opts.base_image_build = 'image-base-26.1'
|
|
|
|
# Case 3. missing required options
|
|
required = ['name', 'version', 'arch', 'target',
|
|
'indirection_template', 'results_loc']
|
|
for r in required:
|
|
orig = getattr(self.task_opts, r)
|
|
setattr(self.task_opts, r, None)
|
|
expected = "Missing the following required options: "
|
|
expected += "--" + r.replace('_', '-') + "\n"
|
|
with self.assertRaises(koji.GenericError) as cm:
|
|
with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assert_console_message(stdout, expected)
|
|
self.assertEqual(
|
|
str(cm.exception), "Missing required options specified above")
|
|
self.activate_session.assert_not_called()
|
|
setattr(self.task_opts, r, orig)
|
|
|
|
# Case 4. target not found error
|
|
self.session.getBuildTarget.return_value = {}
|
|
expected = "No such build target: %s" % {}
|
|
with self.assertRaises(koji.GenericError) as cm:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assertEqual(str(cm.exception), expected)
|
|
self.activate_session.assert_called_with(self.session, self.options)
|
|
|
|
# Case 5. tag not found error
|
|
self.session.getBuildTarget.return_value = self.build_target
|
|
self.session.getTag.return_value = {}
|
|
expected = "No such destination tag: %s" % self.build_target['dest_tag_name']
|
|
with self.assertRaises(koji.GenericError) as cm:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assertEqual(str(cm.exception), expected)
|
|
self.activate_session.assert_called_with(self.session, self.options)
|
|
|
|
# Case 6. --indirection-template-url is not given and --scatch is not set
|
|
self.session.getTag.return_value = self.dest_tag
|
|
self.task_opts.indirection_template_url = None
|
|
self.task_opts.scratch = None
|
|
expected = "Non-scratch builds must provide a URL for the indirection template"
|
|
with self.assertRaises(koji.GenericError) as cm:
|
|
_build_image_indirection(
|
|
self.options, self.task_opts, self.session, [])
|
|
self.assertEqual(str(cm.exception), expected)
|
|
self.activate_session.assert_called_with(self.session, self.options)
|
|
|
|
@mock.patch('koji_cli.commands._build_image_indirection')
|
|
def test_image_build_indirection_configuration(self, build_image_indirection_mock):
|
|
"""Test handle_image_build."""
|
|
self.configparser.return_value = ConfigParser()
|
|
|
|
config_file = os.path.join(
|
|
os.path.dirname(__file__),
|
|
'data/image-build-indirection-config.conf'
|
|
)
|
|
TASK_OPTIONS['config'] = config_file
|
|
|
|
handle_image_build_indirection(
|
|
self.options,
|
|
self.session,
|
|
['--config', config_file,
|
|
'--arch', 'x386']
|
|
)
|
|
|
|
args, _ = build_image_indirection_mock.call_args
|
|
merged_options = args[1].__dict__
|
|
|
|
self.assertEqual("x86_64", merged_options["arch"]) # Overrides command line
|
|
self.assertEqual("fedora-base", merged_options["base_image_build"])
|
|
self.assertEqual("fedora-indirection.tdl", merged_options["indirection_template"])
|
|
self.session.activate_session_mock.assert_not_called()
|
|
|
|
|
|
class TestImageBuildIndirection(utils.CliTestCase):
|
|
def setUp(self):
|
|
self.maxDiff = None
|
|
self.options = mock.MagicMock()
|
|
self.session = mock.MagicMock()
|
|
|
|
self.error_format = """Usage: %s image-build-indirection [base_image] [utility_image] [indirection_build_template]
|
|
%s image-build --config <FILE>
|
|
|
|
(Specify the --help global option for a list of other help options)
|
|
|
|
%s: error: {message}
|
|
""" % (self.progname, self.progname, self.progname)
|
|
|
|
@mock.patch('koji_cli.commands._build_image_indirection')
|
|
def test_handle_image_build_indirection(self, build_image_mock):
|
|
"""Test handle_image_build_indirection function"""
|
|
handle_image_build_indirection(self.options, self.session, [])
|
|
args, kwargs = build_image_mock.call_args
|
|
empty_opts = dict((k, None) for k in TASK_OPTIONS)
|
|
self.assertDictEqual(empty_opts, args[1].__dict__)
|
|
|
|
def test_handle_image_build_indirection_help(self):
|
|
"""Test handle_image_build_indirection help message"""
|
|
self.assert_help(
|
|
handle_image_build_indirection,
|
|
"""Usage: %s image-build-indirection [base_image] [utility_image] [indirection_build_template]
|
|
%s image-build --config <FILE>
|
|
|
|
(Specify the --help global option for a list of other help options)
|
|
|
|
Options:
|
|
-h, --help show this help message and exit
|
|
--config=CONFIG Use a configuration file to define image-build options
|
|
instead of command line options (they will be
|
|
ignored).
|
|
--background Run the image creation task at a lower priority
|
|
--name=NAME Name of the output image
|
|
--version=VERSION Version of the output image
|
|
--release=RELEASE Release of the output image
|
|
--arch=ARCH Architecture of the output image and input images
|
|
--target=TARGET Build target to use for the indirection build
|
|
--skip-tag Do not tag the resulting build
|
|
--base-image-task=BASE_IMAGE_TASK
|
|
ID of the createImage task of the base image to be
|
|
used
|
|
--base-image-build=BASE_IMAGE_BUILD
|
|
NVR or build ID of the base image to be used
|
|
--utility-image-task=UTILITY_IMAGE_TASK
|
|
ID of the createImage task of the utility image to be
|
|
used
|
|
--utility-image-build=UTILITY_IMAGE_BUILD
|
|
NVR or build ID of the utility image to be used
|
|
--indirection-template=INDIRECTION_TEMPLATE
|
|
Name of the local file, or SCM file containing the
|
|
template used to drive the indirection plugin
|
|
--indirection-template-url=INDIRECTION_TEMPLATE_URL
|
|
SCM URL containing the template used to drive the
|
|
indirection plugin
|
|
--results-loc=RESULTS_LOC
|
|
Relative path inside the working space image where the
|
|
results should be extracted from
|
|
--scratch Create a scratch image
|
|
--wait Wait on the image creation, even if running in the
|
|
background
|
|
--nowait Do not wait on the image creation
|
|
--noprogress Do not display progress of the upload
|
|
""" % (self.progname, self.progname))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|