Allow reusing old buildinstall phase results.

New `buildinstall.metadata` file is created once the buildinstall
phase is done. This file contains:

- list of lorax command line arguments.
- list of RPMs installed in the buildinstall buildroot.
- list of RPMs installed in the resulting boot.iso.

This file is checked in the next compose run to find out if
the result of buildinstall phase from the previous compose
can be reused. Following is checked:

- lorax commandline arguments are the same (except of expected
  differences).
- The NVRAs of RPMs in the runroot_tag are the same as the ones
  installed in the old buildinstall buildroot.
- The NVRAs of RPMs installed in the boot.iso are the same as
  the ones in package sets in the current compose.

By its implementation, this reuse strategy is used only if
pungi_buildinstall Koji plugin is used.

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>

Add tests for buildinstall reuse and buildinstall_allow_reuse option.

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
This commit is contained in:
Jan Kaluza 2020-04-01 10:00:48 +02:00 committed by lsedlar
parent 3509d7a36c
commit 5395af416c
6 changed files with 492 additions and 42 deletions

View File

@ -569,7 +569,9 @@ Options
(*list*) -- mapping that defines which variants and arches to skip during
buildinstall; format: ``[(variant_uid_regex, {arch|*: True})]``. This is
only supported for lorax.
**buildinstall_allow_reuse** = False
(*bool*) -- When set to ``True``, *Pungi* will try to reuse buildinstall
results from old compose specified by ``--old-composes``.
Example
-------

View File

