Merge #339 Refactor failables, step 1

This commit is contained in:
Dennis Gilmore 2016-08-03 07:36:34 +00:00
commit 247149d4e1
20 changed files with 148 additions and 97 deletions

View File

@ -117,13 +117,6 @@ Example
base_product_short = "Fedora"
base_product_version = "23"
**tree_arches**
([*str*]) -- list of architectures which should be included; if undefined, all architectures from variants.xml will be included
**tree_variants**
([*str*]) -- list of variants which should be included; if undefined, all variants from variants.xml will be included
General Settings
================
@ -138,28 +131,12 @@ Options
**failable_deliverables** [optional]
(*list*) -- list which deliverables on which variant and architecture can
fail and not abort the whole compose
Currently handled deliverables are:
* buildinstall
* iso
* live
* image-build
* live-media
* ostree
* ostree-installer
* osbs
.. note::
Image building is not run per-architecture. If you want to mark it
as failable, specify it in a block with arch set as ``*``.
fail and not abort the whole compose. This only applies to ``buildinstall``
and ``iso`` parts. All other artifacts can be configured in their
respective part of configuration.
Please note that ``*`` as a wildcard matches all architectures but ``src``.
tree_arches = ["x86_64"]
tree_variants = ["Server"]
**comps_filter_environments** [optional]
(*bool*) -- When set to ``False``, the comps files for variants will not
have their environments filtered to match the variant.
@ -168,6 +145,15 @@ Options
(*list*) -- List of variants for which the original comps file will be
copied without any modifications. Overwrites `comps_filter_environments`.
**tree_arches**
([*str*]) -- list of architectures which should be included; if undefined,
all architectures from variants.xml will be included
**tree_variants**
([*str*]) -- list of variants which should be included; if undefined, all
variants from variants.xml will be included
Example
-------
::
@ -196,6 +182,9 @@ Example
})
]
tree_arches = ["x86_64"]
tree_variants = ["Server"]
Image Naming
============
@ -836,6 +825,14 @@ will be generated based on date, compose type and respin.
* ``image_build_release``
* ``live_images_release``
Each configuration block can also optionally specify a list of architectures
that are not release blocking with ``failable`` key. If any deliverable fails,
it will not abort the whole compose. Due to limitations in how the tasks are
done in Koji, if any architecture fails, all of them fail. Until this is
resolved, it is not possible to configure failability per architecture. An
empty list means required deliverable, non-empty list means non-blocking
deliverable.
Live Images Settings
====================
@ -1059,6 +1056,8 @@ runroot environment.
* ``config_branch`` -- (*str*) Git branch of the repo to use. Defaults to
``master``.
* ``failable`` -- (*[str]*) List of architectures for which this
deliverable is not release blocking.
Example config
@ -1096,6 +1095,8 @@ an OSTree repository. This always runs in Koji as a ``runroot`` task.
* ``release`` -- (*str*) Release value to set for the installer image. Set
to ``None`` to use the date.respin format.
* ``failable`` -- (*[str]*) List of architectures for which this
deliverable is not release blocking.
These optional keys are passed to ``lorax`` to customize the build.
@ -1163,6 +1164,14 @@ they are not scratch builds).
Please see :ref:`git-urls` section for more details.
* ``target`` -- (*str*) A Koji target to build the image for.
Optionally you can specify ``failable``. If it has a truthy value, failure
to create the image will not abort the whole compose.
.. note::
Once OSBS gains support for multiple architectures, the usage of this
option will most likely change to list architectures that are allowed
to fail.
The configuration will pass other attributes directly to the Koji task.
This includes ``name``, ``version``, ``scratch`` and ``priority``.

View File

