# -*- coding: utf-8 -*- from unittest import mock import os import six from pungi.phases.livemedia_phase import LiveMediaPhase, LiveMediaThread from tests.helpers import DummyCompose, PungiTestCase, boom class TestLiveMediaPhase(PungiTestCase): @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_live_media_minimal(self, ThreadPool): compose = DummyCompose( self.topdir, { "live_media": { "^Server$": [ { "target": "f24", "kickstart": "file.ks", "ksurl": "git://example.com/repo.git", "name": "Fedora Server Live", "version": "Rawhide", } ] }, "koji_profile": "koji", "koji_cache": "/tmp", }, ) self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) phase.run() phase.pool.add.assert_called() self.assertEqual( phase.pool.queue_put.call_args_list, [ mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f24", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "Rawhide", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ) ], ) @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_expand_failable(self, ThreadPool): compose = DummyCompose( self.topdir, { "live_media": { "^Server$": [ { "target": "f24", "kickstart": "file.ks", "ksurl": "git://example.com/repo.git", "name": "Fedora Server Live", "version": "Rawhide", "failable": ["*"], } ] }, "koji_profile": "koji", "koji_cache": "/tmp", }, ) self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) phase.run() phase.pool.add.assert_called() self.assertEqual( phase.pool.queue_put.call_args_list, [ mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f24", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "Rawhide", "subvariant": "Server", "failable_arches": ["amd64", "x86_64"], "nomacboot": False, }, ) ) ], ) @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_live_media_with_phase_global_opts(self, ThreadPool): compose = DummyCompose( self.topdir, { "live_media_ksurl": "git://example.com/repo.git#BEEFCAFE", "live_media_target": "f24", "live_media_release": "RRR", "live_media_version": "Rawhide", "live_media": { "^Server$": [ {"kickstart": "file.ks", "name": "Fedora Server Live"}, {"kickstart": "different.ks", "name": "Fedora Server Live"}, { "kickstart": "yet-another.ks", "name": "Fedora Server Live", "ksurl": "git://different.com/repo.git", "target": "f25", "release": "XXX", "version": "25", }, ] }, "koji_profile": "koji", "koji_cache": "/tmp", }, ) self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) phase.run() phase.pool.add.assert_called() self.assertEqual( phase.pool.queue_put.call_args_list, [ mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git#BEEFCAFE", "ksversion": None, "name": "Fedora Server Live", "release": "RRR", "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f24", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "Rawhide", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ), mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "different.ks", "ksurl": "git://example.com/repo.git#BEEFCAFE", "ksversion": None, "name": "Fedora Server Live", "release": "RRR", "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f24", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "Rawhide", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ), mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "yet-another.ks", "ksurl": "git://different.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": "XXX", "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f25", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "25", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ), ], ) @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_live_media_with_global_opts(self, ThreadPool): compose = DummyCompose( self.topdir, { "global_ksurl": "git://example.com/repo.git#BEEFCAFE", "global_target": "f24", "global_release": "RRR", "global_version": "Rawhide", "live_media": { "^Server$": [ {"kickstart": "file.ks", "name": "Fedora Server Live"}, {"kickstart": "different.ks", "name": "Fedora Server Live"}, { "kickstart": "yet-another.ks", "name": "Fedora Server Live", "ksurl": "git://different.com/repo.git", "target": "f25", "release": "XXX", "version": "25", }, ] }, "koji_profile": "koji", "koji_cache": "/tmp", }, ) self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) phase.run() phase.pool.add.assert_called() self.assertEqual( phase.pool.queue_put.call_args_list, [ mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git#BEEFCAFE", "ksversion": None, "name": "Fedora Server Live", "release": "RRR", "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f24", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "Rawhide", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ), mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "different.ks", "ksurl": "git://example.com/repo.git#BEEFCAFE", "ksversion": None, "name": "Fedora Server Live", "release": "RRR", "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f24", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "Rawhide", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ), mock.call( ( compose, compose.variants["Server"], { "arches": ["amd64", "x86_64"], "ksfile": "yet-another.ks", "ksurl": "git://different.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": "XXX", "repo": [self.topdir + "/compose/Server/$basearch/os"], "scratch": False, "skip_tag": None, "target": "f25", "install_tree": self.topdir + "/compose/Server/$basearch/os", "version": "25", "subvariant": "Server", "failable_arches": [], "nomacboot": False, }, ) ), ], ) @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_live_media_non_existing_install_tree(self, ThreadPool): compose = DummyCompose( self.topdir, { "live_media": { "^Server$": [ { "target": "f24", "kickstart": "file.ks", "ksurl": "git://example.com/repo.git", "name": "Fedora Server Live", "version": "Rawhide", "install_tree_from": "Missing", } ] }, "koji_profile": "koji", "koji_cache": "/tmp", }, ) self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) with self.assertRaisesRegex( RuntimeError, r"no.+Missing.+when building.+Server" ): phase.run() @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_live_media_non_existing_repo(self, ThreadPool): compose = DummyCompose( self.topdir, { "live_media": { "^Server$": [ { "target": "f24", "kickstart": "file.ks", "ksurl": "git://example.com/repo.git", "name": "Fedora Server Live", "version": "Rawhide", "repo": "Missing", } ] }, "koji_profile": "koji", "koji_cache": "/tmp", }, ) self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) with self.assertRaisesRegex( RuntimeError, r"There is no variant Missing to get repo from." ): phase.run() @mock.patch("pungi.phases.livemedia_phase.ThreadPool") def test_live_media_full(self, ThreadPool): compose = DummyCompose( self.topdir, { "live_media": { "^Server$": [ { "target": "f24", "kickstart": "file.ks", "ksurl": "git://example.com/repo.git#BEEFCAFE", "name": "Fedora Server Live", "scratch": True, "skip_tag": True, "repo": [ "http://example.com/extra_repo", "Everything", "Server-optional", ], "arches": ["x86_64"], "ksversion": "24", "release": None, "install_tree_from": "Server-optional", "subvariant": "Something", "failable": ["*"], "nomacboot": True, } ] } }, ) compose.setup_optional() self.assertValidConfig(compose.conf) phase = LiveMediaPhase(compose) phase.run() phase.pool.add.assert_called() self.assertEqual( phase.pool.queue_put.call_args_list, [ mock.call( ( compose, compose.variants["Server"], { "arches": ["x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git#BEEFCAFE", "ksversion": "24", "name": "Fedora Server Live", "release": "20151203.t.0", "repo": [ "http://example.com/extra_repo", self.topdir + "/compose/Everything/$basearch/os", self.topdir + "/compose/Server-optional/$basearch/os", self.topdir + "/compose/Server/$basearch/os", ], "scratch": True, "skip_tag": True, "target": "f24", "install_tree": self.topdir + "/compose/Server-optional/$basearch/os", "version": "25", "subvariant": "Something", "failable_arches": ["x86_64"], "nomacboot": True, }, ) ) ], ) class TestLiveMediaThread(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") def test_process(self, Linker, KojiWrapper, get_file_size, get_mtime): compose = DummyCompose(self.topdir, {"koji_profile": "koji"}) config = { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": ["/repo/$basearch/Server"], "scratch": False, "skip_tag": None, "target": "f24", "version": "Rawhide", "subvariant": "KDE", "failable_arches": [], } pool = mock.Mock() get_live_media_cmd = KojiWrapper.return_value.get_live_media_cmd get_live_media_cmd.return_value = "koji-spin-livemedia" run_blocking_cmd = KojiWrapper.return_value.run_blocking_cmd run_blocking_cmd.return_value = { "task_id": 1234, "retcode": 0, "output": None, } get_image_paths = KojiWrapper.return_value.get_image_paths get_image_paths.return_value = { "x86_64": [ "/koji/task/1235/tdl-amd64.xml", "/koji/task/1235/Live-20160103.x86_64.iso", "/koji/task/1235/Live-20160103.x86_64.tar.xz", ], "amd64": [ "/koji/task/1235/tdl-amd64.xml", "/koji/task/1235/Live-20160103.amd64.iso", "/koji/task/1235/Live-20160103.amd64.tar.xz", ], } t = LiveMediaThread(pool) 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=self.topdir + "/logs/amd64-x86_64/livemedia-Server-KDE.amd64-x86_64.log", ) ], ) self.assertEqual( get_live_media_cmd.mock_calls, [ mock.call( { "arch": "amd64,x86_64", "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": ["/repo/$basearch/Server"], "scratch": False, "skip_tag": None, "target": "f24", "version": "Rawhide", "can_fail": [], } ) ], ) self.assertEqual( get_image_paths.mock_calls, [mock.call(1234, callback=mock.ANY)] ) 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 six.assertCountEqual( self, link.mock_calls, [ mock.call( "/koji/task/1235/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", self.topdir + "/compose/Server/x86_64/iso/Live-20160103.x86_64.iso", link_type="hardlink-or-copy", ), ], ) image_relative_paths = [ "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) for call in compose.im.add.call_args_list: _, kwargs = call image = kwargs["image"] self.assertEqual(kwargs["variant"], "Server") self.assertIn(kwargs["arch"], ("amd64", "x86_64")) self.assertEqual(kwargs["arch"], image.arch) self.assertIn(image.path, image_relative_paths) self.assertEqual("iso", image.format) self.assertEqual("live", image.type) self.assertEqual("KDE", image.subvariant) @mock.patch("pungi.phases.livemedia_phase.get_mtime") @mock.patch("pungi.phases.livemedia_phase.get_file_size") @mock.patch("pungi.phases.livemedia_phase.KojiWrapper") def test_handle_koji_fail(self, KojiWrapper, get_file_size, get_mtime): compose = DummyCompose( self.topdir, {"koji_profile": "koji", "koji_cache": "/tmp"} ) config = { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": ["/repo/$basearch/Server"], "scratch": False, "skip_tag": None, "target": "f24", "version": "Rawhide", "subvariant": "KDE", "failable_arches": ["amd64", "x86_64"], } pool = mock.Mock() run_blocking_cmd = KojiWrapper.return_value.run_blocking_cmd run_blocking_cmd.return_value = { "task_id": 1234, "retcode": 1, "output": None, } get_file_size.return_value = 1024 get_mtime.return_value.st_mtime = 13579 t = LiveMediaThread(pool) with mock.patch("time.sleep"): t.process((compose, compose.variants["Server"], config), 1) pool._logger.error.assert_has_calls( [ mock.call( "[FAIL] Live media (variant Server, arch *, subvariant KDE) failed, but going on anyway." # noqa: E501 ), mock.call( "Live media task failed: 1234. See %s for more details." % ( os.path.join( self.topdir, "logs/amd64-x86_64/livemedia-Server-KDE.amd64-x86_64.log", ) ) ), ] ) self.assertEqual( KojiWrapper.return_value.get_live_media_cmd.mock_calls, [ mock.call( { "arch": "amd64,x86_64", "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "skip_tag": None, "target": "f24", "release": None, "version": "Rawhide", "scratch": False, "can_fail": ["amd64", "x86_64"], "name": "Fedora Server Live", "repo": ["/repo/$basearch/Server"], } ) ], ) @mock.patch("pungi.phases.livemedia_phase.get_mtime") @mock.patch("pungi.phases.livemedia_phase.get_file_size") @mock.patch("pungi.phases.livemedia_phase.KojiWrapper") def test_handle_exception(self, KojiWrapper, get_file_size, get_mtime): compose = DummyCompose( self.topdir, { "koji_profile": "koji", "koji_cache": "/tmp", "failable_deliverables": [("^.+$", {"*": ["live-media"]})], }, ) config = { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": ["/repo/$basearch/Server"], "scratch": False, "skip_tag": None, "target": "f24", "version": "Rawhide", "subvariant": "KDE", "failable_arches": ["amd64", "x86_64"], } pool = mock.Mock() run_blocking_cmd = KojiWrapper.return_value.run_blocking_cmd run_blocking_cmd.side_effect = boom get_file_size.return_value = 1024 get_mtime.return_value.st_mtime = 13579 t = LiveMediaThread(pool) with mock.patch("time.sleep"): t.process((compose, compose.variants["Server"], config), 1) pool._logger.error.assert_has_calls( [ mock.call( "[FAIL] Live media (variant Server, arch *, subvariant KDE) failed, but going on anyway." # noqa: E501 ), mock.call("BOOM"), ] ) self.assertEqual( KojiWrapper.return_value.get_live_media_cmd.mock_calls, [ mock.call( { "arch": "amd64,x86_64", "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "skip_tag": None, "target": "f24", "release": None, "version": "Rawhide", "scratch": False, "can_fail": ["amd64", "x86_64"], "name": "Fedora Server Live", "repo": ["/repo/$basearch/Server"], } ) ], ) @mock.patch("pungi.phases.livemedia_phase.get_mtime") @mock.patch("pungi.phases.livemedia_phase.get_file_size") @mock.patch("pungi.phases.livemedia_phase.KojiWrapper") def test_handle_exception_only_one_arch_optional( self, KojiWrapper, get_file_size, get_mtime ): compose = DummyCompose( self.topdir, { "koji_profile": "koji", "koji_cache": "/tmp", "failable_deliverables": [("^.+$", {"*": ["live-media"]})], }, ) config = { "arches": ["amd64", "x86_64"], "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "name": "Fedora Server Live", "release": None, "repo": ["/repo/$basearch/Server"], "scratch": False, "skip_tag": None, "target": "f24", "version": "Rawhide", "subvariant": "KDE", "failable_arches": ["amd64"], } pool = mock.Mock() run_blocking_cmd = KojiWrapper.return_value.run_blocking_cmd run_blocking_cmd.side_effect = boom get_file_size.return_value = 1024 get_mtime.return_value.st_mtime = 13579 t = LiveMediaThread(pool) with self.assertRaises(Exception): with mock.patch("time.sleep"): t.process((compose, compose.variants["Server"], config), 1) self.assertEqual( KojiWrapper.return_value.get_live_media_cmd.mock_calls, [ mock.call( { "arch": "amd64,x86_64", "ksfile": "file.ks", "ksurl": "git://example.com/repo.git", "ksversion": None, "skip_tag": None, "target": "f24", "release": None, "version": "Rawhide", "scratch": False, "can_fail": ["amd64"], "name": "Fedora Server Live", "repo": ["/repo/$basearch/Server"], } ) ], )