diff --git a/pungi/phases/image_build.py b/pungi/phases/image_build.py index 4974b994..83557270 100644 --- a/pungi/phases/image_build.py +++ b/pungi/phases/image_build.py @@ -5,7 +5,7 @@ import os import time from kobo import shortcuts -from pungi.util import get_variant_data, resolve_git_url, makedirs +from pungi.util import get_variant_data, resolve_git_url, makedirs, get_mtime, get_file_size from pungi.phases.base import PhaseBase from pungi.linker import Linker from pungi.paths import translate_path @@ -223,8 +223,8 @@ class CreateImageBuildThread(WorkerThread): img.type = image_info['type'] img.format = image_info['suffix'] img.path = os.path.join(relative_image_dir, os.path.basename(image_dest)) - img.mtime = int(os.stat(image_dest).st_mtime) - img.size = os.path.getsize(image_dest) + img.mtime = get_mtime(image_dest) + img.size = get_file_size(image_dest) img.arch = image_info['arch'] img.disc_number = 1 # We don't expect multiple disks img.disc_count = 1 diff --git a/pungi/phases/live_images.py b/pungi/phases/live_images.py index 5234951f..c3eb3e20 100644 --- a/pungi/phases/live_images.py +++ b/pungi/phases/live_images.py @@ -28,7 +28,7 @@ from productmd.images import Image from pungi.wrappers.kojiwrapper import KojiWrapper from pungi.wrappers.iso import IsoWrapper from pungi.phases.base import PhaseBase -from pungi.util import get_arch_variant_data, resolve_git_url, makedirs +from pungi.util import get_arch_variant_data, resolve_git_url, makedirs, get_mtime, get_file_size from pungi.paths import translate_path @@ -281,8 +281,8 @@ class CreateLiveImageThread(WorkerThread): img.type = type img.format = format img.path = os.path.relpath(path, compose.paths.compose.topdir()) - img.mtime = int(os.stat(path).st_mtime) - img.size = os.path.getsize(path) + img.mtime = get_mtime(path) + img.size = get_file_size(path) img.arch = arch img.disc_number = 1 # We don't expect multiple disks img.disc_count = 1 diff --git a/pungi/phases/livemedia_phase.py b/pungi/phases/livemedia_phase.py index 22d97bb9..e6c90c59 100644 --- a/pungi/phases/livemedia_phase.py +++ b/pungi/phases/livemedia_phase.py @@ -4,7 +4,7 @@ import os import time from kobo import shortcuts -from pungi.util import get_variant_data, resolve_git_url, makedirs +from pungi.util import get_variant_data, resolve_git_url, makedirs, get_mtime, get_file_size from pungi.phases.base import PhaseBase from pungi.linker import Linker from pungi.paths import translate_path @@ -122,7 +122,7 @@ class LiveMediaThread(WorkerThread): def _get_log_file(self, compose, variant, config): arches = '-'.join(config['arches']) - return compose.paths.log.log_file(arches, 'livemedia-%s' % variant) + return compose.paths.log.log_file(arches, 'livemedia-%s' % variant.uid) def _run_command(self, koji_wrapper, cmd, compose, log_file): time.sleep(self.num * 3) @@ -186,8 +186,8 @@ class LiveMediaThread(WorkerThread): img.type = 'live' img.format = 'iso' img.path = os.path.join(relative_image_dir, os.path.basename(image_dest)) - img.mtime = int(os.stat(image_dest).st_mtime) - img.size = os.path.getsize(image_dest) + img.mtime = get_mtime(image_dest) + img.size = get_file_size(image_dest) img.arch = image_info['arch'] img.disc_number = 1 # We don't expect multiple disks img.disc_count = 1 diff --git a/pungi/util.py b/pungi/util.py index 6aabdaad..3b572f1c 100644 --- a/pungi/util.py +++ b/pungi/util.py @@ -383,3 +383,11 @@ def get_volid(compose, arch, variant=None, escape_spaces=False, disc_type=False) if volid and escape_spaces: volid = volid.replace(" ", r"\x20") return volid + + +def get_mtime(path): + return int(os.stat(path).st_mtime) + + +def get_file_size(path): + return os.path.getsize(path) diff --git a/tests/helpers.py b/tests/helpers.py index d7c8d35e..b3eb4240 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -1,13 +1,24 @@ # -*- coding: utf-8 -*- import mock -import os +import unittest +import tempfile +import shutil from pungi.util import get_arch_variant_data +from pungi import paths + + +class PungiTestCase(unittest.TestCase): + def setUp(self): + self.topdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.topdir) class _DummyCompose(object): - def __init__(self, config): + def __init__(self, topdir, config): self.compose_date = '20151203' self.compose_type_suffix = '.t' self.compose_respin = 0 @@ -19,47 +30,17 @@ class _DummyCompose(object): version='1.0', ), ) + self.topdir = topdir self.conf = config - self.paths = mock.Mock( - compose=mock.Mock( - topdir=mock.Mock(return_value='/a/b'), - os_tree=mock.Mock( - side_effect=lambda arch, variant, create_dir=False: os.path.join('/ostree', arch, variant.uid) - ), - repository=mock.Mock( - side_effect=lambda arch, variant, create_dir=False: os.path.join('/repo', arch, variant.uid) - ), - image_dir=mock.Mock( - side_effect=lambda variant, relative=False, symlink_to=None: os.path.join( - '' if relative else '/', 'image_dir', variant.uid, '%(arch)s' - ) - ), - iso_dir=mock.Mock( - side_effect=lambda arch, variant, symlink_to=None, relative=False: os.path.join( - '' if relative else '/', 'iso_dir', arch, variant.uid - ) - ), - iso_path=mock.Mock( - side_effect=lambda arch, variant, filename, symlink_to: os.path.join( - '/iso_dir', arch, variant.uid, filename - ) - ) - ), - work=mock.Mock( - image_build_conf=mock.Mock( - side_effect=lambda variant, image_name, image_type: - '-'.join([variant.uid, image_name, image_type]) - ) - ), - log=mock.Mock( - log_file=mock.Mock(return_value='/a/b/log/log_file') - ) - ) + self.paths = paths.Paths(self) self._logger = mock.Mock() self.variants = { - 'Server': mock.Mock(uid='Server', arches=['x86_64', 'amd64'], is_empty=False), - 'Client': mock.Mock(uid='Client', arches=['amd64'], is_empty=False), - 'Everything': mock.Mock(uid='Everything', arches=['x86_64', 'amd64'], is_empty=False), + 'Server': mock.Mock(uid='Server', arches=['x86_64', 'amd64'], + type='variant', is_empty=False), + 'Client': mock.Mock(uid='Client', arches=['amd64'], + type='variant', is_empty=False), + 'Everything': mock.Mock(uid='Everything', arches=['x86_64', 'amd64'], + type='variant', is_empty=False), } self.log_error = mock.Mock() self.get_image_name = mock.Mock(return_value='image-name') diff --git a/tests/test_imagebuildphase.py b/tests/test_imagebuildphase.py index fc4eb329..fc236481 100755 --- a/tests/test_imagebuildphase.py +++ b/tests/test_imagebuildphase.py @@ -11,14 +11,14 @@ import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from pungi.phases.image_build import ImageBuildPhase, CreateImageBuildThread -from tests.helpers import _DummyCompose +from tests.helpers import _DummyCompose, PungiTestCase -class TestImageBuildPhase(unittest.TestCase): +class TestImageBuildPhase(PungiTestCase): @mock.patch('pungi.phases.image_build.ThreadPool') def test_image_build(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'image_build': { '^Client|Server$': [ { @@ -49,10 +49,10 @@ class TestImageBuildPhase(unittest.TestCase): "format": [('docker', 'tar.xz')], "image_conf": { 'image-build': { - 'install_tree': '/ostree/$arch/Client', + 'install_tree': self.topdir + '/compose/Client/$arch/os', 'kickstart': 'fedora-docker-base.ks', 'format': 'docker', - 'repo': '/ostree/$arch/Client', + 'repo': self.topdir + '/compose/Client/$arch/os', 'variant': compose.variants['Client'], 'target': 'f24', 'disk_size': 3, @@ -63,9 +63,9 @@ class TestImageBuildPhase(unittest.TestCase): 'distro': 'Fedora-20', } }, - "conf_file": 'Client-Fedora-Docker-Base-docker', - "image_dir": '/image_dir/Client/%(arch)s', - "relative_image_dir": 'image_dir/Client/%(arch)s', + "conf_file": self.topdir + '/work/image-build/Client/docker_Fedora-Docker-Base.cfg', + "image_dir": self.topdir + '/compose/Client/%(arch)s/images', + "relative_image_dir": 'Client/%(arch)s/images', "link_type": 'hardlink-or-copy', "scratch": False, } @@ -73,10 +73,10 @@ class TestImageBuildPhase(unittest.TestCase): "format": [('docker', 'tar.xz')], "image_conf": { 'image-build': { - 'install_tree': '/ostree/$arch/Server', + 'install_tree': self.topdir + '/compose/Server/$arch/os', 'kickstart': 'fedora-docker-base.ks', 'format': 'docker', - 'repo': '/ostree/$arch/Server', + 'repo': self.topdir + '/compose/Server/$arch/os', 'variant': compose.variants['Server'], 'target': 'f24', 'disk_size': 3, @@ -87,19 +87,20 @@ class TestImageBuildPhase(unittest.TestCase): 'distro': 'Fedora-20', } }, - "conf_file": 'Server-Fedora-Docker-Base-docker', - "image_dir": '/image_dir/Server/%(arch)s', - "relative_image_dir": 'image_dir/Server/%(arch)s', + "conf_file": self.topdir + '/work/image-build/Server/docker_Fedora-Docker-Base.cfg', + "image_dir": self.topdir + '/compose/Server/%(arch)s/images', + "relative_image_dir": 'Server/%(arch)s/images', "link_type": 'hardlink-or-copy', "scratch": False, } + self.maxDiff = None self.assertItemsEqual(phase.pool.queue_put.mock_calls, [mock.call((compose, client_args)), mock.call((compose, server_args))]) @mock.patch('pungi.phases.image_build.ThreadPool') def test_image_build_filter_all_variants(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'image_build': { '^Client|Server$': [ { @@ -130,7 +131,7 @@ class TestImageBuildPhase(unittest.TestCase): @mock.patch('pungi.phases.image_build.ThreadPool') def test_image_build_set_install_tree(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'image_build': { '^Server$': [ { @@ -167,10 +168,10 @@ class TestImageBuildPhase(unittest.TestCase): "format": [('docker', 'tar.xz')], "image_conf": { 'image-build': { - 'install_tree': '/ostree/$arch/Everything', + 'install_tree': self.topdir + '/compose/Everything/$arch/os', 'kickstart': 'fedora-docker-base.ks', 'format': 'docker', - 'repo': '/ostree/$arch/Server', + 'repo': self.topdir + '/compose/Server/$arch/os', 'variant': compose.variants['Server'], 'target': 'f24', 'disk_size': 3, @@ -181,16 +182,16 @@ class TestImageBuildPhase(unittest.TestCase): 'distro': 'Fedora-20', } }, - "conf_file": 'Server-Fedora-Docker-Base-docker', - "image_dir": '/image_dir/Server/%(arch)s', - "relative_image_dir": 'image_dir/Server/%(arch)s', + "conf_file": self.topdir + '/work/image-build/Server/docker_Fedora-Docker-Base.cfg', + "image_dir": self.topdir + '/compose/Server/%(arch)s/images', + "relative_image_dir": 'Server/%(arch)s/images', "link_type": 'hardlink-or-copy', "scratch": False, }) @mock.patch('pungi.phases.image_build.ThreadPool') def test_image_build_set_extra_repos(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'image_build': { '^Server$': [ { @@ -227,10 +228,11 @@ class TestImageBuildPhase(unittest.TestCase): "format": [('docker', 'tar.xz')], "image_conf": { 'image-build': { - 'install_tree': '/ostree/$arch/Server', + 'install_tree': self.topdir + '/compose/Server/$arch/os', 'kickstart': 'fedora-docker-base.ks', 'format': 'docker', - 'repo': '/ostree/$arch/Everything,/ostree/$arch/Server', + 'repo': ','.join([self.topdir + '/compose/Everything/$arch/os', + self.topdir + '/compose/Server/$arch/os']), 'variant': compose.variants['Server'], 'target': 'f24', 'disk_size': 3, @@ -241,16 +243,16 @@ class TestImageBuildPhase(unittest.TestCase): 'distro': 'Fedora-20', } }, - "conf_file": 'Server-Fedora-Docker-Base-docker', - "image_dir": '/image_dir/Server/%(arch)s', - "relative_image_dir": 'image_dir/Server/%(arch)s', + "conf_file": self.topdir + '/work/image-build/Server/docker_Fedora-Docker-Base.cfg', + "image_dir": self.topdir + '/compose/Server/%(arch)s/images', + "relative_image_dir": 'Server/%(arch)s/images', "link_type": 'hardlink-or-copy', "scratch": False, }) @mock.patch('pungi.phases.image_build.ThreadPool') def test_image_build_create_release(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'image_build': { '^Server$': [ { @@ -286,7 +288,7 @@ class TestImageBuildPhase(unittest.TestCase): @mock.patch('pungi.phases.image_build.ThreadPool') def test_image_build_scratch_build(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'image_build': { '^Server$': [ { @@ -320,13 +322,14 @@ class TestImageBuildPhase(unittest.TestCase): self.assertTrue(args[0][1].get('scratch')) -class TestCreateImageBuildThread(unittest.TestCase): +class TestCreateImageBuildThread(PungiTestCase): + @mock.patch('pungi.phases.image_build.get_mtime') + @mock.patch('pungi.phases.image_build.get_file_size') @mock.patch('pungi.phases.image_build.KojiWrapper') @mock.patch('pungi.phases.image_build.Linker') - @mock.patch('pungi.phases.image_build.makedirs') - def test_process(self, makedirs, Linker, KojiWrapper): - compose = _DummyCompose({ + def test_process(self, Linker, KojiWrapper, get_file_size, get_mtime): + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji' }) pool = mock.Mock() @@ -349,7 +352,7 @@ class TestCreateImageBuildThread(unittest.TestCase): } }, "conf_file": 'amd64,x86_64-Client-Fedora-Docker-Base-docker', - "image_dir": '/image_dir/Client/%(arch)s', + "image_dir": self.topdir + '/compose/Client/%(arch)s/images', "relative_image_dir": 'image_dir/Client/%(arch)s', "link_type": 'hardlink-or-copy', "scratch": False, @@ -374,28 +377,26 @@ class TestCreateImageBuildThread(unittest.TestCase): } linker = Linker.return_value + get_file_size.return_value = 1024 + get_mtime.return_value = 13579 t = CreateImageBuildThread(pool) - with mock.patch('os.stat') as stat: - with mock.patch('os.path.getsize') as getsize: - with mock.patch('time.sleep'): - getsize.return_value = 1024 - stat.return_value.st_mtime = 13579 - t.process((compose, cmd), 1) + with mock.patch('time.sleep'): + t.process((compose, cmd), 1) self.assertItemsEqual( linker.mock_calls, [mock.call('/koji/task/1235/Fedora-Docker-Base-20160103.amd64.qcow2', - '/image_dir/Client/amd64/Fedora-Docker-Base-20160103.amd64.qcow2', + self.topdir + '/compose/Client/amd64/images/Fedora-Docker-Base-20160103.amd64.qcow2', link_type='hardlink-or-copy'), mock.call('/koji/task/1235/Fedora-Docker-Base-20160103.amd64.tar.xz', - '/image_dir/Client/amd64/Fedora-Docker-Base-20160103.amd64.tar.xz', + self.topdir + '/compose/Client/amd64/images/Fedora-Docker-Base-20160103.amd64.tar.xz', link_type='hardlink-or-copy'), mock.call('/koji/task/1235/Fedora-Docker-Base-20160103.x86_64.qcow2', - '/image_dir/Client/x86_64/Fedora-Docker-Base-20160103.x86_64.qcow2', + self.topdir + '/compose/Client/x86_64/images/Fedora-Docker-Base-20160103.x86_64.qcow2', link_type='hardlink-or-copy'), mock.call('/koji/task/1235/Fedora-Docker-Base-20160103.x86_64.tar.xz', - '/image_dir/Client/x86_64/Fedora-Docker-Base-20160103.x86_64.tar.xz', + self.topdir + '/compose/Client/x86_64/images/Fedora-Docker-Base-20160103.x86_64.tar.xz', link_type='hardlink-or-copy')]) image_relative_paths = { @@ -434,16 +435,13 @@ class TestCreateImageBuildThread(unittest.TestCase): self.assertEqual(data['format'], image.format) self.assertEqual(data['type'], image.type) - self.assertItemsEqual(makedirs.mock_calls, - [mock.call('/image_dir/Client/amd64'), - mock.call('/image_dir/Client/amd64'), - mock.call('/image_dir/Client/x86_64'), - mock.call('/image_dir/Client/x86_64')]) + self.assertTrue(os.path.isdir(self.topdir + '/compose/Client/amd64/images')) + self.assertTrue(os.path.isdir(self.topdir + '/compose/Client/x86_64/images')) @mock.patch('pungi.phases.image_build.KojiWrapper') @mock.patch('pungi.phases.image_build.Linker') def test_process_handle_fail(self, Linker, KojiWrapper): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji', 'failable_deliverables': [ ('^.*$', { @@ -494,7 +492,7 @@ class TestCreateImageBuildThread(unittest.TestCase): @mock.patch('pungi.phases.image_build.KojiWrapper') @mock.patch('pungi.phases.image_build.Linker') def test_process_handle_exception(self, Linker, KojiWrapper): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji', 'failable_deliverables': [ ('^.*$', { diff --git a/tests/test_imagechecksumphase.py b/tests/test_imagechecksumphase.py index 634e44ec..8be2c2fc 100755 --- a/tests/test_imagechecksumphase.py +++ b/tests/test_imagechecksumphase.py @@ -13,13 +13,13 @@ import shutil sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from pungi.phases.image_checksum import ImageChecksumPhase, dump_checksums -from tests.helpers import _DummyCompose +from tests.helpers import _DummyCompose, PungiTestCase -class TestImageChecksumPhase(unittest.TestCase): +class TestImageChecksumPhase(PungiTestCase): def test_config_skip_individual_with_multiple_algorithms(self): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'media_checksums': ['md5', 'sha1'], 'media_checksum_one_file': True }) @@ -32,7 +32,7 @@ class TestImageChecksumPhase(unittest.TestCase): @mock.patch('kobo.shortcuts.compute_file_checksums') @mock.patch('pungi.phases.image_checksum.dump_checksums') def test_checksum_one_file(self, dump, cc, exists): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'media_checksums': ['sha256'], 'media_checksum_one_file': True, }) @@ -44,15 +44,15 @@ class TestImageChecksumPhase(unittest.TestCase): phase.run() - dump.assert_called_once_with('/a/b/Client/i386/iso', 'sha256', {'image.iso': 'cafebabe'}, 'CHECKSUM') - cc.assert_called_once_with('/a/b/Client/i386/iso/image.iso', ['sha256']) + dump.assert_called_once_with(self.topdir + '/compose/Client/i386/iso', 'sha256', {'image.iso': 'cafebabe'}, 'CHECKSUM') + cc.assert_called_once_with(self.topdir + '/compose/Client/i386/iso/image.iso', ['sha256']) compose.image.add_checksum.assert_called_once_with(None, 'sha256', 'cafebabe') @mock.patch('os.path.exists') @mock.patch('kobo.shortcuts.compute_file_checksums') @mock.patch('pungi.phases.image_checksum.dump_checksums') def test_checksum_save_individuals(self, dump, cc, exists): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'media_checksums': ['md5', 'sha256'], }) @@ -64,13 +64,17 @@ class TestImageChecksumPhase(unittest.TestCase): phase.run() dump.assert_has_calls( - [mock.call('/a/b/Client/i386/iso', 'md5', {'image.iso': 'cafebabe'}, 'image.iso.MD5SUM'), - mock.call('/a/b/Client/i386/iso', 'sha256', {'image.iso': 'deadbeef'}, 'image.iso.SHA256SUM'), - mock.call('/a/b/Client/i386/iso', 'md5', {'image.iso': 'cafebabe'}, 'MD5SUM'), - mock.call('/a/b/Client/i386/iso', 'sha256', {'image.iso': 'deadbeef'}, 'SHA256SUM')], + [mock.call(self.topdir + '/compose/Client/i386/iso', 'md5', + {'image.iso': 'cafebabe'}, 'image.iso.MD5SUM'), + mock.call(self.topdir + '/compose/Client/i386/iso', 'sha256', + {'image.iso': 'deadbeef'}, 'image.iso.SHA256SUM'), + mock.call(self.topdir + '/compose/Client/i386/iso', 'md5', + {'image.iso': 'cafebabe'}, 'MD5SUM'), + mock.call(self.topdir + '/compose/Client/i386/iso', 'sha256', + {'image.iso': 'deadbeef'}, 'SHA256SUM')], any_order=True ) - cc.assert_called_once_with('/a/b/Client/i386/iso/image.iso', ['md5', 'sha256']) + cc.assert_called_once_with(self.topdir + '/compose/Client/i386/iso/image.iso', ['md5', 'sha256']) compose.image.add_checksum.assert_has_calls([mock.call(None, 'sha256', 'deadbeef'), mock.call(None, 'md5', 'cafebabe')], any_order=True) @@ -79,7 +83,7 @@ class TestImageChecksumPhase(unittest.TestCase): @mock.patch('kobo.shortcuts.compute_file_checksums') @mock.patch('pungi.phases.image_checksum.dump_checksums') def test_checksum_one_file_custom_name(self, dump, cc, exists): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'media_checksums': ['sha256'], 'media_checksum_one_file': True, 'media_checksum_base_filename': '%(release_short)s-%(variant)s-%(version)s-%(date)s%(type_suffix)s.%(respin)s' @@ -92,17 +96,17 @@ class TestImageChecksumPhase(unittest.TestCase): phase.run() - dump.assert_called_once_with('/a/b/Client/i386/iso', 'sha256', + dump.assert_called_once_with(self.topdir + '/compose/Client/i386/iso', 'sha256', {'image.iso': 'cafebabe'}, 'test-Client-1.0-20151203.t.0-CHECKSUM') - cc.assert_called_once_with('/a/b/Client/i386/iso/image.iso', ['sha256']) + cc.assert_called_once_with(self.topdir + '/compose/Client/i386/iso/image.iso', ['sha256']) compose.image.add_checksum.assert_called_once_with(None, 'sha256', 'cafebabe') @mock.patch('os.path.exists') @mock.patch('kobo.shortcuts.compute_file_checksums') @mock.patch('pungi.phases.image_checksum.dump_checksums') def test_checksum_save_individuals_custom_name(self, dump, cc, exists): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'media_checksums': ['md5', 'sha256'], 'media_checksum_base_filename': '%(release_short)s-%(variant)s-%(version)s-%(date)s%(type_suffix)s.%(respin)s' }) @@ -115,15 +119,17 @@ class TestImageChecksumPhase(unittest.TestCase): phase.run() dump.assert_has_calls( - [mock.call('/a/b/Client/i386/iso', 'md5', {'image.iso': 'cafebabe'}, 'image.iso.MD5SUM'), - mock.call('/a/b/Client/i386/iso', 'sha256', {'image.iso': 'deadbeef'}, 'image.iso.SHA256SUM'), - mock.call('/a/b/Client/i386/iso', 'md5', {'image.iso': 'cafebabe'}, + [mock.call(self.topdir + '/compose/Client/i386/iso', 'md5', + {'image.iso': 'cafebabe'}, 'image.iso.MD5SUM'), + mock.call(self.topdir + '/compose/Client/i386/iso', 'sha256', + {'image.iso': 'deadbeef'}, 'image.iso.SHA256SUM'), + mock.call(self.topdir + '/compose/Client/i386/iso', 'md5', {'image.iso': 'cafebabe'}, 'test-Client-1.0-20151203.t.0-MD5SUM'), - mock.call('/a/b/Client/i386/iso', 'sha256', {'image.iso': 'deadbeef'}, + mock.call(self.topdir + '/compose/Client/i386/iso', 'sha256', {'image.iso': 'deadbeef'}, 'test-Client-1.0-20151203.t.0-SHA256SUM')], any_order=True ) - cc.assert_called_once_with('/a/b/Client/i386/iso/image.iso', ['md5', 'sha256']) + cc.assert_called_once_with(self.topdir + '/compose/Client/i386/iso/image.iso', ['md5', 'sha256']) compose.image.add_checksum.assert_has_calls([mock.call(None, 'sha256', 'deadbeef'), mock.call(None, 'md5', 'cafebabe')], any_order=True) diff --git a/tests/test_liveimagesphase.py b/tests/test_liveimagesphase.py index 8dc65d31..ac06546d 100755 --- a/tests/test_liveimagesphase.py +++ b/tests/test_liveimagesphase.py @@ -11,14 +11,14 @@ import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from pungi.phases.live_images import LiveImagesPhase, CreateLiveImageThread -from tests.helpers import _DummyCompose +from tests.helpers import _DummyCompose, PungiTestCase -class TestLiveImagesPhase(unittest.TestCase): +class TestLiveImagesPhase(PungiTestCase): @mock.patch('pungi.phases.live_images.ThreadPool') def test_live_image_build(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_images': [ ('^Client$', { 'amd64': { @@ -42,11 +42,11 @@ class TestLiveImagesPhase(unittest.TestCase): [mock.call((compose, {'ks_file': 'test.ks', 'build_arch': 'amd64', - 'dest_dir': '/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, - 'repos': ['/repo/amd64/Client', + 'repos': [self.topdir + '/compose/Client/amd64/os', 'http://example.com/repo/', - '/repo/amd64/Everything'], + self.topdir + '/compose/Everything/amd64/os'], 'label': '', 'name': None, 'filename': 'image-name', @@ -61,7 +61,7 @@ class TestLiveImagesPhase(unittest.TestCase): @mock.patch('pungi.phases.live_images.ThreadPool') def test_live_image_build_without_rename(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_images_no_rename': True, 'live_images': [ ('^Client$', { @@ -86,11 +86,11 @@ class TestLiveImagesPhase(unittest.TestCase): [mock.call((compose, {'ks_file': 'test.ks', 'build_arch': 'amd64', - 'dest_dir': '/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, - 'repos': ['/repo/amd64/Client', + 'repos': [self.topdir + '/compose/Client/amd64/os', 'http://example.com/repo/', - '/repo/amd64/Everything'], + self.topdir + '/compose/Everything/amd64/os'], 'label': '', 'name': None, 'filename': None, @@ -105,7 +105,7 @@ class TestLiveImagesPhase(unittest.TestCase): @mock.patch('pungi.phases.live_images.ThreadPool') def test_live_image_build_two_images(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_images': [ ('^Client$', { 'amd64': [{ @@ -132,11 +132,11 @@ class TestLiveImagesPhase(unittest.TestCase): [mock.call((compose, {'ks_file': 'test.ks', 'build_arch': 'amd64', - 'dest_dir': '/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, - 'repos': ['/repo/amd64/Client', + 'repos': [self.topdir + '/compose/Client/amd64/os', 'http://example.com/repo/', - '/repo/amd64/Everything'], + self.topdir + '/compose/Everything/amd64/os'], 'label': '', 'name': None, 'filename': 'image-name', @@ -151,11 +151,11 @@ class TestLiveImagesPhase(unittest.TestCase): mock.call((compose, {'ks_file': 'another.ks', 'build_arch': 'amd64', - 'dest_dir': '/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, - 'repos': ['/repo/amd64/Client', + 'repos': [self.topdir + '/compose/Client/amd64/os', 'http://example.com/repo/', - '/repo/amd64/Everything'], + self.topdir + '/compose/Everything/amd64/os'], 'label': '', 'name': None, 'filename': 'image-name', @@ -171,7 +171,7 @@ class TestLiveImagesPhase(unittest.TestCase): @mock.patch('pungi.phases.live_images.ThreadPool') @mock.patch('pungi.phases.live_images.resolve_git_url') def test_spin_appliance(self, resolve_git_url, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_images': [ ('^Client$', { 'amd64': { @@ -198,11 +198,11 @@ class TestLiveImagesPhase(unittest.TestCase): [mock.call((compose, {'ks_file': 'test.ks', 'build_arch': 'amd64', - 'dest_dir': '/image_dir/Client/amd64', + 'dest_dir': self.topdir + '/compose/Client/amd64/images', 'scratch': False, - 'repos': ['/repo/amd64/Client', + 'repos': [self.topdir + '/compose/Client/amd64/os', 'http://example.com/repo/', - '/repo/amd64/Everything'], + self.topdir + '/compose/Everything/amd64/os'], 'label': '', 'name': None, 'filename': 'image-name', @@ -218,19 +218,19 @@ class TestLiveImagesPhase(unittest.TestCase): [mock.call('https://git.example.com/kickstarts.git?#HEAD')]) -class TestCreateLiveImageThread(unittest.TestCase): +class TestCreateLiveImageThread(PungiTestCase): @mock.patch('pungi.phases.live_images.Image') @mock.patch('shutil.copy2') @mock.patch('pungi.phases.live_images.run') @mock.patch('pungi.phases.live_images.KojiWrapper') def test_process(self, KojiWrapper, run, copy2, Image): - compose = _DummyCompose({'koji_profile': 'koji'}) + compose = _DummyCompose(self.topdir, {'koji_profile': 'koji'}) pool = mock.Mock() cmd = { 'ks_file': '/path/to/ks_file', 'build_arch': 'amd64', - 'dest_dir': '/top/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, 'repos': ['/repo/amd64/Client', 'http://example.com/repo/', @@ -255,21 +255,22 @@ class TestCreateLiveImageThread(unittest.TestCase): koji_wrapper.get_image_path.return_value = ['/path/to/image.iso'] t = CreateLiveImageThread(pool) - with mock.patch('os.stat') as stat: - with mock.patch('os.path.getsize') as getsize: + with mock.patch('pungi.phases.live_images.get_file_size') as get_file_size: + get_file_size.return_value = 1024 + with mock.patch('pungi.phases.live_images.get_mtime') as get_mtime: + get_mtime.return_value = 13579 with mock.patch('time.sleep'): - getsize.return_value = 1024 - stat.return_value.st_mtime = 13579 t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1) self.assertEqual(koji_wrapper.run_blocking_cmd.mock_calls, - [mock.call('koji spin-livecd ...', log_file='/a/b/log/log_file')]) + [mock.call('koji spin-livecd ...', + log_file=self.topdir + '/logs/amd64/createiso-None-None-None.amd64.log')]) self.assertEqual(koji_wrapper.get_image_path.mock_calls, [mock.call(123)]) self.assertEqual(copy2.mock_calls, - [mock.call('/path/to/image.iso', '/top/iso_dir/amd64/Client/image-name')]) + [mock.call('/path/to/image.iso', self.topdir + '/compose/Client/amd64/iso/image-name')]) write_manifest_cmd = ' && '.join([ - 'cd /top/iso_dir/amd64/Client', + 'cd ' + self.topdir + '/compose/Client/amd64/iso', 'isoinfo -R -f -i image-name | grep -v \'/TRANS.TBL$\' | sort >> image-name.manifest' ]) self.assertEqual(run.mock_calls, [mock.call(write_manifest_cmd)]) @@ -287,7 +288,7 @@ class TestCreateLiveImageThread(unittest.TestCase): ksurl='https://git.example.com/kickstarts.git?#CAFEBABE')]) self.assertEqual(Image.return_value.type, 'live') self.assertEqual(Image.return_value.format, 'iso') - self.assertEqual(Image.return_value.path, '../../top/iso_dir/amd64/Client/image-name') + self.assertEqual(Image.return_value.path, 'Client/amd64/iso/image-name') self.assertEqual(Image.return_value.size, 1024) self.assertEqual(Image.return_value.mtime, 13579) self.assertEqual(Image.return_value.arch, 'amd64') @@ -302,12 +303,12 @@ class TestCreateLiveImageThread(unittest.TestCase): @mock.patch('pungi.phases.live_images.run') @mock.patch('pungi.phases.live_images.KojiWrapper') def test_process_no_rename(self, KojiWrapper, run, copy2, Image): - compose = _DummyCompose({'koji_profile': 'koji'}) + compose = _DummyCompose(self.topdir, {'koji_profile': 'koji'}) pool = mock.Mock() cmd = { 'ks_file': '/path/to/ks_file', 'build_arch': 'amd64', - 'dest_dir': '/top/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, 'repos': ['/repo/amd64/Client', 'http://example.com/repo/', @@ -332,25 +333,22 @@ class TestCreateLiveImageThread(unittest.TestCase): koji_wrapper.get_image_path.return_value = ['/path/to/image.iso'] t = CreateLiveImageThread(pool) - with mock.patch('os.stat') as stat: - with mock.patch('os.path.getsize') as getsize: - getsize.return_value = 1024 - getsize.return_value = 1024 - getsize.return_value = 1024 - getsize.return_value = 1024 + with mock.patch('pungi.phases.live_images.get_file_size') as get_file_size: + get_file_size.return_value = 1024 + with mock.patch('pungi.phases.live_images.get_mtime') as get_mtime: + get_mtime.return_value = 13579 with mock.patch('time.sleep'): - getsize.return_value = 1024 - stat.return_value.st_mtime = 13579 t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1) self.assertEqual(koji_wrapper.run_blocking_cmd.mock_calls, - [mock.call('koji spin-livecd ...', log_file='/a/b/log/log_file')]) + [mock.call('koji spin-livecd ...', + log_file=self.topdir + '/logs/amd64/createiso-None-None-None.amd64.log')]) self.assertEqual(koji_wrapper.get_image_path.mock_calls, [mock.call(123)]) self.assertEqual(copy2.mock_calls, - [mock.call('/path/to/image.iso', '/top/iso_dir/amd64/Client/image.iso')]) + [mock.call('/path/to/image.iso', self.topdir + '/compose/Client/amd64/iso/image.iso')]) write_manifest_cmd = ' && '.join([ - 'cd /top/iso_dir/amd64/Client', + 'cd ' + self.topdir + '/compose/Client/amd64/iso', 'isoinfo -R -f -i image.iso | grep -v \'/TRANS.TBL$\' | sort >> image.iso.manifest' ]) self.assertEqual(run.mock_calls, [mock.call(write_manifest_cmd)]) @@ -369,7 +367,7 @@ class TestCreateLiveImageThread(unittest.TestCase): self.assertEqual(Image.return_value.type, 'live') self.assertEqual(Image.return_value.format, 'iso') - self.assertEqual(Image.return_value.path, '../../top/iso_dir/amd64/Client/image.iso') + self.assertEqual(Image.return_value.path, 'Client/amd64/iso/image.iso') self.assertEqual(Image.return_value.size, 1024) self.assertEqual(Image.return_value.mtime, 13579) self.assertEqual(Image.return_value.arch, 'amd64') @@ -384,12 +382,12 @@ class TestCreateLiveImageThread(unittest.TestCase): @mock.patch('pungi.phases.live_images.run') @mock.patch('pungi.phases.live_images.KojiWrapper') def test_process_applicance(self, KojiWrapper, run, copy2, Image): - compose = _DummyCompose({'koji_profile': 'koji'}) + compose = _DummyCompose(self.topdir, {'koji_profile': 'koji'}) pool = mock.Mock() cmd = { 'ks_file': '/path/to/ks_file', 'build_arch': 'amd64', - 'dest_dir': '/top/iso_dir/amd64/Client', + 'dest_dir': self.topdir + '/compose/Client/amd64/iso', 'scratch': False, 'repos': ['/repo/amd64/Client', 'http://example.com/repo/', @@ -414,21 +412,22 @@ class TestCreateLiveImageThread(unittest.TestCase): koji_wrapper.get_image_path.return_value = ['/path/to/image.raw.xz'] t = CreateLiveImageThread(pool) - with mock.patch('os.stat') as stat: - with mock.patch('os.path.getsize') as getsize: + with mock.patch('pungi.phases.live_images.get_file_size') as get_file_size: + get_file_size.return_value = 1024 + with mock.patch('pungi.phases.live_images.get_mtime') as get_mtime: + get_mtime.return_value = 13579 with mock.patch('time.sleep'): - getsize.return_value = 1024 - stat.return_value.st_mtime = 13579 t.process((compose, cmd, compose.variants['Client'], 'amd64'), 1) self.assertEqual(koji_wrapper.run_blocking_cmd.mock_calls, - [mock.call('koji spin-livecd ...', log_file='/a/b/log/log_file')]) + [mock.call('koji spin-livecd ...', + log_file=self.topdir + '/logs/amd64/createiso-None-None-None.amd64.log')]) self.assertEqual(koji_wrapper.get_image_path.mock_calls, [mock.call(123)]) self.assertEqual(copy2.mock_calls, - [mock.call('/path/to/image.raw.xz', '/top/iso_dir/amd64/Client/image-name')]) + [mock.call('/path/to/image.raw.xz', self.topdir + '/compose/Client/amd64/iso/image-name')]) write_manifest_cmd = ' && '.join([ - 'cd /top/iso_dir/amd64/Client', + 'cd ' + self.topdir + '/compose/Client/amd64/iso', 'isoinfo -R -f -i image-name | grep -v \'/TRANS.TBL$\' | sort >> image-name.manifest' ]) self.assertEqual(run.mock_calls, [mock.call(write_manifest_cmd)]) @@ -447,7 +446,7 @@ class TestCreateLiveImageThread(unittest.TestCase): self.assertEqual(Image.return_value.type, 'appliance') self.assertEqual(Image.return_value.format, 'raw.xz') - self.assertEqual(Image.return_value.path, '../../top/iso_dir/amd64/Client/image-name') + self.assertEqual(Image.return_value.path, 'Client/amd64/iso/image-name') self.assertEqual(Image.return_value.size, 1024) self.assertEqual(Image.return_value.mtime, 13579) self.assertEqual(Image.return_value.arch, 'amd64') @@ -461,7 +460,7 @@ class TestCreateLiveImageThread(unittest.TestCase): @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({ + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji', 'failable_deliverables': [('^.+$', {'*': ['live']})], }) @@ -498,7 +497,7 @@ class TestCreateLiveImageThread(unittest.TestCase): @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({ + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji', 'failable_deliverables': [('^.+$', {'*': ['live']})], }) diff --git a/tests/test_livemediaphase.py b/tests/test_livemediaphase.py index eecee799..5c786b78 100755 --- a/tests/test_livemediaphase.py +++ b/tests/test_livemediaphase.py @@ -10,13 +10,13 @@ import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from pungi.phases.livemedia_phase import LiveMediaPhase, LiveMediaThread -from tests.helpers import _DummyCompose +from tests.helpers import _DummyCompose, PungiTestCase -class TestLiveMediaPhase(unittest.TestCase): +class TestLiveMediaPhase(PungiTestCase): @mock.patch('pungi.phases.livemedia_phase.ThreadPool') def test_live_media_minimal(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_media': { '^Server$': [ { @@ -45,18 +45,18 @@ class TestLiveMediaPhase(unittest.TestCase): 'ksversion': None, 'name': 'Fedora Server Live', 'release': None, - 'repo': ['/repo/$basearch/Server'], + 'repo': [self.topdir + '/compose/Server/$basearch/os'], 'scratch': False, 'skip_tag': None, 'target': 'f24', 'title': None, - 'install_tree': '/ostree/$basearch/Server', + 'install_tree': self.topdir + '/compose/Server/$basearch/os', 'version': 'Rawhide', }))]) @mock.patch('pungi.phases.livemedia_phase.ThreadPool') def test_live_media_non_existing_install_tree(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_media': { '^Server$': [ { @@ -79,7 +79,7 @@ class TestLiveMediaPhase(unittest.TestCase): @mock.patch('pungi.phases.livemedia_phase.ThreadPool') def test_live_media_non_existing_repo(self, ThreadPool): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_media': { '^Server$': [ { @@ -103,7 +103,7 @@ class TestLiveMediaPhase(unittest.TestCase): @mock.patch('pungi.phases.livemedia_phase.resolve_git_url') @mock.patch('pungi.phases.livemedia_phase.ThreadPool') def test_live_media_full(self, ThreadPool, resolve_git_url): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'live_media': { '^Server$': [ { @@ -143,24 +143,25 @@ class TestLiveMediaPhase(unittest.TestCase): 'name': 'Fedora Server Live', 'release': '20151203.0', 'repo': ['http://example.com/extra_repo', - '/repo/$basearch/Everything', - '/repo/$basearch/Server'], + self.topdir + '/compose/Everything/$basearch/os', + self.topdir + '/compose/Server/$basearch/os'], 'scratch': True, 'skip_tag': True, 'target': 'f24', 'title': 'Custom Title', - 'install_tree': '/ostree/$basearch/Everything', + 'install_tree': self.topdir + '/compose/Everything/$basearch/os', 'version': 'Rawhide', }))]) -class TestCreateImageBuildThread(unittest.TestCase): +class TestCreateImageBuildThread(PungiTestCase): + @mock.patch('pungi.phases.livemedia_phase.get_mtime') + @mock.patch('pungi.phases.livemedia_phase.get_file_size') @mock.patch('pungi.phases.livemedia_phase.KojiWrapper') @mock.patch('pungi.phases.livemedia_phase.Linker') - @mock.patch('pungi.phases.livemedia_phase.makedirs') - def test_process(self, makedirs, Linker, KojiWrapper): - compose = _DummyCompose({ + def test_process(self, Linker, KojiWrapper, get_file_size, get_mtime): + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji' }) config = { @@ -204,15 +205,15 @@ class TestCreateImageBuildThread(unittest.TestCase): } t = LiveMediaThread(pool) - with mock.patch('os.stat') as stat: - with mock.patch('os.path.getsize') as getsize: - with mock.patch('time.sleep'): - getsize.return_value = 1024 - stat.return_value.st_mtime = 13579 - t.process((compose, compose.variants['Server'], config), 1) + get_file_size.return_value = 1024 + get_mtime.return_value = 13579 + with mock.patch('time.sleep'): + t.process((compose, compose.variants['Server'], config), 1) - self.assertEqual(run_blocking_cmd.mock_calls, - [mock.call('koji-spin-livemedia', log_file='/a/b/log/log_file')]) + self.assertEqual( + run_blocking_cmd.mock_calls, + [mock.call('koji-spin-livemedia', + log_file=self.topdir + '/logs/amd64-x86_64/livemedia-Server.amd64-x86_64.log')]) self.assertEqual(get_live_media_cmd.mock_calls, [mock.call({'arch': 'amd64,x86_64', 'ksfile': 'file.ks', @@ -228,21 +229,20 @@ class TestCreateImageBuildThread(unittest.TestCase): 'version': 'Rawhide'})]) self.assertEqual(get_image_paths.mock_calls, [mock.call(1234)]) - self.assertItemsEqual(makedirs.mock_calls, - [mock.call('/iso_dir/x86_64/Server'), - mock.call('/iso_dir/amd64/Server')]) + self.assertTrue(os.path.isdir(self.topdir + '/compose/Server/x86_64/iso')) + self.assertTrue(os.path.isdir(self.topdir + '/compose/Server/amd64/iso')) link = Linker.return_value.link self.assertItemsEqual(link.mock_calls, [mock.call('/koji/task/1235/Live-20160103.amd64.iso', - '/iso_dir/amd64/Server/Live-20160103.amd64.iso', + self.topdir + '/compose/Server/amd64/iso/Live-20160103.amd64.iso', link_type='hardlink-or-copy'), mock.call('/koji/task/1235/Live-20160103.x86_64.iso', - '/iso_dir/x86_64/Server/Live-20160103.x86_64.iso', + self.topdir + '/compose/Server/x86_64/iso/Live-20160103.x86_64.iso', link_type='hardlink-or-copy')]) image_relative_paths = [ - 'iso_dir/amd64/Server/Live-20160103.amd64.iso', - 'iso_dir/x86_64/Server/Live-20160103.x86_64.iso' + 'Server/amd64/iso/Live-20160103.amd64.iso', + 'Server/x86_64/iso/Live-20160103.x86_64.iso' ] self.assertEqual(len(compose.im.add.call_args_list), 2) @@ -258,7 +258,7 @@ class TestCreateImageBuildThread(unittest.TestCase): @mock.patch('pungi.phases.livemedia_phase.KojiWrapper') def test_handle_koji_fail(self, KojiWrapper): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji', 'failable_deliverables': [ ('^.+$', {'*': ['live-media']}) @@ -297,7 +297,7 @@ class TestCreateImageBuildThread(unittest.TestCase): @mock.patch('pungi.phases.livemedia_phase.KojiWrapper') def test_handle_exception(self, KojiWrapper): - compose = _DummyCompose({ + compose = _DummyCompose(self.topdir, { 'koji_profile': 'koji', 'failable_deliverables': [ ('^.+$', {'*': ['live-media']})