@ -190,9 +190,10 @@ class BuildinstallPhase(PhaseBase):
# TODO: label is not used
label = ""
volid = get_volid(self.compose, arch, variant, escape_spaces=False, disc_type=disc_type)
with failable(self.compose, variant, arch, 'buildinstall'):
can_fail = self.compose.can_fail(variant, arch, 'buildinstall')
with failable(self.compose, can_fail, variant, arch, 'buildinstall'):
tweak_buildinstall(buildinstall_dir, os_tree, arch, variant.uid, label, volid, kickstart_file)
link_boot_iso(self.compose, arch, variant)
link_boot_iso(self.compose, arch, variant, can_fail)
def get_kickstart_file(compose):
@ -315,7 +316,7 @@ def tweak_buildinstall(src, dst, arch, variant, label, volid, kickstart_file=Non
shutil.rmtree(tmp_dir)
def link_boot_iso(compose, arch, variant):
def link_boot_iso(compose, arch, variant, can_fail):
if arch == "src":
return
@ -369,6 +370,7 @@ def link_boot_iso(compose, arch, variant):
img.bootable = True
img.subvariant = variant.name
img.implant_md5 = implant_md5
setattr(img, 'can_fail', can_fail)
setattr(img, 'deliverable', 'buildinstall')
try:
img.volume_id = iso.get_volume_id(new_boot_iso_path)
@ -382,7 +384,8 @@ class BuildinstallThread(WorkerThread):
def process(self, item, num):
# The variant is None unless lorax is used as buildinstall method.
compose, arch, variant, cmd = item
with failable(compose, variant, arch, 'buildinstall'):
can_fail = compose.can_fail(variant, arch, 'buildinstall')
with failable(compose, can_fail, variant, arch, 'buildinstall'):
self.worker(compose, arch, variant, cmd, num)
def worker(self, compose, arch, variant, cmd, num):

View File

@ -183,7 +183,8 @@ class CreateIsoThread(WorkerThread):
def process(self, item, num):
compose, cmd, variant, arch = item
with failable(compose, variant, arch, 'iso'):
can_fail = compose.can_fail(variant, arch, 'iso')
with failable(compose, can_fail, variant, arch, 'iso'):
self.worker(compose, cmd, variant, arch, num)
def worker(self, compose, cmd, variant, arch, num):

View File

@ -157,6 +157,7 @@ class ImageBuildPhase(base.ImageConfigMixin, base.ConfigGuardedPhase):
),
"link_type": self.compose.conf.get("link_type", "hardlink-or-copy"),
"scratch": image_conf['image-build'].pop('scratch', False),
"failable_arches": image_conf.pop('failable', []),
}
self.pool.add(CreateImageBuildThread(self.pool))
self.pool.queue_put((self.compose, cmd))
@ -172,7 +173,10 @@ class CreateImageBuildThread(WorkerThread):
compose, cmd = item
variant = cmd["image_conf"]["image-build"]["variant"]
subvariant = cmd["image_conf"]["image-build"].get("subvariant", variant.uid)
with failable(compose, variant, '*', 'image-build', subvariant):
failable_arches = cmd.get('failable_arches', [])
self.can_fail = bool(failable_arches)
# TODO handle failure per architecture; currently not possible in single task
with failable(compose, self.can_fail, variant, '*', 'image-build', subvariant):
self.worker(num, compose, variant, subvariant, cmd)
def worker(self, num, compose, variant, subvariant, cmd):
@ -253,6 +257,7 @@ class CreateImageBuildThread(WorkerThread):
img.disc_count = 1
img.bootable = False
img.subvariant = subvariant
setattr(img, 'can_fail', self.can_fail)
setattr(img, 'deliverable', 'image-build')
compose.im.add(variant=variant.uid, arch=image_info['arch'], image=img)

View File

@ -157,6 +157,7 @@ class LiveImagesPhase(base.ImageConfigMixin, base.ConfigGuardedPhase):
"type": type,
"label": "", # currently not used
"subvariant": subvariant,
"failable_arches": data.get('failable', []),
}
cmd["repos"] = self._get_repos(arch, variant, data)
@ -199,7 +200,10 @@ class CreateLiveImageThread(WorkerThread):
def process(self, item, num):
compose, cmd, variant, arch = item
with failable(compose, variant, arch, 'live', cmd.get('subvariant')):
self.failable_arches = cmd.get('failable_arches', [])
# TODO handle failure per architecture; currently not possible in single task
self.can_fail = bool(self.failable_arches)
with failable(compose, self.can_fail, variant, arch, 'live', cmd.get('subvariant')):
self.worker(compose, cmd, variant, arch, num)
def worker(self, compose, cmd, variant, arch, num):
@ -290,6 +294,7 @@ class CreateLiveImageThread(WorkerThread):
img.disc_count = 1
img.bootable = True
img.subvariant = subvariant
setattr(img, 'can_fail', self.can_fail)
setattr(img, 'deliverable', 'live')
compose.im.add(variant=variant.uid, arch=arch, image=img)

