pungi/tests/test_createiso_phase.py
Lubomír Sedlář ce2c222dc2
createiso: Block reuse if unsigned packages are allowed
We can have a compose with unsigned packages.

By the time the next compose is generated, the packages could have been
signed. However, the new compose would still reuse the ISO with unsigned
copies.

Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
(cherry picked from commit d546a49299)
2024-08-30 13:40:49 +03:00

1734 lines
59 KiB
Python

# -*- coding: utf-8 -*-
import logging
from unittest import mock
import contextlib
import six
import productmd
import os
from tests import helpers
from pungi.createiso import CreateIsoOpts
from pungi.phases import createiso
class CreateisoPhaseTest(helpers.PungiTestCase):
@mock.patch("pungi.phases.createiso.ThreadPool")
def test_skip_all(self, ThreadPool):
compose = helpers.DummyCompose(
self.topdir, {"createiso_skip": [("^.*$", {"*": True, "src": True})]}
)
pool = ThreadPool.return_value
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = mock.Mock()
phase.run()
self.assertEqual(len(pool.add.call_args_list), 0)
self.assertEqual(pool.queue_put.call_args_list, [])
@mock.patch("pungi.phases.createiso.ThreadPool")
def test_nothing_happens_without_rpms(self, ThreadPool):
compose = helpers.DummyCompose(
self.topdir,
{"release_short": "test", "release_version": "1.0", "createiso_skip": []},
)
pool = ThreadPool.return_value
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = mock.Mock()
phase.run()
self.assertEqual(len(pool.add.call_args_list), 0)
self.assertEqual(pool.queue_put.call_args_list, [])
six.assertCountEqual(
self,
phase.logger.warning.call_args_list,
[
mock.call("No RPMs found for Everything.x86_64, skipping ISO"),
mock.call("No RPMs found for Everything.amd64, skipping ISO"),
mock.call("No RPMs found for Everything.src, skipping ISO"),
mock.call("No RPMs found for Client.amd64, skipping ISO"),
mock.call("No RPMs found for Client.src, skipping ISO"),
mock.call("No RPMs found for Server.x86_64, skipping ISO"),
mock.call("No RPMs found for Server.amd64, skipping ISO"),
mock.call("No RPMs found for Server.src, skipping ISO"),
],
)
@mock.patch("pungi.createiso.write_script")
@mock.patch("pungi.phases.createiso.prepare_iso")
@mock.patch("pungi.phases.createiso.split_iso")
@mock.patch("pungi.phases.createiso.ThreadPool")
def test_start_one_worker(self, ThreadPool, split_iso, prepare_iso, write_script):
compose = helpers.DummyCompose(
self.topdir,
{"release_short": "test", "release_version": "1.0", "createiso_skip": []},
)
helpers.touch(
os.path.join(
compose.paths.compose.os_tree("x86_64", compose.variants["Server"]),
"dummy.rpm",
)
)
disc_data = mock.Mock()
split_iso.return_value = [disc_data]
prepare_iso.return_value = "dummy-graft-points"
pool = ThreadPool.return_value
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = mock.Mock()
phase.run()
self.assertEqual(
prepare_iso.call_args_list,
[
mock.call(
compose,
"x86_64",
compose.variants["Server"],
disc_count=1,
disc_num=1,
split_iso_data=disc_data,
)
],
)
self.assertEqual(
split_iso.call_args_list,
[
mock.call(
compose,
"x86_64",
compose.variants["Server"],
no_split=False,
logger=phase.logger,
)
],
)
self.assertEqual(len(pool.add.call_args_list), 1)
self.maxDiff = None
self.assertEqual(
[x[0][0] for x in write_script.call_args_list],
[
CreateIsoOpts(
output_dir="%s/compose/Server/x86_64/iso" % self.topdir,
iso_name="image-name",
volid="test-1.0 Server.x86_64",
graft_points="dummy-graft-points",
arch="x86_64",
supported=True,
jigdo_dir=None,
os_tree=None,
hfs_compat=True,
use_xorrisofs=False,
script_dir="%s/work/x86_64/tmp-Server" % self.topdir,
)
],
)
self.assertEqual(
pool.queue_put.call_args_list,
[
mock.call(
(
compose,
{
"iso_path": "%s/compose/Server/x86_64/iso/image-name"
% self.topdir,
"bootable": False,
"cmd": [
"bash",
self.topdir
+ "/work/x86_64/tmp-Server/createiso-image-name.sh",
],
"label": "",
"disc_num": 1,
"disc_count": 1,
},
compose.variants["Server"],
"x86_64",
)
)
],
)
@mock.patch("pungi.createiso.write_script")
@mock.patch("pungi.phases.createiso.prepare_iso")
@mock.patch("pungi.phases.createiso.split_iso")
@mock.patch("pungi.phases.createiso.ThreadPool")
def test_bootable(self, ThreadPool, split_iso, prepare_iso, write_script):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"buildinstall_method": "lorax",
"bootable": True,
"createiso_skip": [],
},
)
helpers.touch(
os.path.join(
compose.paths.compose.os_tree("x86_64", compose.variants["Server"]),
"dummy.rpm",
)
)
helpers.touch(
os.path.join(
compose.paths.compose.os_tree("src", compose.variants["Server"]),
"dummy.rpm",
)
)
disc_data = mock.Mock()
split_iso.return_value = [disc_data]
prepare_iso.return_value = "dummy-graft-points"
pool = ThreadPool.return_value
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = mock.Mock()
phase.run()
six.assertCountEqual(
self,
prepare_iso.call_args_list,
[
mock.call(
compose,
"x86_64",
compose.variants["Server"],
disc_count=1,
disc_num=1,
split_iso_data=disc_data,
),
mock.call(
compose,
"src",
compose.variants["Server"],
disc_count=1,
disc_num=1,
split_iso_data=disc_data,
),
],
)
six.assertCountEqual(
self,
split_iso.call_args_list,
[
mock.call(
compose,
"x86_64",
compose.variants["Server"],
no_split=True,
logger=phase.logger,
),
mock.call(
compose,
"src",
compose.variants["Server"],
no_split=False,
logger=phase.logger,
),
],
)
self.assertEqual(len(pool.add.call_args_list), 2)
self.maxDiff = None
six.assertCountEqual(
self,
[x[0][0] for x in write_script.call_args_list],
[
CreateIsoOpts(
output_dir="%s/compose/Server/x86_64/iso" % self.topdir,
boot_iso=(
"%s/compose/Server/x86_64/os/images/boot.iso" % self.topdir
),
iso_name="image-name",
volid="test-1.0 Server.x86_64",
graft_points="dummy-graft-points",
arch="x86_64",
buildinstall_method="lorax",
supported=True,
jigdo_dir=None,
os_tree=None,
hfs_compat=True,
use_xorrisofs=False,
script_dir="%s/work/x86_64/tmp-Server" % self.topdir,
),
CreateIsoOpts(
output_dir="%s/compose/Server/source/iso" % self.topdir,
iso_name="image-name",
volid="test-1.0 Server.src",
graft_points="dummy-graft-points",
arch="src",
supported=True,
jigdo_dir=None,
os_tree=None,
hfs_compat=True,
use_xorrisofs=False,
script_dir="%s/work/src/tmp-Server" % self.topdir,
),
],
)
six.assertCountEqual(
self,
pool.queue_put.call_args_list,
[
mock.call(
(
compose,
{
"iso_path": "%s/compose/Server/x86_64/iso/image-name"
% self.topdir,
"bootable": True,
"cmd": [
"bash",
self.topdir
+ "/work/x86_64/tmp-Server/createiso-image-name.sh",
],
"label": "",
"disc_num": 1,
"disc_count": 1,
},
compose.variants["Server"],
"x86_64",
)
),
mock.call(
(
compose,
{
"iso_path": "%s/compose/Server/source/iso/image-name"
% self.topdir,
"bootable": False,
"cmd": [
"bash",
self.topdir
+ "/work/src/tmp-Server/createiso-image-name.sh",
],
"label": "",
"disc_num": 1,
"disc_count": 1,
},
compose.variants["Server"],
"src",
)
),
],
)
@mock.patch("pungi.createiso.write_script")
@mock.patch("pungi.phases.createiso.prepare_iso")
@mock.patch("pungi.phases.createiso.split_iso")
@mock.patch("pungi.phases.createiso.ThreadPool")
def test_bootable_but_failed(
self, ThreadPool, split_iso, prepare_iso, write_script
):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"buildinstall_method": "lorax",
"bootable": True,
"createiso_skip": [],
},
)
helpers.touch(
os.path.join(
compose.paths.compose.os_tree("x86_64", compose.variants["Server"]),
"dummy.rpm",
)
)
helpers.touch(
os.path.join(
compose.paths.compose.os_tree("src", compose.variants["Server"]),
"dummy.rpm",
)
)
disc_data = mock.Mock()
split_iso.return_value = [disc_data]
prepare_iso.return_value = "dummy-graft-points"
pool = ThreadPool.return_value
mock_bi = mock.Mock(succeeded=lambda v, a: False)
phase = createiso.CreateisoPhase(compose, mock_bi)
phase.logger = mock.Mock()
phase.run()
self.assertEqual(
prepare_iso.call_args_list,
[
mock.call(
compose,
"src",
compose.variants["Server"],
disc_count=1,
disc_num=1,
split_iso_data=disc_data,
)
],
)
self.assertEqual(
split_iso.call_args_list,
[
mock.call(
compose,
"src",
compose.variants["Server"],
no_split=False,
logger=phase.logger,
)
],
)
self.assertEqual(len(pool.add.call_args_list), 1)
self.maxDiff = None
self.assertEqual(
[x[0][0] for x in write_script.call_args_list],
[
CreateIsoOpts(
output_dir="%s/compose/Server/source/iso" % self.topdir,
iso_name="image-name",
volid="test-1.0 Server.src",
graft_points="dummy-graft-points",
arch="src",
supported=True,
jigdo_dir=None,
os_tree=None,
hfs_compat=True,
use_xorrisofs=False,
script_dir="%s/work/src/tmp-Server" % self.topdir,
)
],
)
self.assertEqual(
pool.queue_put.call_args_list,
[
mock.call(
(
compose,
{
"iso_path": "%s/compose/Server/source/iso/image-name"
% self.topdir,
"bootable": False,
"cmd": [
"bash",
self.topdir
+ "/work/src/tmp-Server/createiso-image-name.sh",
],
"label": "",
"disc_num": 1,
"disc_count": 1,
},
compose.variants["Server"],
"src",
)
)
],
)
@mock.patch("pungi.createiso.write_script")
@mock.patch("pungi.phases.createiso.prepare_iso")
@mock.patch("pungi.phases.createiso.split_iso")
@mock.patch("pungi.phases.createiso.ThreadPool")
def test_bootable_product_but_not_variant(
self, ThreadPool, split_iso, prepare_iso, write_script
):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"buildinstall_method": "lorax",
"bootable": True,
"createiso_skip": [],
"buildinstall_skip": [("Server", {"*": True})],
"iso_hfs_ppc64le_compatible": False,
},
)
helpers.touch(
os.path.join(
compose.paths.compose.os_tree("x86_64", compose.variants["Server"]),
"dummy.rpm",
)
)
disc_data = mock.Mock()
split_iso.return_value = [disc_data]
prepare_iso.return_value = "dummy-graft-points"
pool = ThreadPool.return_value
mock_bi = mock.Mock(succeeded=lambda v, a: False)
phase = createiso.CreateisoPhase(compose, mock_bi)
phase.logger = mock.Mock()
phase.run()
self.maxDiff = None
self.assertEqual(
prepare_iso.call_args_list,
[
mock.call(
compose,
"x86_64",
compose.variants["Server"],
disc_count=1,
disc_num=1,
split_iso_data=disc_data,
)
],
)
self.assertEqual(
split_iso.call_args_list,
[
mock.call(
compose,
"x86_64",
compose.variants["Server"],
no_split=False,
logger=phase.logger,
)
],
)
self.assertEqual(len(pool.add.call_args_list), 1)
self.assertEqual(
[x[0][0] for x in write_script.call_args_list],
[
CreateIsoOpts(
output_dir="%s/compose/Server/x86_64/iso" % self.topdir,
iso_name="image-name",
volid="test-1.0 Server.x86_64",
graft_points="dummy-graft-points",
arch="x86_64",
supported=True,
jigdo_dir=None,
os_tree=None,
hfs_compat=False,
use_xorrisofs=False,
script_dir="%s/work/x86_64/tmp-Server" % self.topdir,
)
],
)
self.assertEqual(
pool.queue_put.call_args_list,
[
mock.call(
(
compose,
{
"iso_path": "%s/compose/Server/x86_64/iso/image-name"
% self.topdir,
"bootable": False,
"cmd": [
"bash",
self.topdir
+ "/work/x86_64/tmp-Server/createiso-image-name.sh",
],
"label": "",
"disc_num": 1,
"disc_count": 1,
},
compose.variants["Server"],
"x86_64",
)
)
],
)
class CreateisoThreadTest(helpers.PungiTestCase):
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_in_runroot(self, KojiWrapper, get_file_size, get_mtime, iso):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"runroot_tag": "f25-build",
"koji_profile": "koji",
"koji_cache": "/tmp",
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
get_file_size.return_value = 1024
get_mtime.return_value = 13579
getTag = KojiWrapper.return_value.koji_proxy.getTag
getTag.return_value = {"arches": "x86_64"}
get_runroot_cmd = KojiWrapper.return_value.get_runroot_cmd
run_runroot = KojiWrapper.return_value.run_runroot_cmd
run_runroot.return_value = {
"retcode": 0,
"output": "whatever",
"task_id": 1234,
}
t = createiso.CreateIsoThread(mock.Mock())
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
self.assertEqual(getTag.call_args_list, [mock.call("f25-build")])
self.assertEqual(
get_runroot_cmd.call_args_list,
[
mock.call(
"f25-build",
"x86_64",
cmd["cmd"],
channel=None,
mounts=[self.topdir],
packages=["coreutils", "genisoimage", "isomd5sum"],
use_shell=True,
weight=None,
)
],
)
self.assertEqual(
run_runroot.call_args_list,
[
mock.call(
get_runroot_cmd.return_value,
log_file="%s/logs/x86_64/createiso-image-name.x86_64.log"
% self.topdir,
)
],
)
self.assertEqual(
iso.get_implanted_md5.call_args_list,
[mock.call(cmd["iso_path"], logger=compose._logger)],
)
self.assertEqual(
iso.get_volume_id.call_args_list, [mock.call(cmd["iso_path"], False)]
)
self.assertEqual(len(compose.im.add.call_args_list), 1)
args, _ = compose.im.add.call_args_list[0]
self.assertEqual(args[0], "Server")
self.assertEqual(args[1], "x86_64")
image = args[2]
self.assertEqual(image.arch, "x86_64")
self.assertEqual(image.path, "Server/x86_64/iso/image-name")
self.assertEqual(image.format, "iso")
self.assertEqual(image.type, "dvd")
self.assertEqual(image.subvariant, "Server")
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_source_iso(self, KojiWrapper, get_file_size, get_mtime, iso):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"runroot_tag": "f25-build",
"koji_profile": "koji",
"koji_cache": "/tmp",
"create_jigdo": False,
"runroot_weights": {"createiso": 123},
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
get_file_size.return_value = 1024
get_mtime.return_value = 13579
getTag = KojiWrapper.return_value.koji_proxy.getTag
getTag.return_value = {"arches": "x86_64"}
get_runroot_cmd = KojiWrapper.return_value.get_runroot_cmd
run_runroot = KojiWrapper.return_value.run_runroot_cmd
run_runroot.return_value = {
"retcode": 0,
"output": "whatever",
"task_id": 1234,
}
t = createiso.CreateIsoThread(mock.Mock())
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "src"), 1)
self.assertEqual(getTag.call_args_list, [mock.call("f25-build")])
self.assertEqual(
get_runroot_cmd.call_args_list,
[
mock.call(
"f25-build",
"x86_64",
cmd["cmd"],
channel=None,
mounts=[self.topdir],
packages=["coreutils", "genisoimage", "isomd5sum"],
use_shell=True,
weight=123,
)
],
)
self.assertEqual(
run_runroot.call_args_list,
[
mock.call(
get_runroot_cmd.return_value,
log_file="%s/logs/src/createiso-image-name.src.log" % self.topdir,
)
],
)
self.assertEqual(
iso.get_implanted_md5.call_args_list,
[mock.call(cmd["iso_path"], logger=compose._logger)],
)
self.assertEqual(
iso.get_volume_id.call_args_list, [mock.call(cmd["iso_path"], False)]
)
self.assertEqual(len(compose.im.add.call_args_list), 2)
for args, _ in compose.im.add.call_args_list:
self.assertEqual(args[0], "Server")
self.assertIn(args[1], ["x86_64", "amd64"])
image = args[2]
self.assertEqual(image.arch, "src")
self.assertEqual(image.path, "Server/x86_64/iso/image-name")
self.assertEqual(image.format, "iso")
self.assertEqual(image.type, "dvd")
self.assertEqual(image.subvariant, "Server")
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_bootable(self, KojiWrapper, get_file_size, get_mtime, iso):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"bootable": True,
"buildinstall_method": "lorax",
"runroot_tag": "f25-build",
"koji_profile": "koji",
"koji_cache": "/tmp",
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": True,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
get_file_size.return_value = 1024
get_mtime.return_value = 13579
getTag = KojiWrapper.return_value.koji_proxy.getTag
getTag.return_value = {"arches": "x86_64"}
get_runroot_cmd = KojiWrapper.return_value.get_runroot_cmd
run_runroot = KojiWrapper.return_value.run_runroot_cmd
run_runroot.return_value = {
"retcode": 0,
"output": "whatever",
"task_id": 1234,
}
t = createiso.CreateIsoThread(mock.Mock())
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
# There is no need to call getTag if `bootable` is True.
self.assertEqual(getTag.call_args_list, [])
self.assertEqual(
get_runroot_cmd.call_args_list,
[
mock.call(
"f25-build",
"x86_64",
cmd["cmd"],
channel=None,
mounts=[self.topdir],
packages=[
"coreutils",
"genisoimage",
"isomd5sum",
"lorax",
"which",
],
use_shell=True,
weight=None,
)
],
)
self.assertEqual(
run_runroot.call_args_list,
[
mock.call(
get_runroot_cmd.return_value,
log_file="%s/logs/x86_64/createiso-image-name.x86_64.log"
% self.topdir,
)
],
)
self.assertEqual(
iso.get_implanted_md5.call_args_list,
[mock.call(cmd["iso_path"], logger=compose._logger)],
)
self.assertEqual(
iso.get_volume_id.call_args_list, [mock.call(cmd["iso_path"], False)]
)
self.assertEqual(len(compose.im.add.call_args_list), 1)
args, _ = compose.im.add.call_args_list[0]
self.assertEqual(args[0], "Server")
self.assertEqual(args[1], "x86_64")
image = args[2]
self.assertEqual(image.arch, "x86_64")
self.assertEqual(image.path, "Server/x86_64/iso/image-name")
self.assertEqual(image.format, "iso")
self.assertEqual(image.type, "dvd")
self.assertEqual(image.subvariant, "Server")
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_in_runroot_non_existing_tag(
self, KojiWrapper, get_file_size, get_mtime, iso
):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"runroot_tag": "f25-build",
"koji_profile": "koji",
"koji_cache": "/tmp",
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
getTag = KojiWrapper.return_value.koji_proxy.getTag
getTag.return_value = None
t = createiso.CreateIsoThread(mock.Mock())
with self.assertRaises(RuntimeError) as ctx:
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
self.assertEqual('Tag "f25-build" does not exist.', str(ctx.exception))
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_in_runroot_crash(self, KojiWrapper, get_file_size, get_mtime, iso):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"runroot_tag": "f25-build",
"koji_profile": "koji",
"koji_cache": "/tmp",
"failable_deliverables": [("^.*$", {"*": "iso"})],
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
getTag = KojiWrapper.return_value.koji_proxy.getTag
getTag.return_value = {"arches": "x86_64"}
run_runroot = KojiWrapper.return_value.run_runroot_cmd
run_runroot.side_effect = helpers.boom
pool = mock.Mock()
t = createiso.CreateIsoThread(pool)
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
pool._logger.error.assert_has_calls(
[
mock.call(
"[FAIL] Iso (variant Server, arch x86_64) failed, but going on anyway." # noqa: E501
),
mock.call("BOOM"),
]
)
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_in_runroot_fail(self, KojiWrapper, get_file_size, get_mtime, iso):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"runroot_tag": "f25-build",
"koji_profile": "koji",
"koji_cache": "/tmp",
"failable_deliverables": [("^.*$", {"*": "iso"})],
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
getTag = KojiWrapper.return_value.koji_proxy.getTag
getTag.return_value = {"arches": "x86_64"}
run_runroot = KojiWrapper.return_value.run_runroot_cmd
run_runroot.return_value = {
"retcode": 1,
"output": "Nope",
"task_id": "1234",
}
pool = mock.Mock()
t = createiso.CreateIsoThread(pool)
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
pool._logger.error.assert_has_calls(
[
mock.call(
"[FAIL] Iso (variant Server, arch x86_64) failed, but going on anyway." # noqa: E501
),
mock.call(
"Runroot task failed: 1234. See %s for more details."
% (self.topdir + "/logs/x86_64/createiso-image-name.x86_64.log")
),
]
)
@mock.patch("pungi.phases.createiso.iso")
@mock.patch("pungi.phases.createiso.get_mtime")
@mock.patch("pungi.phases.createiso.get_file_size")
@mock.patch("pungi.runroot.run")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_locally(self, KojiWrapper, run, get_file_size, get_mtime, iso):
compose = helpers.DummyCompose(
self.topdir, {"release_short": "test", "release_version": "1.0"}
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
get_file_size.return_value = 1024
get_mtime.return_value = 13579
t = createiso.CreateIsoThread(mock.Mock())
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
self.assertEqual(KojiWrapper.return_value.mock_calls, [])
self.assertEqual(
run.call_args_list,
[
mock.call(
cmd["cmd"],
show_cmd=True,
logfile="%s/logs/x86_64/createiso-image-name.x86_64.log"
% self.topdir,
)
],
)
self.assertEqual(
iso.get_implanted_md5.call_args_list,
[mock.call(cmd["iso_path"], logger=compose._logger)],
)
self.assertEqual(
iso.get_volume_id.call_args_list, [mock.call(cmd["iso_path"], False)]
)
self.assertEqual(len(compose.im.add.call_args_list), 1)
args, _ = compose.im.add.call_args_list[0]
self.assertEqual(args[0], "Server")
self.assertEqual(args[1], "x86_64")
image = args[2]
self.assertEqual(image.arch, "x86_64")
self.assertEqual(image.path, "Server/x86_64/iso/image-name")
self.assertEqual(image.format, "iso")
self.assertEqual(image.type, "dvd")
self.assertEqual(image.subvariant, "Server")
@mock.patch("pungi.runroot.run")
@mock.patch("pungi.wrappers.kojiwrapper.KojiWrapper")
def test_process_locally_crash(self, KojiWrapper, run):
compose = helpers.DummyCompose(
self.topdir,
{
"release_short": "test",
"release_version": "1.0",
"failable_deliverables": [("^.*$", {"*": "iso"})],
},
)
cmd = {
"iso_path": "%s/compose/Server/x86_64/iso/image-name" % self.topdir,
"bootable": False,
"cmd": mock.Mock(),
"label": "",
"disc_num": 1,
"disc_count": 1,
}
run.side_effect = helpers.boom
pool = mock.Mock()
t = createiso.CreateIsoThread(pool)
with mock.patch("time.sleep"):
t.process((compose, cmd, compose.variants["Server"], "x86_64"), 1)
pool._logger.error.assert_has_calls(
[
mock.call(
"[FAIL] Iso (variant Server, arch x86_64) failed, but going on anyway." # noqa: E501
),
mock.call("BOOM"),
]
)
TREEINFO = """
[header]
version = 1.0
[release]
name = Dummy Product
short = DP
version = 1.0
[tree]
arch = x86_64
platforms = x86_64
build_timestamp = 1464715102
variants = Server
[variant-Server]
id = Server
uid = Server
name = Server
type = variant
"""
class DummySize(object):
"""
This is intended as a replacement for os.path.getsize that returns
predefined sizes. The argument to __init__ should be a mapping from
substring of filepath to size.
"""
def __init__(self, sizes):
self.sizes = sizes
def __call__(self, path):
for fragment, size in self.sizes.items():
if fragment in path:
return size
return 0
class SplitIsoTest(helpers.PungiTestCase):
def test_split_fits_on_single_disc(self):
compose = helpers.DummyCompose(self.topdir, {})
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/.treeinfo"), TREEINFO
)
helpers.touch(os.path.join(self.topdir, "work/x86_64/Server/extra-files/GPL"))
helpers.touch(os.path.join(self.topdir, "compose/Server/x86_64/os/GPL"))
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/repodata/repomd.xml")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/b/bash.rpm")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/n/media.repo")
)
with mock.patch(
"os.path.getsize",
DummySize(
{
"GPL": 20 * 2048,
"bash": 150 * 2048,
"media": 100 * 2048,
"treeinfo": 10 * 2048,
}
),
):
data = createiso.split_iso(compose, "x86_64", compose.variants["Server"])
base_path = os.path.join(self.topdir, "compose/Server/x86_64/os")
# GPL is sticky file, it should be first at all times. Files are
# searched top-down, so nested ones are after top level ones.
self.assertEqual(
data,
[
{
"files": [
os.path.join(base_path, "GPL"),
os.path.join(base_path, ".treeinfo"),
os.path.join(base_path, "n/media.repo"),
os.path.join(base_path, "Packages/b/bash.rpm"),
],
"size": 573440,
}
],
)
def test_split_needs_two_discs(self):
compose = helpers.DummyCompose(self.topdir, {})
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/.treeinfo"), TREEINFO
)
helpers.touch(os.path.join(self.topdir, "work/x86_64/Server/extra-files/GPL"))
helpers.touch(os.path.join(self.topdir, "compose/Server/x86_64/os/GPL"))
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/repodata/repomd.xml")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/b/bash.rpm")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/n/media.repo")
)
M = 1024**2
G = 1024**3
with mock.patch(
"os.path.getsize",
DummySize(
{"GPL": 20 * M, "bash": 3 * G, "media": 2 * G, "treeinfo": 10 * M}
),
):
data = createiso.split_iso(compose, "x86_64", compose.variants["Server"])
base_path = os.path.join(self.topdir, "compose/Server/x86_64/os")
# GPL is the only sticky file, it should be first at all times.
# Files are searched top-down, so nested ones are after top level ones.
self.assertEqual(
data,
[
{
"files": [
os.path.join(base_path, "GPL"),
os.path.join(base_path, ".treeinfo"),
os.path.join(base_path, "n/media.repo"),
],
"size": 2178940928,
},
{
"files": [
os.path.join(base_path, "GPL"),
os.path.join(base_path, "Packages/b/bash.rpm"),
],
"size": 3242196992,
},
],
)
def test_no_split_when_requested(self):
compose = helpers.DummyCompose(self.topdir, {})
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/.treeinfo"), TREEINFO
)
helpers.touch(os.path.join(self.topdir, "work/x86_64/Server/extra-files/GPL"))
helpers.touch(os.path.join(self.topdir, "compose/Server/x86_64/os/GPL"))
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/repodata/repomd.xml")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/b/bash.rpm")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/n/media.repo")
)
M = 1024**2
G = 1024**3
with mock.patch(
"os.path.getsize",
DummySize(
{"GPL": 20 * M, "bash": 3 * G, "media": 2 * G, "treeinfo": 10 * M}
),
):
data = createiso.split_iso(
compose, "x86_64", compose.variants["Server"], no_split=True
)
base_path = os.path.join(self.topdir, "compose/Server/x86_64/os")
# GPL is the only sticky file, it should be first at all times.
# Files are searched top-down, so nested ones are after top level ones.
self.assertEqual(
data,
[
{
"files": [
os.path.join(base_path, "GPL"),
os.path.join(base_path, ".treeinfo"),
os.path.join(base_path, "n/media.repo"),
os.path.join(base_path, "Packages/b/bash.rpm"),
],
"size": 5400166400,
}
],
)
self.assertEqual(
compose._logger.warning.call_args_list,
[
mock.call(
"ISO for Server.x86_64 does not fit on single media! "
"It is 710652160 bytes too big. (Total size: 5400166400 B)"
)
],
)
def test_keeps_reserve(self):
compose = helpers.DummyCompose(self.topdir, {})
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/.treeinfo"), TREEINFO
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/spacer.rpm")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/x/pad.rpm")
)
M = 1024**2
# treeinfo has size 0, spacer leaves 11M of free space, so with 10M
# reserve the padding package should be on second disk
with mock.patch(
"os.path.getsize", DummySize({"spacer": 4688465664, "pad": 5 * M})
):
data = createiso.split_iso(compose, "x86_64", compose.variants["Server"])
base_path = os.path.join(self.topdir, "compose/Server/x86_64/os")
self.assertEqual(len(data), 2)
self.assertEqual(
data[0]["files"],
[
os.path.join(base_path, ".treeinfo"),
os.path.join(base_path, "Packages/spacer.rpm"),
],
)
self.assertEqual(
data[1]["files"], [os.path.join(base_path, "Packages/x/pad.rpm")]
)
def test_can_customize_reserve(self):
compose = helpers.DummyCompose(self.topdir, {"split_iso_reserve": 1024**2})
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/.treeinfo"), TREEINFO
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/spacer.rpm")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/x/pad.rpm")
)
M = 1024**2
with mock.patch(
"os.path.getsize", DummySize({"spacer": 4688465664, "pad": 5 * M})
):
data = createiso.split_iso(compose, "x86_64", compose.variants["Server"])
self.assertEqual(len(data), 1)
def test_can_change_iso_size(self):
compose = helpers.DummyCompose(self.topdir, {"iso_size": "8G"})
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/.treeinfo"), TREEINFO
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/spacer.rpm")
)
helpers.touch(
os.path.join(self.topdir, "compose/Server/x86_64/os/Packages/x/pad.rpm")
)
M = 1024**2
with mock.patch(
"os.path.getsize", DummySize({"spacer": 4688465664, "pad": 5 * M})
):
data = createiso.split_iso(compose, "x86_64", compose.variants["Server"])
self.assertEqual(len(data), 1)
class BreakHardlinksTest(helpers.PungiTestCase):
def setUp(self):
super(BreakHardlinksTest, self).setUp()
self.src = os.path.join(self.topdir, "src")
self.stage = os.path.join(self.topdir, "stage")
def test_not_modify_dir(self):
p = os.path.join(self.src, "dir")
os.makedirs(p)
d = {"dir": p}
createiso.break_hardlinks(d, self.stage)
self.assertEqual(d, {"dir": p})
def test_not_copy_file_with_one(self):
f = os.path.join(self.src, "file")
helpers.touch(f)
d = {"f": f}
createiso.break_hardlinks(d, self.stage)
self.assertEqual(d, {"f": f})
def test_copy(self):
f = os.path.join(self.src, "file")
helpers.touch(f)
os.link(f, os.path.join(self.topdir, "file"))
d = {"f": f}
createiso.break_hardlinks(d, self.stage)
expected = self.stage + f
self.assertEqual(d, {"f": expected})
self.assertTrue(os.path.exists(expected))
class TweakTreeinfo(helpers.PungiTestCase):
def test_tweaking(self):
input = os.path.join(helpers.FIXTURE_DIR, "original-treeinfo")
expected = os.path.join(helpers.FIXTURE_DIR, "expected-treeinfo")
output = os.path.join(self.topdir, "output")
ti = createiso.load_and_tweak_treeinfo(input)
ti.dump(output)
self.assertFilesEqual(output, expected)
class CreateisoTryReusePhaseTest(helpers.PungiTestCase):
def setUp(self):
super(CreateisoTryReusePhaseTest, self).setUp()
self.logger = logging.getLogger()
self.logger.setLevel(logging.DEBUG)
self.logger.addHandler(logging.StreamHandler(os.devnull))
def test_disabled(self):
compose = helpers.DummyCompose(self.topdir, {"createiso_allow_reuse": False})
phase = createiso.CreateisoPhase(compose, mock.Mock())
self.assertFalse(phase.try_reuse(mock.Mock(), "Server", "x86_64", mock.Mock()))
def test_buildinstall_changed(self):
compose = helpers.DummyCompose(self.topdir, {"createiso_allow_reuse": True})
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
phase.bi = mock.Mock()
phase.bi.reused.return_value = False
cmd = {"disc_num": 1, "disc_count": 1}
opts = CreateIsoOpts(buildinstall_method="lorax")
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
def test_no_old_config(self):
compose = helpers.DummyCompose(self.topdir, {"createiso_allow_reuse": True})
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
cmd = {"disc_num": 1, "disc_count": 1}
opts = CreateIsoOpts()
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
def test_old_config_changed(self):
compose = helpers.DummyCompose(
self.topdir, {"createiso_allow_reuse": True, "sigkeys": ["abcdef"]}
)
old_config = compose.conf.copy()
old_config["release_version"] = "2"
compose.load_old_compose_config.return_value = old_config
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
cmd = {"disc_num": 1, "disc_count": 1}
opts = CreateIsoOpts()
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
@mock.patch("pungi.phases.createiso.read_json_file")
def test_unsigned_packages_allowed(self, read_json_file):
compose = helpers.DummyCompose(self.topdir, {"createiso_allow_reuse": True})
compose.load_old_compose_config.return_value = compose.conf.copy()
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
cmd = {"disc_num": 1, "disc_count": 1}
opts = CreateIsoOpts(volid="new-volid")
read_json_file.return_value = {"opts": {"volid": "old-volid"}}
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
def test_no_old_metadata(self):
compose = helpers.DummyCompose(
self.topdir, {"createiso_allow_reuse": True, "sigkeys": ["abcdef"]}
)
compose.load_old_compose_config.return_value = compose.conf.copy()
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
cmd = {"disc_num": 1, "disc_count": 1}
opts = CreateIsoOpts()
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
@mock.patch("pungi.phases.createiso.read_json_file")
def test_volume_id_differs(self, read_json_file):
compose = helpers.DummyCompose(
self.topdir, {"createiso_allow_reuse": True, "sigkeys": ["abcdef"]}
)
compose.load_old_compose_config.return_value = compose.conf.copy()
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
cmd = {"disc_num": 1, "disc_count": 1}
opts = CreateIsoOpts(volid="new-volid")
read_json_file.return_value = {"opts": {"volid": "old-volid"}}
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
@mock.patch("pungi.phases.createiso.read_json_file")
def test_packages_differ(self, read_json_file):
compose = helpers.DummyCompose(
self.topdir, {"createiso_allow_reuse": True, "sigkeys": ["abcdef"]}
)
compose.load_old_compose_config.return_value = compose.conf.copy()
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
cmd = {"disc_num": 1, "disc_count": 1}
new_graft_points = os.path.join(self.topdir, "new_graft_points")
helpers.touch(new_graft_points, "Packages/f/foo-1-1.x86_64.rpm\n")
opts = CreateIsoOpts(graft_points=new_graft_points, volid="volid")
old_graft_points = os.path.join(self.topdir, "old_graft_points")
helpers.touch(old_graft_points, "Packages/f/foo-1-2.x86_64.rpm\n")
read_json_file.return_value = {
"opts": {"graft_points": old_graft_points, "volid": "volid"}
}
self.assertFalse(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
@mock.patch("pungi.phases.createiso.read_json_file")
def test_runs_perform_reuse(self, read_json_file):
compose = helpers.DummyCompose(
self.topdir, {"createiso_allow_reuse": True, "sigkeys": ["abcdef"]}
)
compose.load_old_compose_config.return_value = compose.conf.copy()
phase = createiso.CreateisoPhase(compose, mock.Mock())
phase.logger = self.logger
phase.perform_reuse = mock.Mock()
cmd = {"disc_num": 1, "disc_count": 1}
new_graft_points = os.path.join(self.topdir, "new_graft_points")
helpers.touch(new_graft_points)
opts = CreateIsoOpts(graft_points=new_graft_points, volid="volid")
old_graft_points = os.path.join(self.topdir, "old_graft_points")
helpers.touch(old_graft_points)
dummy_iso_path = "dummy-iso-path"
read_json_file.return_value = {
"opts": {
"graft_points": old_graft_points,
"volid": "volid",
},
"cmd": {"iso_path": dummy_iso_path},
}
self.assertTrue(
phase.try_reuse(cmd, compose.variants["Server"], "x86_64", opts)
)
self.assertEqual(
phase.perform_reuse.call_args_list,
[
mock.call(
cmd,
compose.variants["Server"],
"x86_64",
opts,
dummy_iso_path,
)
],
)
@mock.patch("pungi.phases.createiso.OldFileLinker")
@mock.patch("pungi.phases.createiso.add_iso_to_metadata")
class CreateisoPerformReusePhaseTest(helpers.PungiTestCase):
def test_success(self, add_iso_to_metadata, OldFileLinker):
compose = helpers.DummyCompose(self.topdir, {"createiso_allow_reuse": True})
phase = createiso.CreateisoPhase(compose, mock.Mock())
cmd = {
"iso_path": "target/image.iso",
"bootable": False,
"disc_num": 1,
"disc_count": 2,
}
opts = CreateIsoOpts()
phase.perform_reuse(
cmd,
compose.variants["Server"],
"x86_64",
opts,
"old/image.iso",
)
self.assertEqual(
add_iso_to_metadata.call_args_list,
[
mock.call(
compose,
compose.variants["Server"],
"x86_64",
cmd["iso_path"],
bootable=False,
disc_count=2,
disc_num=1,
),
],
)
self.assertEqual(
OldFileLinker.return_value.mock_calls,
[
mock.call.link("old/image.iso", "target/image.iso"),
mock.call.link("old/image.iso.manifest", "target/image.iso.manifest"),
# The old log file doesn't exist in the test scenario.
mock.call.link(
None,
os.path.join(
self.topdir, "logs/x86_64/createiso-image.iso.x86_64.log"
),
),
],
)
def test_failure(self, add_iso_to_metadata, OldFileLinker):
OldFileLinker.return_value.link.side_effect = helpers.mk_boom()
compose = helpers.DummyCompose(self.topdir, {"createiso_allow_reuse": True})
phase = createiso.CreateisoPhase(compose, mock.Mock())
cmd = {
"iso_path": "target/image.iso",
"bootable": False,
"disc_num": 1,
"disc_count": 2,
}
opts = CreateIsoOpts()
with self.assertRaises(Exception):
phase.perform_reuse(
cmd,
compose.variants["Server"],
"x86_64",
opts,
"old/image.iso",
)
self.assertEqual(add_iso_to_metadata.call_args_list, [])
self.assertEqual(
OldFileLinker.return_value.mock_calls,
[
mock.call.link("old/image.iso", "target/image.iso"),
mock.call.abort(),
],
)
class ComposeConfGetIsoLevelTest(helpers.PungiTestCase):
def test_global_config(self):
compose = helpers.DummyCompose(self.topdir, {"iso_level": 3})
self.assertEqual(
createiso.get_iso_level_config(
compose, compose.variants["Server"], "x86_64"
),
3,
)
def test_src_only_config(self):
compose = helpers.DummyCompose(
self.topdir,
{"iso_level": [(".*", {"src": 4})]},
)
self.assertEqual(
createiso.get_iso_level_config(compose, compose.variants["Server"], "src"),
4,
)
def test_no_match(self):
compose = helpers.DummyCompose(
self.topdir,
{"iso_level": [("^Server$", {"*": 4})]},
)
self.assertIsNone(
createiso.get_iso_level_config(
compose, compose.variants["Client"], "x86_64"
),
)
def mk_mount(topdir, images):
@contextlib.contextmanager
def dummy_mount(path, logger):
treeinfo = [
"[general]",
"family = Test",
"version = 1.0",
"arch = x86_64",
"variant = Server",
"[checksums]",
]
for image in images:
helpers.touch(os.path.join(topdir, image.path), image.content)
treeinfo.append("%s = sha256:%s" % (image.path, image.checksum))
helpers.touch(os.path.join(topdir, ".treeinfo"), "\n".join(treeinfo))
yield topdir
return dummy_mount
class _MockRun:
"""This class replaces kobo.shortcuts.run and validates that the correct
two commands are called. The assertions can not be done after the tested
function finishes because it will clean up the .treeinfo file that needs to
be checked.
"""
def __init__(self):
self.num_calls = 0
self.asserts = [self._assert_xorriso, self._assert_implantisomd5]
def __call__(self, cmd, logfile):
self.num_calls += 1
self.asserts.pop(0)(cmd)
def _assert_xorriso(self, cmd):
assert cmd[0] == "xorriso"
ti = productmd.TreeInfo()
input_iso = None
for i, arg in enumerate(cmd):
if arg == "-map":
ti.load(cmd[i + 1])
if arg == "-outdev":
self.temp_iso = cmd[i + 1]
if arg == "-indev":
input_iso = cmd[i + 1]
assert self.input_iso == input_iso
assert ti.checksums.checksums[self.image_relative_path] == self.image_checksum
def _assert_implantisomd5(self, cmd):
assert cmd[0] == "/usr/bin/implantisomd5"
assert cmd[-1] == self.temp_iso
class DummyImage:
def __init__(self, path, content, checksum=None):
self.path = path
self.content = content
self.checksum = checksum or helpers.hash_string("sha256", content)
@mock.patch("os.rename")
@mock.patch("pungi.phases.createiso.run", new_callable=_MockRun)
class FixChecksumsTest(helpers.PungiTestCase):
def test_checksum_matches(self, mock_run, mock_rename):
compose = helpers.DummyCompose(self.topdir, {})
arch = "x86_64"
iso_path = "DUMMY_ISO"
with mock.patch(
"pungi.wrappers.iso.mount",
new=mk_mount(self.topdir, [DummyImage("images/eltorito.img", "eltorito")]),
):
createiso.fix_treeinfo_checksums(compose, iso_path, arch)
self.assertEqual(mock_run.num_calls, 0)
self.assertEqual(mock_rename.call_args_list, [])
def test_checksum_fix(self, mock_run, mock_rename):
compose = helpers.DummyCompose(self.topdir, {})
arch = "x86_64"
img = "images/eltorito.img"
content = "eltorito"
iso_path = "DUMMY_ISO"
mock_run.input_iso = iso_path
mock_run.image_relative_path = "images/eltorito.img"
mock_run.image_checksum = ("sha256", helpers.hash_string("sha256", content))
with mock.patch(
"pungi.wrappers.iso.mount",
new=mk_mount(self.topdir, [DummyImage(img, content, "abc")]),
):
createiso.fix_treeinfo_checksums(compose, iso_path, arch)
# The new image was copied over the old one
self.assertEqual(
mock_rename.call_args_list, [mock.call(mock_run.temp_iso, iso_path)]
)