@ -748,6 +748,7 @@ def make_schema():
_variant_arch_mapping({"type": "boolean"}),
]
},
"buildinstall_allow_reuse": {"type": "boolean", "default": False},
"buildinstall_method": {
"type": "string",
"enum": ["lorax", "buildinstall"],

View File

@ -19,9 +19,12 @@ import os
import time
import shutil
import re
from six.moves import cPickle as pickle
from copy import copy
from kobo.threads import ThreadPool, WorkerThread
from kobo.shortcuts import run, force_list
import kobo.rpmlib
from productmd.images import Image
from six.moves import shlex_quote
@ -32,6 +35,7 @@ from pungi.util import copy_all, translate_path, move_all
from pungi.wrappers.lorax import LoraxWrapper
from pungi.wrappers import iso
from pungi.wrappers.scm import get_file_from_scm
from pungi.wrappers import kojiwrapper
from pungi.phases.base import PhaseBase
from pungi.runroot import Runroot
@ -268,7 +272,9 @@ class BuildinstallPhase(PhaseBase):
for (variant, cmd) in commands:
self.pool.add(BuildinstallThread(self.pool))
self.pool.queue_put((self.compose, arch, variant, cmd))
self.pool.queue_put(
(self.compose, arch, variant, cmd, self.pkgset_phase)
)
self.pool.start()
@ -495,12 +501,224 @@ def link_boot_iso(compose, arch, variant, can_fail):
class BuildinstallThread(WorkerThread):
def process(self, item, num):
# The variant is None unless lorax is used as buildinstall method.
compose, arch, variant, cmd = item
compose, arch, variant, cmd, pkgset_phase = item
can_fail = compose.can_fail(variant, arch, "buildinstall")
with failable(compose, can_fail, variant, arch, "buildinstall"):
self.worker(compose, arch, variant, cmd, num)
self.worker(compose, arch, variant, cmd, pkgset_phase, num)
def worker(self, compose, arch, variant, cmd, num):
def _generate_buildinstall_metadata(
self, compose, arch, variant, cmd, buildroot_rpms, pkgset_phase
):
"""
Generate buildinstall.metadata dict.
:param Compose compose: Current compose.
:param str arch: Current architecture.
:param Variant variant: Compose variant.
:param list cmd: List of command line arguments passed to buildinstall task.
:param list buildroot_rpms: List of NVRAs of all RPMs installed in the
buildinstall task's buildroot.
:param PkgsetPhase pkgset_phase: Package set phase instance.
:return: The buildinstall.metadata dict.
"""
# Load the list of packages installed in the boot.iso.
# The list of installed packages is logged by Lorax in the "pkglists"
# directory. There is one file for each installed RPM and the name
# of the file is the name of the RPM.
# We need to resolve the name of each RPM back to its NVRA.
installed_rpms = []
log_fname = "buildinstall-%s-logs/dummy" % variant.uid
log_dir = os.path.dirname(compose.paths.log.log_file(arch, log_fname, False))
pkglists_dir = os.path.join(log_dir, "pkglists")
if os.path.exists(pkglists_dir):
for pkg_name in os.listdir(pkglists_dir):
for pkgset in pkgset_phase.package_sets:
global_pkgset = pkgset["global"]
# We actually do not care from which package_set the RPM
# came from or if there are multiple versions/release of
# the single RPM in more packages sets. We simply include
# all RPMs with this name in the metadata.
# Later when deciding if the buildinstall phase results
# can be reused, we check that all the RPMs with this name
# are still the same in old/new compose.
for rpm_path, rpm_obj in global_pkgset.file_cache.items():
if rpm_obj.name == pkg_name:
installed_rpms.append(rpm_path)
# Store the metadata in `buildinstall.metadata`.
metadata = {
"cmd": cmd,
"buildroot_rpms": sorted(buildroot_rpms),
"installed_rpms": sorted(installed_rpms),
}
return metadata
def _write_buildinstall_metadata(
self, compose, arch, variant, cmd, buildroot_rpms, pkgset_phase
):
"""
Write buildinstall.metadata file containing all the information about
buildinstall phase input and environment.
This file is later used to decide whether old buildinstall results can
be reused instead of generating them again.
:param Compose compose: Current compose.
:param str arch: Current architecture.
:param Variant variant: Compose variant.
:param list cmd: List of command line arguments passed to buildinstall task.
:param list buildroot_rpms: List of NVRAs of all RPMs installed in the
buildinstall task's buildroot.
:param PkgsetPhase pkgset_phase: Package set phase instance.
"""
# Generate the list of `*-RPMs` log file.
log_filename = ("buildinstall-%s" % variant.uid) if variant else "buildinstall"
log_file = compose.paths.log.log_file(arch, log_filename + "-RPMs")
with open(log_file, "w") as f:
f.write("\n".join(buildroot_rpms))
# Write buildinstall.metadata only if particular variant is defined.
# The `variant` is `None` only if old "buildinstall" method is used.
if not variant:
return
metadata = self._generate_buildinstall_metadata(
compose, arch, variant, cmd, buildroot_rpms, pkgset_phase
)
log_fname = "buildinstall-%s-logs/dummy" % variant.uid
log_dir = os.path.dirname(compose.paths.log.log_file(arch, log_fname))
metadata_path = os.path.join(log_dir, "buildinstall.metadata")
with open(metadata_path, "wb") as f:
pickle.dump(metadata, f, protocol=pickle.HIGHEST_PROTOCOL)
def _load_old_buildinstall_metadata(self, compose, arch, variant):
"""
Helper method to load "buildinstall.metadata" from old compose.
:param Compose compose: Current compose.
:param str arch: Current architecture.
:param Variant variant: Compose variant.
"""
if not variant:
return None
log_fname = "buildinstall-%s-logs/dummy" % variant.uid
metadata = os.path.join(
os.path.dirname(compose.paths.log.log_file(arch, log_fname)),
"buildinstall.metadata",
)
old_metadata = compose.paths.old_compose_path(metadata)
if not old_metadata:
return None
compose.log_info("Loading old BUILDINSTALL phase metadata: %s", old_metadata)
with open(old_metadata, "rb") as f:
old_result = pickle.load(f)
return old_result
def _reuse_old_buildinstall_result(self, compose, arch, variant, cmd, pkgset_phase):
"""
Try to reuse old buildinstall results.
:param Compose compose: Current compose.
:param str arch: Current architecture.
:param Variant variant: Compose variant.
:param list cmd: List of command line arguments passed to buildinstall task.
:param list buildroot_rpms: List of NVRAs of all RPMs installed in the
buildinstall task's buildroot.
:param PkgsetPhase pkgset_phase: Package set phase instance.
:return: True if old buildinstall phase results have been reused.
"""
log_msg = "Cannot reuse old BUILDINSTALL phase results - %s"
if not compose.conf["buildinstall_allow_reuse"]:
compose.log_info(log_msg % "reuse of old buildinstall results is disabled.")
return
# Load the old buildinstall.metadata.
old_metadata = self._load_old_buildinstall_metadata(compose, arch, variant)
if old_metadata is None:
compose.log_info(log_msg % "no old BUILDINSTALL metadata.")
return
# For now try to reuse only if pungi_buildinstall plugin is used.
# This is the easiest approach, because we later need to filter out
# some parts of `cmd` and for pungi_buildinstall, the `cmd` is a dict
# which makes this easy.
if not isinstance(old_metadata["cmd"], dict) or not isinstance(cmd, dict):
compose.log_info(log_msg % "pungi_buildinstall plugin is not used.")
return
# Filter out "outputdir" and "sources" because they change everytime.
# The "sources" are not important, because we check the buildinstall
# input on RPM level.
cmd_copy = copy(cmd)
for key in ["outputdir", "sources"]:
del cmd_copy[key]
del old_metadata["cmd"][key]
# Do not reuse if command line arguments are not the same.
if old_metadata["cmd"] != cmd_copy:
compose.log_info(log_msg % "lorax command line arguments differ.")
return
# Check that the RPMs installed in the old boot.iso exists in the very
# same versions/releases in this compose.
for rpm_path in old_metadata["installed_rpms"]:
found = False
for pkgset in pkgset_phase.package_sets:
global_pkgset = pkgset["global"]
if rpm_path in global_pkgset.file_cache:
found = True
break
if not found:
compose.log_info(
log_msg % "RPM %s does not exist in new compose." % rpm_path
)
return
# Ask Koji for all the RPMs in the `runroot_tag` and check that
# those installed in the old buildinstall buildroot are still in the
# very same versions/releases.
koji_wrapper = kojiwrapper.KojiWrapper(compose.conf["koji_profile"])
rpms = koji_wrapper.koji_proxy.listTaggedRPMS(
compose.conf.get("runroot_tag"), inherit=True, latest=True
)[0]
rpm_nvras = set()
for rpm in rpms:
rpm_nvras.add(kobo.rpmlib.make_nvra(rpm, add_rpm=False, force_epoch=False))
for old_nvra in old_metadata["buildroot_rpms"]:
if old_nvra not in rpm_nvras:
compose.log_info(
log_msg % "RPM %s does not exist in new buildroot." % old_nvra
)
return
# We can reuse the old buildinstall results!
compose.log_info("Reusing old BUILDINSTALL phase output")
# Copy old buildinstall output to this this compose.
final_output_dir = compose.paths.work.buildinstall_dir(arch, variant=variant)
old_final_output_dir = compose.paths.old_compose_path(final_output_dir)
copy_all(old_final_output_dir, final_output_dir)
# Copy old buildinstall logs to this compose.
log_fname = "buildinstall-%s-logs/dummy" % variant.uid
final_log_dir = os.path.dirname(compose.paths.log.log_file(arch, log_fname))
old_final_log_dir = compose.paths.old_compose_path(final_log_dir)
if not os.path.exists(final_log_dir):
makedirs(final_log_dir)
copy_all(old_final_log_dir, final_log_dir)
# Write the buildinstall metadata so next compose can reuse this compose.
self._write_buildinstall_metadata(
compose, arch, variant, cmd, old_metadata["buildroot_rpms"], pkgset_phase
)
return True
def worker(self, compose, arch, variant, cmd, pkgset_phase, num):
buildinstall_method = compose.conf["buildinstall_method"]
lorax_use_koji_plugin = compose.conf["lorax_use_koji_plugin"]
log_filename = ("buildinstall-%s" % variant.uid) if variant else "buildinstall"
@ -536,6 +754,14 @@ class BuildinstallThread(WorkerThread):
elif buildinstall_method == "buildinstall":
packages += ["anaconda"]
if self._reuse_old_buildinstall_result(
compose, arch, variant, cmd, pkgset_phase
):
self.copy_files(compose, variant, arch)
self.pool.finished_tasks.add((variant.uid if variant else None, arch))
self.pool.log_info("[DONE ] %s" % msg)
return
# This should avoid a possible race condition with multiple processes
# trying to get a kerberos ticket at the same time.
# Kerberos authentication failed:
@ -592,15 +818,15 @@ class BuildinstallThread(WorkerThread):
log_dir = os.path.join(output_dir, "logs")
move_all(log_dir, final_log_dir, rm_src_dir=True)
log_file = compose.paths.log.log_file(arch, log_filename + "-RPMs")
rpms = runroot.get_buildroot_rpms()
with open(log_file, "w") as f:
f.write("\n".join(rpms))
self.pool.finished_tasks.add((variant.uid if variant else None, arch))
self._write_buildinstall_metadata(
compose, arch, variant, cmd, rpms, pkgset_phase
)
self.copy_files(compose, variant, arch)
self.pool.finished_tasks.add((variant.uid if variant else None, arch))
self.pool.log_info("[DONE ] %s" % msg)
def copy_files(self, compose, variant, arch):

View File

@ -129,6 +129,29 @@ class MockVariant(mock.Mock):
return module_stream
class MockPackageSet(dict):
def __init__(self, *args):
for pkg in args:
self[pkg.path] = pkg
class MockPkg(object):
def __init__(self, path, is_system_release=False, **kwargs):
self.path = path
self.is_system_release = is_system_release
filename = os.path.basename(path)
self.nvr, self.arch, _ = filename.rsplit(".", 2)
self.name, self.version, self.release = self.nvr.rsplit("-", 2)
for k, v in kwargs.items():
setattr(self, k, v)
def __repr__(self):
return self.nvr
def __lt__(self, another):
return self.nvr < another.nvr
class IterableMock(mock.Mock):
def __iter__(self):
return iter([])

View File

@ -3,6 +3,7 @@
import mock
import six
from copy import copy
import os
@ -13,7 +14,7 @@ from pungi.phases.buildinstall import (
BOOT_CONFIGS,
tweak_configs,
)
from tests.helpers import DummyCompose, PungiTestCase, touch
from tests.helpers import DummyCompose, PungiTestCase, touch, MockPackageSet, MockPkg
class BuildInstallCompose(DummyCompose):
@ -1100,7 +1101,7 @@ class BuildinstallThreadTestCase(PungiTestCase):
def setUp(self):
super(BuildinstallThreadTestCase, self).setUp()
self.pool = mock.Mock(finished_tasks=set())
self.cmd = mock.Mock()
self.cmd = ["echo", "1"]
@mock.patch("pungi.phases.buildinstall.link_boot_iso")
@mock.patch("pungi.phases.buildinstall.tweak_buildinstall")
@ -1134,7 +1135,11 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "x86_64", compose.variants["Server"], self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process(
(compose, "x86_64", compose.variants["Server"], self.cmd, pkgset_phase),
0,
)
destdir = os.path.join(self.topdir, "work/x86_64/buildinstall/Server")
self.assertEqual(
@ -1231,7 +1236,11 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "x86_64", compose.variants["Server"], self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process(
(compose, "x86_64", compose.variants["Server"], self.cmd, pkgset_phase),
0,
)
destdir = os.path.join(self.topdir, "work/x86_64/buildinstall/Server")
self.assertEqual(
@ -1328,7 +1337,8 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "amd64", None, self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process((compose, "amd64", None, self.cmd, pkgset_phase), 0)
destdir = os.path.join(self.topdir, "work/amd64/buildinstall")
self.assertEqual(
@ -1414,7 +1424,8 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "x86_64", None, self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process((compose, "x86_64", None, self.cmd, pkgset_phase), 0)
compose._logger.error.assert_has_calls(
[
@ -1455,7 +1466,11 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "x86_64", compose.variants["Server"], self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process(
(compose, "x86_64", compose.variants["Server"], self.cmd, pkgset_phase),
0,
)
compose._logger.error.assert_has_calls(
[
@ -1494,7 +1509,11 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "x86_64", compose.variants["Server"], self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process(
(compose, "x86_64", compose.variants["Server"], self.cmd, pkgset_phase),
0,
)
self.assertEqual(0, len(run.mock_calls))
@ -1535,7 +1554,11 @@ class BuildinstallThreadTestCase(PungiTestCase):
t = BuildinstallThread(self.pool)
with mock.patch("time.sleep"):
t.process((compose, "x86_64", compose.variants["Server"], self.cmd), 0)
pkgset_phase = self._make_pkgset_phase(["p1"])
t.process(
(compose, "x86_64", compose.variants["Server"], self.cmd, pkgset_phase),
0,
)
self.assertEqual(
get_runroot_cmd.mock_calls,
@ -1613,6 +1636,203 @@ class BuildinstallThreadTestCase(PungiTestCase):
[mock.call(compose, "x86_64", compose.variants["Server"], False)],
)
def _prepare_buildinstall_reuse_test(self):
compose = BuildInstallCompose(
self.topdir,
{
"buildinstall_allow_reuse": True,
"buildinstall_method": "lorax",
"runroot_tag": "rrt",
"koji_profile": "koji",
},
)
pkgset = MockPackageSet(
MockPkg("/build/kernel-1.0.0-1.x86_64.rpm"),
MockPkg("/build/kernel-1.0.0-1.i686.rpm"),
MockPkg("/build/bash-1.0.0-1.x86_64.rpm"),
)
pkgset.file_cache = pkgset
pkgsets = [{"global": pkgset, "x86_64": pkgset}]
pkgset_phase = mock.Mock(package_sets=pkgsets)
cmd = {
"add-arch-template": [],
"buildarch": "x86_64",
"outputdir": self.topdir,
"product": "Fedora",
"release": "31",
"sources": ["/tmp/test/repo"],
"variant": "Server",
"version": "1",
}
return compose, pkgset_phase, cmd
@mock.patch("os.listdir")
@mock.patch("os.path.exists")
def test_generate_buildinstall_metadata(self, exists, listdir):
compose, pkgset_phase, cmd = self._prepare_buildinstall_reuse_test()
buildroot_rpms = ["bash-1-1.x86_64", "httpd-1-1.x86_64"]
listdir.return_value = ["kernel"]
t = BuildinstallThread(self.pool)
metadata = t._generate_buildinstall_metadata(
compose,
"x86_64",
compose.variants["Server"],
cmd,
buildroot_rpms,
pkgset_phase,
)
self.assertEqual(metadata["cmd"], cmd)
self.assertEqual(metadata["buildroot_rpms"], buildroot_rpms)
self.assertEqual(
metadata["installed_rpms"],
["/build/kernel-1.0.0-1.i686.rpm", "/build/kernel-1.0.0-1.x86_64.rpm"],
)
@mock.patch(
"pungi.phases.buildinstall.BuildinstallThread._write_buildinstall_metadata"
)
@mock.patch(
"pungi.phases.buildinstall.BuildinstallThread._load_old_buildinstall_metadata"
)
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
@mock.patch("pungi.phases.buildinstall.copy_all")
def test_reuse_old_buildinstall_result(
self,
copy_all,
KojiWrapperMock,
load_old_buildinstall_metadata,
write_buildinstall_metadata,
):
compose, pkgset_phase, cmd = self._prepare_buildinstall_reuse_test()
listTaggedRPMS = KojiWrapperMock.return_value.koji_proxy.listTaggedRPMS
listTaggedRPMS.return_value = [
[{"name": "bash", "version": "1", "release": 1, "arch": "x86_64"}],
[],
]
load_old_buildinstall_metadata.return_value = {
"cmd": cmd,
"installed_rpms": ["/build/kernel-1.0.0-1.x86_64.rpm"],
"buildroot_rpms": ["bash-1-1.x86_64"],
}
t = BuildinstallThread(self.pool)
with mock.patch.object(compose.paths, "old_compose_path") as old_compose_path:
old_compose_path.side_effect = ["/tmp/old/1", "/tmp/old/2"]
ret = t._reuse_old_buildinstall_result(
compose, "x86_64", compose.variants["Server"], cmd, pkgset_phase
)
self.assertEqual(ret, True)
self.assertEqual(
copy_all.mock_calls,
[
mock.call(
"/tmp/old/1",
os.path.join(self.topdir, "work/x86_64/buildinstall/Server"),
),
mock.call(
"/tmp/old/2",
os.path.join(self.topdir, "logs/x86_64/buildinstall-Server-logs"),
),
],
)
write_buildinstall_metadata.assert_called_once_with(
compose,
"x86_64",
compose.variants["Server"],
cmd,
["bash-1-1.x86_64"],
pkgset_phase,
)
@mock.patch(
"pungi.phases.buildinstall.BuildinstallThread._load_old_buildinstall_metadata"
)
def test_reuse_old_buildinstall_result_no_old_compose(
self, load_old_buildinstall_metadata,
):
compose, pkgset_phase, cmd = self._prepare_buildinstall_reuse_test()
load_old_buildinstall_metadata.return_value = None
t = BuildinstallThread(self.pool)
ret = t._reuse_old_buildinstall_result(
compose, "x86_64", compose.variants["Server"], cmd, pkgset_phase
)
self.assertEqual(ret, None)
@mock.patch(
"pungi.phases.buildinstall.BuildinstallThread._load_old_buildinstall_metadata"
)
def test_reuse_old_buildinstall_result_different_cmd(
self, load_old_buildinstall_metadata,
):
compose, pkgset_phase, cmd = self._prepare_buildinstall_reuse_test()
old_cmd = copy(cmd)
old_cmd["version"] = "32"
load_old_buildinstall_metadata.return_value = {
"cmd": old_cmd,
"installed_rpms": ["/build/kernel-1.0.0-1.x86_64.rpm"],
"buildroot_rpms": ["bash-1-1.x86_64"],
}
t = BuildinstallThread(self.pool)
ret = t._reuse_old_buildinstall_result(
compose, "x86_64", compose.variants["Server"], cmd, pkgset_phase
)
self.assertEqual(ret, None)
@mock.patch(
"pungi.phases.buildinstall.BuildinstallThread._load_old_buildinstall_metadata"
)
def test_reuse_old_buildinstall_result_different_installed_pkgs(
self, load_old_buildinstall_metadata,
):
compose, pkgset_phase, cmd = self._prepare_buildinstall_reuse_test()
load_old_buildinstall_metadata.return_value = {
"cmd": cmd,
"installed_rpms": ["/build/kernel-1.0.0-0.x86_64.rpm"],
"buildroot_rpms": ["bash-1-1.x86_64"],
}
t = BuildinstallThread(self.pool)
ret = t._reuse_old_buildinstall_result(
compose, "x86_64", compose.variants["Server"], cmd, pkgset_phase
)
self.assertEqual(ret, None)
@mock.patch(
"pungi.phases.buildinstall.BuildinstallThread._load_old_buildinstall_metadata"
)
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_reuse_old_buildinstall_result_different_buildroot_rpms(
self, KojiWrapperMock, load_old_buildinstall_metadata,
):
compose, pkgset_phase, cmd = self._prepare_buildinstall_reuse_test()
load_old_buildinstall_metadata.return_value = {
"cmd": cmd,
"installed_rpms": ["/build/kernel-1.0.0-1.x86_64.rpm"],
"buildroot_rpms": ["bash-1-1.x86_64"],
}
listTaggedRPMS = KojiWrapperMock.return_value.koji_proxy.listTaggedRPMS
listTaggedRPMS.return_value = [
[{"name": "bash", "version": "1", "release": 2, "arch": "x86_64"}],
[],
]
t = BuildinstallThread(self.pool)
ret = t._reuse_old_buildinstall_result(
compose, "x86_64", compose.variants["Server"], cmd, pkgset_phase
)
self.assertEqual(ret, None)
class TestSymlinkIso(PungiTestCase):
def setUp(self):

View File

@ -15,29 +15,7 @@ from pungi.phases import gather
from pungi.phases.pkgset.common import MaterializedPackageSet
from pungi.phases.gather import _mk_pkg_map
from tests import helpers
class MockPackageSet(dict):
def __init__(self, *args):
for pkg in args:
self[pkg.path] = pkg
class MockPkg(object):
def __init__(self, path, is_system_release=False, **kwargs):
self.path = path
self.is_system_release = is_system_release
filename = os.path.basename(path)
self.nvr, self.arch, _ = filename.rsplit(".", 2)
self.name, self.version, self.release = self.nvr.rsplit("-", 2)
for k, v in kwargs.items():
setattr(self, k, v)
def __repr__(self):
return self.nvr
def __lt__(self, another):
return self.nvr < another.nvr
from tests.helpers import MockPackageSet, MockPkg
def _join(a, *rest):