View File

@ -116,6 +116,7 @@ class LiveMediaPhase(ImageConfigMixin, ConfigGuardedPhase):
'repo': self._get_repos(image_conf, variant),
'install_tree': self._get_install_tree(image_conf, variant),
'version': self.get_config(image_conf, 'version'),
'failable_arches': image_conf.get('failable', []),
}
self.pool.add(LiveMediaThread(self.pool))
self.pool.queue_put((self.compose, variant, config))
@ -127,8 +128,10 @@ class LiveMediaThread(WorkerThread):
def process(self, item, num):
compose, variant, config = item
subvariant = config.pop('subvariant')
self.failable_arches = config.pop('failable_arches')
self.num = num
with failable(compose, variant, '*', 'live-media', subvariant):
# TODO handle failure per architecture; currently not possible in single task
with failable(compose, bool(self.failable_arches), variant, '*', 'live-media', subvariant):
self.worker(compose, variant, subvariant, config)
def _get_log_file(self, compose, variant, subvariant, config):
@ -204,6 +207,7 @@ class LiveMediaThread(WorkerThread):
img.disc_count = 1
img.bootable = True
img.subvariant = subvariant
setattr(img, 'can_fail', bool(self.failable_arches))
setattr(img, 'deliverable', 'live-media')
compose.im.add(variant=variant.uid, arch=image_info['arch'], image=img)

View File

@ -47,7 +47,7 @@ class OSBSThread(WorkerThread):
def process(self, item, num):
compose, variant, config = item
self.num = num
with util.failable(compose, variant, '*', 'osbs'):
with util.failable(compose, bool(config.pop('failable', None)), variant, '*', 'osbs'):
self.worker(compose, variant, config)
def worker(self, compose, variant, config):

View File

@ -39,7 +39,9 @@ class OSTreeThread(WorkerThread):
def process(self, item, num):
compose, variant, arch, config = item
self.num = num
with util.failable(compose, variant, arch, 'ostree'):
failable_arches = config.get('failable', [])
with util.failable(compose, util.can_arch_fail(failable_arches, arch),
variant, arch, 'ostree'):
self.worker(compose, variant, arch, config)
def worker(self, compose, variant, arch, config):

View File

@ -42,7 +42,9 @@ class OstreeInstallerThread(WorkerThread):
def process(self, item, num):
compose, variant, arch, config = item
self.num = num
with util.failable(compose, variant, arch, 'ostree-installer'):
failable_arches = config.get('failable', [])
self.can_fail = util.can_arch_fail(failable_arches, arch)
with util.failable(compose, self.can_fail, variant, arch, 'ostree-installer'):
self.worker(compose, variant, arch, config)
def worker(self, compose, variant, arch, config):
@ -119,6 +121,7 @@ class OstreeInstallerThread(WorkerThread):
img.bootable = True
img.subvariant = variant.name
img.implant_md5 = implant_md5
setattr(img, 'can_fail', self.can_fail)
setattr(img, 'deliverable', 'ostree-installer')
try:
img.volume_id = iso_wrapper.get_volume_id(full_iso_path)

View File

@ -125,7 +125,9 @@ def check(compose, variant, arch, image):
result = True
path = os.path.join(compose.paths.compose.topdir(), image.path)
deliverable = getattr(image, 'deliverable')
with failable(compose, variant, arch, deliverable, subvariant=image.subvariant):
can_fail = getattr(image, 'can_fail', False)
with failable(compose, can_fail, variant, arch, deliverable,
subvariant=image.subvariant):
with open(path) as f:
iso = is_iso(f)
if image.format == 'iso' and not iso:

View File

@ -464,10 +464,9 @@ def process_args(fmt, args):
@contextlib.contextmanager
def failable(compose, variant, arch, deliverable, subvariant=None):
def failable(compose, can_fail, variant, arch, deliverable, subvariant=None):
"""If a deliverable can fail, log a message and go on as if it succeeded."""
msg = deliverable.replace('-', ' ').capitalize()
can_fail = compose.can_fail(variant, arch, deliverable)
if can_fail:
compose.attempt_deliverable(variant, arch, deliverable, subvariant)
else:
@ -489,6 +488,11 @@ def failable(compose, variant, arch, deliverable, subvariant=None):
compose.log_debug(tb)
def can_arch_fail(failable_arches, arch):
"""Check if `arch` is in `failable_arches` or `*` can fail."""
return '*' in failable_arches or arch in failable_arches
def get_format_substs(compose, **kwargs):
"""Return a dict of basic format substitutions.

View File

@ -62,7 +62,7 @@ class DummyCompose(object):
self.log_debug = mock.Mock()
self.log_warning = mock.Mock()
self.get_image_name = mock.Mock(return_value='image-name')
self.image = mock.Mock(path='Client/i386/iso/image.iso')
self.image = mock.Mock(path='Client/i386/iso/image.iso', can_fail=False)
self.im = mock.Mock(images={'Client': {'amd64': [self.image]}})
self.old_composes = []
self.config_dir = '/home/releng/config'

View File

@ -355,9 +355,9 @@ class TestCopyFiles(PungiTestCase):
'amd64', 'Client', '', 'Client.amd64', 'kickstart')])
self.assertItemsEqual(
link_boot_iso.mock_calls,
[mock.call(compose, 'x86_64', compose.variants['Server']),
mock.call(compose, 'amd64', compose.variants['Client']),
mock.call(compose, 'amd64', compose.variants['Server'])])
[mock.call(compose, 'x86_64', compose.variants['Server'], False),
mock.call(compose, 'amd64', compose.variants['Client'], False),
mock.call(compose, 'amd64', compose.variants['Server'], False)])
@mock.patch('pungi.phases.buildinstall.link_boot_iso')
@mock.patch('pungi.phases.buildinstall.tweak_buildinstall')
@ -397,9 +397,9 @@ class TestCopyFiles(PungiTestCase):
'amd64', 'Client', '', 'Client.amd64', 'kickstart')])
self.assertItemsEqual(
link_boot_iso.mock_calls,
[mock.call(compose, 'x86_64', compose.variants['Server']),
mock.call(compose, 'amd64', compose.variants['Client']),
mock.call(compose, 'amd64', compose.variants['Server'])])
[mock.call(compose, 'x86_64', compose.variants['Server'], False),
mock.call(compose, 'amd64', compose.variants['Client'], False),
mock.call(compose, 'amd64', compose.variants['Server'], False)])
@mock.patch('pungi.phases.buildinstall.link_boot_iso')
@mock.patch('pungi.phases.buildinstall.tweak_buildinstall')
@ -622,7 +622,7 @@ class TestSymlinkIso(PungiTestCase):
get_file_size.return_value = 1024
get_mtime.return_value = 13579
link_boot_iso(self.compose, 'x86_64', self.compose.variants['Server'])
link_boot_iso(self.compose, 'x86_64', self.compose.variants['Server'], False)
tgt = self.topdir + '/compose/Server/x86_64/iso/image-name'
self.assertTrue(os.path.isfile(tgt))
@ -654,6 +654,7 @@ class TestSymlinkIso(PungiTestCase):
self.assertEqual(image.disc_count, 1)
self.assertEqual(image.bootable, True)
self.assertEqual(image.implant_md5, IsoWrapper.get_implanted_md5.return_value)
self.assertEqual(image.can_fail, False)
self.assertEqual(self.compose.im.add.mock_calls,
[mock.call('Server', 'x86_64', image)])
@ -671,7 +672,7 @@ class TestSymlinkIso(PungiTestCase):
get_file_size.return_value = 1024
get_mtime.return_value = 13579
link_boot_iso(self.compose, 'x86_64', self.compose.variants['Server'])
link_boot_iso(self.compose, 'x86_64', self.compose.variants['Server'], True)
tgt = self.topdir + '/compose/Server/x86_64/iso/image-name'
self.assertTrue(os.path.isfile(tgt))
@ -703,6 +704,7 @@ class TestSymlinkIso(PungiTestCase):
self.assertEqual(image.disc_count, 1)
self.assertEqual(image.bootable, True)
self.assertEqual(image.implant_md5, IsoWrapper.get_implanted_md5.return_value)
self.assertEqual(image.can_fail, True)
self.assertEqual(self.compose.im.add.mock_calls,
[mock.call('Server', 'x86_64', image)])

View File

@ -71,6 +71,7 @@ class TestImageBuildPhase(PungiTestCase):
"relative_image_dir": 'Client/%(arch)s/images',
"link_type": 'hardlink-or-copy',
"scratch": False,
"failable_arches": [],
}
server_args = {
"format": [('docker', 'tar.xz')],
@ -95,6 +96,7 @@ class TestImageBuildPhase(PungiTestCase):
"relative_image_dir": 'Server/%(arch)s/images',
"link_type": 'hardlink-or-copy',
"scratch": False,
"failable_arches": [],
}
self.maxDiff = None
self.assertItemsEqual(phase.pool.queue_put.mock_calls,
@ -155,6 +157,7 @@ class TestImageBuildPhase(PungiTestCase):
"relative_image_dir": 'Server/%(arch)s/images',
"link_type": 'hardlink-or-copy',
"scratch": False,
"failable_arches": [],
}
self.maxDiff = None
self.assertItemsEqual(phase.pool.queue_put.mock_calls,
@ -249,6 +252,7 @@ class TestImageBuildPhase(PungiTestCase):
"relative_image_dir": 'Server/%(arch)s/images',
"link_type": 'hardlink-or-copy',
"scratch": False,
"failable_arches": [],
})
@mock.patch('pungi.phases.image_build.ThreadPool')
@ -310,6 +314,7 @@ class TestImageBuildPhase(PungiTestCase):
"relative_image_dir": 'Server/%(arch)s/images',
"link_type": 'hardlink-or-copy',
"scratch": False,
"failable_arches": [],
})
@mock.patch('pungi.phases.image_build.ThreadPool')
@ -370,6 +375,7 @@ class TestImageBuildPhase(PungiTestCase):
"relative_image_dir": 'Server/%(arch)s/images',
"link_type": 'hardlink-or-copy',
"scratch": False,
"failable_arches": [],
})
@mock.patch('pungi.phases.image_build.ThreadPool')
@ -621,14 +627,7 @@ class TestCreateImageBuildThread(PungiTestCase):
@mock.patch('pungi.phases.image_build.KojiWrapper')
@mock.patch('pungi.phases.image_build.Linker')
def test_process_handle_fail(self, Linker, KojiWrapper):
compose = DummyCompose(self.topdir, {
'koji_profile': 'koji',
'failable_deliverables': [
('^.*$', {
'*': ['image-build']
})
]
})
compose = DummyCompose(self.topdir, {'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
"format": [('docker', 'tar.xz'), ('qcow2', 'qcow2')],
@ -653,6 +652,7 @@ class TestCreateImageBuildThread(PungiTestCase):
"relative_image_dir": 'image_dir/Client/%(arch)s',
"link_type": 'hardlink-or-copy',
'scratch': False,
"failable_arches": ['*'],
}
koji_wrapper = KojiWrapper.return_value
koji_wrapper.run_blocking_cmd.return_value = {
@ -675,14 +675,7 @@ class TestCreateImageBuildThread(PungiTestCase):
@mock.patch('pungi.phases.image_build.KojiWrapper')
@mock.patch('pungi.phases.image_build.Linker')
def test_process_handle_exception(self, Linker, KojiWrapper):
compose = DummyCompose(self.topdir, {
'koji_profile': 'koji',
'failable_deliverables': [
('^.*$', {
'*': ['image-build']
})
]
})
compose = DummyCompose(self.topdir, {'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
"format": [('docker', 'tar.xz'), ('qcow2', 'qcow2')],
@ -707,6 +700,7 @@ class TestCreateImageBuildThread(PungiTestCase):
"relative_image_dir": 'image_dir/Client/%(arch)s',
"link_type": 'hardlink-or-copy',
'scratch': False,
"failable_arches": ['*'],
}
koji_wrapper = KojiWrapper.return_value

View File

@ -56,6 +56,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'live',
'release': '20151203.t.0',
'subvariant': 'Client',
'failable_arches': [],
'ksurl': None},
compose.variants['Client'],
'amd64'))])
@ -104,6 +105,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'live',
'release': '20151203.t.0',
'subvariant': 'Client',
'failable_arches': [],
'ksurl': None},
compose.variants['Client'],
'amd64'))])
@ -149,6 +151,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'live',
'release': '20151203.t.0',
'subvariant': 'Client',
'failable_arches': [],
'ksurl': None},
compose.variants['Client'],
'amd64'))])
@ -196,6 +199,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'live',
'release': None,
'subvariant': 'Client',
'failable_arches': [],
'ksurl': None},
compose.variants['Client'],
'amd64')),
@ -216,6 +220,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'live',
'release': None,
'subvariant': 'Client',
'failable_arches': [],
'ksurl': None},
compose.variants['Client'],
'amd64'))])
@ -264,6 +269,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'appliance',
'release': None,
'subvariant': 'Client',
'failable_arches': [],
'ksurl': 'https://git.example.com/kickstarts.git?#CAFEBABE'},
compose.variants['Client'],
'amd64'))])
@ -316,6 +322,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'appliance',
'release': '20151203.t.0',
'subvariant': 'Client',
'failable_arches': [],
'ksurl': 'https://git.example.com/kickstarts.git?#CAFEBABE'},
compose.variants['Client'],
'amd64'))])
@ -368,6 +375,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'appliance',
'release': '20151203.t.0',
'subvariant': 'Client',
'failable_arches': [],
'ksurl': 'https://git.example.com/kickstarts.git?#CAFEBABE'},
compose.variants['Client'],
'amd64'))])
@ -415,6 +423,7 @@ class TestLiveImagesPhase(PungiTestCase):
'type': 'live',
'release': '20151203.t.0',
'subvariant': 'Client',
'failable_arches': [],
'ksurl': None},
compose.variants['Client'],
'amd64'))])
@ -665,10 +674,7 @@ class TestCreateLiveImageThread(PungiTestCase):
@mock.patch('pungi.phases.live_images.run')
@mock.patch('pungi.phases.live_images.KojiWrapper')
def test_process_handles_fail(self, KojiWrapper, run, copy2):
compose = DummyCompose(self.topdir, {
'koji_profile': 'koji',
'failable_deliverables': [('^.+$', {'*': ['live']})],
})
compose = DummyCompose(self.topdir, {'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
'ks_file': '/path/to/ks_file',
@ -687,6 +693,7 @@ class TestCreateLiveImageThread(PungiTestCase):
'subvariant': 'Client',
'release': 'xyz',
'type': 'live',
'failable_arches': ['*'],
}
koji_wrapper = KojiWrapper.return_value
@ -711,10 +718,7 @@ class TestCreateLiveImageThread(PungiTestCase):
@mock.patch('pungi.phases.live_images.run')
@mock.patch('pungi.phases.live_images.KojiWrapper')
def test_process_handles_exception(self, KojiWrapper, run, copy2):
compose = DummyCompose(self.topdir, {
'koji_profile': 'koji',
'failable_deliverables': [('^.+$', {'*': ['live']})],
})
compose = DummyCompose(self.topdir, {'koji_profile': 'koji'})
pool = mock.Mock()
cmd = {
'ks_file': '/path/to/ks_file',
@ -733,6 +737,7 @@ class TestCreateLiveImageThread(PungiTestCase):
'subvariant': 'Client',
'release': 'xyz',
'type': 'live',
'failable_arches': ['*'],
}
koji_wrapper = KojiWrapper.return_value

View File

@ -73,6 +73,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
'subvariant': 'Server',
'failable_arches': [],
}))])
@mock.patch('pungi.util.resolve_git_url')
@ -133,6 +134,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
'subvariant': 'Server',
'failable_arches': [],
})),
mock.call((compose,
compose.variants['Server'],
@ -151,6 +153,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
'subvariant': 'Server',
'failable_arches': [],
})),
mock.call((compose,
compose.variants['Server'],
@ -169,6 +172,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': '25',
'subvariant': 'Server',
'failable_arches': [],
}))])
@mock.patch('pungi.util.resolve_git_url')
@ -229,6 +233,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
'subvariant': 'Server',
'failable_arches': [],
})),
mock.call((compose,
compose.variants['Server'],
@ -247,6 +252,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': 'Rawhide',
'subvariant': 'Server',
'failable_arches': [],
})),
mock.call((compose,
compose.variants['Server'],
@ -265,6 +271,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Server/$basearch/os',
'version': '25',
'subvariant': 'Server',
'failable_arches': [],
}))])
@mock.patch('pungi.phases.livemedia_phase.ThreadPool')
@ -335,6 +342,7 @@ class TestLiveMediaPhase(PungiTestCase):
'version': 'Rawhide',
'install_tree_from': 'Everything',
'subvariant': 'Something',
'failable': ['*'],
}
]
}
@ -366,6 +374,7 @@ class TestLiveMediaPhase(PungiTestCase):
'install_tree': self.topdir + '/compose/Everything/$basearch/os',
'version': 'Rawhide',
'subvariant': 'Something',
'failable_arches': ['*'],
}))])
@ -393,6 +402,7 @@ class TestLiveMediaThread(PungiTestCase):
'title': None,
'version': 'Rawhide',
'subvariant': 'KDE',
'failable_arches': [],
}
pool = mock.Mock()
@ -479,9 +489,6 @@ class TestLiveMediaThread(PungiTestCase):
def test_handle_koji_fail(self, KojiWrapper, get_file_size, get_mtime):
compose = DummyCompose(self.topdir, {
'koji_profile': 'koji',
'failable_deliverables': [
('^.+$', {'*': ['live-media']})
]
})
config = {
'arches': ['amd64', 'x86_64'],
@ -497,6 +504,7 @@ class TestLiveMediaThread(PungiTestCase):
'title': None,
'version': 'Rawhide',
'subvariant': 'KDE',
'failable_arches': ['*'],
}
pool = mock.Mock()
@ -543,6 +551,7 @@ class TestLiveMediaThread(PungiTestCase):
'title': None,
'version': 'Rawhide',
'subvariant': 'KDE',
'failable_arches': ['*'],
}
pool = mock.Mock()

View File

@ -231,6 +231,21 @@ class OSBSThreadTest(helpers.PungiTestCase):
self._assertCorrectCalls({})
self._assertCorrectMetadata()
@mock.patch('pungi.util.resolve_git_url')
@mock.patch('pungi.phases.osbs.kojiwrapper.KojiWrapper')
def test_run_failable(self, KojiWrapper, resolve_git_url):
cfg = {
'url': 'git://example.com/repo?#HEAD',
'target': 'f24-docker-candidate',
'failable': ['*']
}
self._setupMock(KojiWrapper, resolve_git_url)
self.t.process((self.compose, self.compose.variants['Server'], cfg), 1)
self._assertCorrectCalls({})
self._assertCorrectMetadata()
@mock.patch('pungi.util.resolve_git_url')
@mock.patch('pungi.phases.osbs.kojiwrapper.KojiWrapper')
def test_run_with_more_args(self, KojiWrapper, resolve_git_url):
@ -296,10 +311,10 @@ class OSBSThreadTest(helpers.PungiTestCase):
cfg = {
'url': 'git://example.com/repo?#HEAD',
'target': 'fedora-24-docker-candidate',
'failable': ['*']
}
self._setupMock(KojiWrapper, resolve_git_url)
self.wrapper.watch_task.return_value = 1
self.compose.conf['failable_deliverables'] = [('.*', {'*': ['osbs']})]
self.t.process((self.compose, self.compose.variants['Server'], cfg), 1)

View File

@ -432,14 +432,12 @@ class OstreeThreadTest(helpers.PungiTestCase):
'release_version': 'Rawhide',
'koji_profile': 'koji',
'runroot_tag': 'rrt',
'failable_deliverables': [
('^.+$', {'*': ['ostree-installer']})
],
})
pool = mock.Mock()
cfg = {
'source_repo_from': 'Everything',
'release': None,
'failable': ['x86_64']
}
koji = KojiWrapper.return_value
koji.run_runroot_cmd.side_effect = helpers.boom
@ -466,14 +464,12 @@ class OstreeThreadTest(helpers.PungiTestCase):
'release_version': 'Rawhide',
'koji_profile': 'koji',
'runroot_tag': 'rrt',
'failable_deliverables': [
('^.+$', {'*': ['ostree-installer']})
],
})
pool = mock.Mock()
cfg = {
'source_repo_from': 'Everything',
'release': None,
'failable': ['*'],
}
koji = KojiWrapper.return_value
koji.run_runroot_cmd.return_value = {

View File

@ -155,9 +155,6 @@ class OSTreeThreadTest(helpers.PungiTestCase):
compose = helpers.DummyCompose(self.topdir, {
'koji_profile': 'koji',
'runroot_tag': 'rrt',
'failable_deliverables': [
('^.*$', {'*': ['ostree']})
]
})
pool = mock.Mock()
cfg = {
@ -166,6 +163,7 @@ class OSTreeThreadTest(helpers.PungiTestCase):
'config_branch': 'f24',
'treefile': 'fedora-atomic-docker-host.json',
'ostree_repo': self.repo,
'failable': ['*']
}
koji = KojiWrapper.return_value
koji.run_runroot_cmd.return_value = {
@ -192,9 +190,6 @@ class OSTreeThreadTest(helpers.PungiTestCase):
compose = helpers.DummyCompose(self.topdir, {
'koji_profile': 'koji',
'runroot_tag': 'rrt',
'failable_deliverables': [
('^.*$', {'*': ['ostree']})
]
})
pool = mock.Mock()
cfg = {
@ -203,6 +198,7 @@ class OSTreeThreadTest(helpers.PungiTestCase):
'config_branch': 'f24',
'treefile': 'fedora-atomic-docker-host.json',
'ostree_repo': self.repo,
'failable': ['*']
}
koji = KojiWrapper.return_value
koji.run_runroot_cmd.side_effect = helpers.boom

View File

@ -17,12 +17,6 @@ import pungi.phases.test as test_phase
from tests.helpers import DummyCompose, PungiTestCase, touch
FAILABLE_CONFIG = {
'failable_deliverables': [
('^.+$', {'*': ['iso']}),
]
}
PAD = '\0' * 100
UNBOOTABLE_ISO = ('\0' * 0x8001) + 'CD001' + PAD
ISO_WITH_MBR = ('\0' * 0x1fe) + '\x55\xAA' + ('\0' * 0x7e01) + 'CD001' + PAD
@ -40,8 +34,9 @@ class TestCheckImageSanity(PungiTestCase):
test_phase.check_image_sanity(compose)
def test_missing_file_doesnt_report_if_failable(self):
compose = DummyCompose(self.topdir, FAILABLE_CONFIG)
compose = DummyCompose(self.topdir, {})
compose.image.deliverable = 'iso'
compose.image.can_fail = True
try:
test_phase.check_image_sanity(compose)
@ -83,10 +78,11 @@ class TestCheckImageSanity(PungiTestCase):
str(ctx.exception))
def test_failable_bootable_iso_without_mbr_gpt_doesnt_raise(self):
compose = DummyCompose(self.topdir, FAILABLE_CONFIG)
compose = DummyCompose(self.topdir, {})
compose.image.format = 'iso'
compose.image.bootable = True
compose.image.deliverable = 'iso'
compose.image.can_fail = True
touch(os.path.join(self.topdir, 'compose', compose.image.path), UNBOOTABLE_ISO)
try: