class DNFManagerTestCase(unittest.TestCase): """Test the abstraction of the DNF base.""" def setUp(self): self.maxDiff = None self.dnf_manager = DNFManager() def _check_configuration(self, *attributes): """Check the DNF configuration.""" configuration = self.dnf_manager._base.conf.dump() configuration = configuration.splitlines(keepends=False) for attribute in attributes: assert attribute in configuration def _check_substitutions(self, substitutions): """Check the DNF substitutions.""" assert dict(self.dnf_manager._base.conf.substitutions) == substitutions def test_create_base(self): """Test the creation of the DNF base.""" assert self.dnf_manager._base is not None def test_reset_base(self): """Test the reset of the DNF base.""" base_1 = self.dnf_manager._base assert self.dnf_manager._base == base_1 self.dnf_manager.reset_base() base_2 = self.dnf_manager._base assert self.dnf_manager._base == base_2 assert self.dnf_manager._base != base_1 def test_clear_cache(self): """Test the clear_cache method.""" self.dnf_manager.clear_cache() def test_set_default_configuration(self): """Test the default configuration of the DNF base.""" self._check_configuration( "cachedir = /tmp/dnf.cache", "pluginconfpath = /tmp/dnf.pluginconf", "logdir = /tmp/", ) self._check_configuration("installroot = /mnt/sysroot", "persistdir = /mnt/sysroot/var/lib/dnf") self._check_configuration("reposdir = " "/etc/yum.repos.d, " "/etc/anaconda.repos.d") self._check_substitutions({ "arch": "x86_64", "basearch": "x86_64", "releasever": "rawhide" }) @patch( "pyanaconda.modules.payloads.payload.dnf.dnf_manager.get_os_release_value" ) def test_set_module_platform_id(self, get_platform_id): """Test the configuration of module_platform_id.""" get_platform_id.return_value = "platform:f32" self.dnf_manager.reset_base() self._check_configuration("module_platform_id = platform:f32") def test_configure_proxy(self): """Test the proxy configuration.""" self.dnf_manager.configure_proxy("http://*****:*****@example.com/proxy") self._check_configuration( "proxy = http://example.com:3128", "proxy_username = user", "proxy_password = pass", ) self.dnf_manager.configure_proxy("@:/invalid") self._check_configuration( "proxy = ", "proxy_username = "******"proxy_password = "******"http://example.com/proxy") self._check_configuration( "proxy = http://example.com:3128", "proxy_username = "******"proxy_password = "******"proxy = ", "proxy_username = "******"proxy_password = "******"""Test the configuration of the DNF base.""" data = PackagesConfigurationData() self.dnf_manager.configure_base(data) self._check_configuration( "multilib_policy = best", "timeout = 30", "retries = 10", "install_weak_deps = 1", ) assert self.dnf_manager._ignore_broken_packages is False assert self.dnf_manager._ignore_missing_packages is False data.multilib_policy = MULTILIB_POLICY_ALL data.timeout = 100 data.retries = 5 data.broken_ignored = True data.missing_ignored = True data.weakdeps_excluded = True self.dnf_manager.configure_base(data) self._check_configuration( "multilib_policy = all", "timeout = 100", "retries = 5", "install_weak_deps = 0", ) assert self.dnf_manager._ignore_broken_packages is True assert self.dnf_manager._ignore_missing_packages is True def test_dump_configuration(self): """Test the dump of the DNF configuration.""" with self.assertLogs(level="DEBUG") as cm: self.dnf_manager.dump_configuration() msg = "DNF configuration:" assert any(map(lambda x: msg in x, cm.output)) msg = "installroot = /mnt/sysroot" assert any(map(lambda x: msg in x, cm.output)) def test_get_installation_size(self): """Test the get_installation_size method.""" # No transaction. size = self.dnf_manager.get_installation_size() assert size == Size("3000 MiB") # Fake transaction. tsi_1 = Mock() tsi_1.pkg.installsize = 1024 * 100 tsi_1.pkg.files = ["/file"] * 10 tsi_2 = Mock() tsi_2.pkg.installsize = 1024 * 200 tsi_2.pkg.files = ["/file"] * 20 self.dnf_manager._base.transaction = [tsi_1, tsi_2] size = self.dnf_manager.get_installation_size() size = size.round_to_nearest("KiB", ROUND_UP) assert size == Size("528 KiB") def test_get_download_size(self): """Test the get_download_size method.""" # No transaction. size = self.dnf_manager.get_download_size() assert size == Size(0) # Fake transaction. tsi_1 = Mock() tsi_1.pkg.downloadsize = 1024 * 1024 * 100 tsi_2 = Mock() tsi_2.pkg.downloadsize = 1024 * 1024 * 200 self.dnf_manager._base.transaction = [tsi_1, tsi_2] size = self.dnf_manager.get_download_size() assert size == Size("450 MiB") @patch("dnf.module.module_base.ModuleBase.enable") def test_enable_modules(self, module_base_enable): """Test the enable_modules method.""" self.dnf_manager.enable_modules(module_specs=["m1", "m2:latest"]) module_base_enable.assert_called_once_with(["m1", "m2:latest"]) @patch("dnf.module.module_base.ModuleBase.enable") def test_enable_modules_error(self, module_base_enable): """Test the failed enable_modules method.""" module_base_enable.side_effect = MarkingErrors( module_depsolv_errors=["e1", "e2"]) with pytest.raises(BrokenSpecsError): self.dnf_manager.enable_modules(module_specs=["m1", "m2:latest"]) @patch("dnf.module.module_base.ModuleBase.disable") def test_disable_modules(self, module_base_disable): """Test the enable_modules method.""" self.dnf_manager.disable_modules(module_specs=["m1", "m2:latest"]) module_base_disable.assert_called_once_with(["m1", "m2:latest"]) @patch("dnf.module.module_base.ModuleBase.disable") def test_disable_modules_error(self, module_base_disable): """Test the failed enable_modules method.""" module_base_disable.side_effect = MarkingErrors( module_depsolv_errors=["e1", "e2"]) with pytest.raises(BrokenSpecsError): self.dnf_manager.disable_modules(module_specs=["m1", "m2:latest"]) @patch("dnf.base.Base.install_specs") def test_apply_specs(self, install_specs): """Test the apply_specs method.""" self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.assert_called_once_with(install=["@g1", "p1"], exclude=["@g2", "p2"], strict=True) @patch("dnf.base.Base.install_specs") def test_apply_specs_error(self, install_specs): """Test the apply_specs method with an error.""" install_specs.side_effect = MarkingErrors(error_group_specs=["@g1"]) with pytest.raises(BrokenSpecsError): self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.side_effect = MarkingErrors(no_match_group_specs=["@g1"]) with pytest.raises(MissingSpecsError): self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) @patch("dnf.base.Base.install_specs") def test_apply_specs_ignore_broken(self, install_specs): """Test the apply_specs method with ignored broken packages.""" self.dnf_manager._ignore_broken_packages = True self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.assert_called_once_with(install=["@g1", "p1"], exclude=["@g2", "p2"], strict=False) @patch("dnf.base.Base.install_specs") def test_apply_specs_ignore_missing(self, install_specs): """Test the apply_specs method with ignored missing packages.""" self.dnf_manager._ignore_missing_packages = True # Ignore a missing package. install_specs.side_effect = MarkingErrors(no_match_pkg_specs=["p1"]) self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.assert_called_once_with(install=["@g1", "p1"], exclude=["@g2", "p2"], strict=True) # Don't ignore a broken transaction. install_specs.side_effect = MarkingErrors(error_pkg_specs=["p1"]) with pytest.raises(BrokenSpecsError): self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) @patch("dnf.base.Base.download_packages") @patch("dnf.base.Base.transaction") def test_download_packages(self, transaction, download_packages): """Test the download_packages method.""" callback = Mock() transaction.install_set = ["p1", "p2", "p3"] download_packages.side_effect = self._download_packages self.dnf_manager.download_packages(callback) callback.assert_has_calls([ call('Downloading 3 RPMs, 25 B / 300 B (8%) done.'), call('Downloading 3 RPMs, 75 B / 300 B (25%) done.'), call('Downloading 3 RPMs, 100 B / 300 B (33%) done.'), call('Downloading 3 RPMs, 125 B / 300 B (41%) done.'), call('Downloading 3 RPMs, 175 B / 300 B (58%) done.'), call('Downloading 3 RPMs, 200 B / 300 B (66%) done.'), call('Downloading 3 RPMs, 225 B / 300 B (75%) done.'), call('Downloading 3 RPMs, 275 B / 300 B (91%) done.'), call('Downloading 3 RPMs, 300 B / 300 B (100%) done.') ]) def _download_packages(self, packages, progress): """Simulate the download of packages.""" progress.start(total_files=3, total_size=300) for name in packages: payload = Mock() payload.__str__ = Mock(return_value=name) payload.download_size = 100 progress.last_time = 0 progress.progress(payload, 25) progress.last_time += 3600 progress.progress(payload, 50) progress.last_time = 0 progress.progress(payload, 75) progress.last_time = 0 progress.end(payload, STATUS_OK, "Message!") assert progress.downloads == {"p1": 100, "p2": 100, "p3": 100} @patch("dnf.base.Base.download_packages") @patch("dnf.base.Base.transaction") def test_download_packages_failed(self, transaction, download_packages): """Test the download_packages method with failed packages.""" callback = Mock() transaction.install_set = ["p1", "p2", "p3"] download_packages.side_effect = self._download_packages_failed self.dnf_manager.download_packages(callback) callback.assert_has_calls([ call('Downloading 3 RPMs, 25 B / 300 B (8%) done.'), call('Downloading 3 RPMs, 50 B / 300 B (16%) done.'), call('Downloading 3 RPMs, 75 B / 300 B (25%) done.') ]) def _download_packages_failed(self, packages, progress): """Simulate the failed download of packages.""" progress.start(total_files=3, total_size=300) for name in packages: payload = Mock() payload.__str__ = Mock(return_value=name) payload.download_size = 100 progress.last_time = 0 progress.progress(payload, 25) progress.last_time = 0 progress.end(payload, STATUS_FAILED, "Message!") assert progress.downloads == {"p1": 25, "p2": 25, "p3": 25} @patch("dnf.base.Base.do_transaction") def test_install_packages(self, do_transaction): """Test the install_packages method.""" calls = [] do_transaction.side_effect = self._install_packages self.dnf_manager.install_packages(calls.append) assert calls == [ 'Installing p1.x86_64 (0/3)', 'Installing p2.x86_64 (1/3)', 'Installing p3.x86_64 (2/3)', 'Performing post-installation setup tasks', 'Configuring p1.x86_64', 'Configuring p2.x86_64', 'Configuring p3.x86_64', 'Verifying p1.x86_64 (1/3)', 'Verifying p2.x86_64 (2/3)', 'Verifying p3.x86_64 (3/3)', ] def _get_package(self, name): """Get a mocked package of the specified name.""" package = Mock(spec=Package) package.name = name package.arch = "x86_64" package.evr = "1.2-3" package.buildtime = 100 package.returnIdSum.return_value = ("", "1a2b3c") return package def _install_packages(self, progress): """Simulate the installation of packages.""" packages = list(map(self._get_package, ["p1", "p2", "p3"])) ts_total = len(packages) for ts_done, package in enumerate(packages): progress.progress(package, PKG_INSTALL, 0, 100, ts_done, ts_total) progress.progress(package, PKG_INSTALL, 50, 100, ts_done, ts_total) progress.progress(package, PKG_SCRIPTLET, 75, 100, ts_done, ts_total) progress.progress(package, PKG_INSTALL, 100, 100, ts_done + 1, ts_total) progress.progress(None, TRANS_POST, None, None, None, None) for ts_done, package in enumerate(packages): progress.progress(package, PKG_SCRIPTLET, 100, 100, ts_done + 1, ts_total) for ts_done, package in enumerate(packages): progress.progress(package, PKG_VERIFY, 100, 100, ts_done + 1, ts_total) @patch("dnf.base.Base.do_transaction") def test_install_packages_failed(self, do_transaction): """Test the failed install_packages method.""" calls = [] do_transaction.side_effect = self._install_packages_failed with pytest.raises(PayloadInstallationError) as cm: self.dnf_manager.install_packages(calls.append) msg = "An error occurred during the transaction: " \ "The p1 package couldn't be installed!" assert str(cm.value) == msg assert calls == [] def _install_packages_failed(self, progress): """Simulate the failed installation of packages.""" progress.error("The p1 package couldn't be installed!") @patch("dnf.base.Base.do_transaction") def test_install_packages_quit(self, do_transaction): """Test the terminated install_packages method.""" calls = [] do_transaction.side_effect = self._install_packages_quit with pytest.raises(RuntimeError) as cm: self.dnf_manager.install_packages(calls.append) msg = "The transaction process has ended abruptly: " \ "Something went wrong with the p1 package!" assert msg in str(cm.value) assert calls == [] def _install_packages_quit(self, progress): """Simulate the terminated installation of packages.""" raise IOError("Something went wrong with the p1 package!") def _add_repo(self, name, enabled=True): """Add the DNF repo object.""" repo = Repo(name, self.dnf_manager._base.conf) self.dnf_manager._base.repos.add(repo) if enabled: repo.enable() return repo def test_set_download_location(self): """Test the set_download_location method.""" r1 = self._add_repo("r1") r2 = self._add_repo("r2") r3 = self._add_repo("r3") self.dnf_manager.set_download_location("/my/download/location") assert r1.pkgdir == "/my/download/location" assert r2.pkgdir == "/my/download/location" assert r3.pkgdir == "/my/download/location" def test_download_location(self): """Test the download_location property.""" assert self.dnf_manager.download_location is None self.dnf_manager.set_download_location("/my/location") assert self.dnf_manager.download_location == "/my/location" self.dnf_manager.reset_base() assert self.dnf_manager.download_location is None def test_substitute(self): """Test the substitute method.""" # No variables. assert self.dnf_manager.substitute(None) == "" assert self.dnf_manager.substitute("") == "" assert self.dnf_manager.substitute("/") == "/" assert self.dnf_manager.substitute("/text") == "/text" # Unknown variables. assert self.dnf_manager.substitute("/$unknown") == "/$unknown" # Supported variables. assert self.dnf_manager.substitute("/$basearch") != "/$basearch" assert self.dnf_manager.substitute("/$releasever") != "/$releasever" def test_configure_substitution(self): """Test the configure_substitution function.""" self.dnf_manager.configure_substitution(release_version="123") self._check_substitutions({ "arch": "x86_64", "basearch": "x86_64", "releasever": "123" }) def test_reset_substitution(self): """Test the reset_substitution method.""" self.dnf_manager.configure_substitution(release_version="123") self._check_substitutions({ "arch": "x86_64", "basearch": "x86_64", "releasever": "123" }) self.dnf_manager.reset_substitution() self._check_substitutions({ "arch": "x86_64", "basearch": "x86_64", "releasever": "rawhide" }) @patch("dnf.subject.Subject.get_best_query") def test_is_package_available(self, get_best_query): """Test the is_package_available method.""" self.dnf_manager._base._sack = Mock() assert self.dnf_manager.is_package_available("kernel") is True # No package. get_best_query.return_value = None assert self.dnf_manager.is_package_available("kernel") is False # No metadata. self.dnf_manager._base._sack = None with self.assertLogs(level="WARNING") as cm: assert self.dnf_manager.is_package_available("kernel") is False msg = "There is no metadata about packages!" assert any(map(lambda x: msg in x, cm.output)) def test_match_available_packages(self): """Test the match_available_packages method""" p1 = self._get_package("langpacks-cs") p2 = self._get_package("langpacks-core-cs") p3 = self._get_package("langpacks-core-font-cs") sack = Mock() sack.query.return_value.available.return_value.filter.return_value = [ p1, p2, p3 ] # With metadata. self.dnf_manager._base._sack = sack assert self.dnf_manager.match_available_packages("langpacks-*") == [ "langpacks-cs", "langpacks-core-cs", "langpacks-core-font-cs" ] # No metadata. self.dnf_manager._base._sack = None with self.assertLogs(level="WARNING") as cm: assert self.dnf_manager.match_available_packages( "langpacks-*") == [] msg = "There is no metadata about packages!" assert any(map(lambda x: msg in x, cm.output)) @patch("dnf.base.Base.resolve") def test_resolve_selection(self, resolve): """Test the resolve_selection method.""" self.dnf_manager._base.transaction = [Mock(), Mock()] with self.assertLogs(level="INFO") as cm: self.dnf_manager.resolve_selection() expected = "The software selection has been resolved (2 packages selected)." assert expected in "\n".join(cm.output) resolve.assert_called_once() @patch("dnf.base.Base.resolve") def test_resolve_selection_failed(self, resolve): """Test the failed resolve_selection method.""" resolve.side_effect = DepsolveError("e1") with pytest.raises(InvalidSelectionError) as cm: self.dnf_manager.resolve_selection() expected = \ "The following software marked for installation has errors.\n" \ "This is likely caused by an error with your installation source.\n\n" \ "e1" assert expected == str(cm.value) def test_clear_selection(self): """Test the clear_selection method.""" self.dnf_manager.clear_selection()
class DNFMangerTestCase(unittest.TestCase): """Test the abstraction of the DNF base.""" def setUp(self): self.maxDiff = None self.dnf_manager = DNFManager() def _check_configuration(self, *attributes): """Check the DNF configuration.""" configuration = self.dnf_manager._base.conf.dump() configuration = configuration.splitlines(keepends=False) for attribute in attributes: self.assertIn(attribute, configuration) def _check_substitutions(self, substitutions): """Check the DNF substitutions.""" self.assertEqual(dict(self.dnf_manager._base.conf.substitutions), substitutions) def create_base_test(self): """Test the creation of the DNF base.""" self.assertIsNotNone(self.dnf_manager._base) def reset_base_test(self): """Test the reset of the DNF base.""" base_1 = self.dnf_manager._base self.assertEqual(self.dnf_manager._base, base_1) self.dnf_manager.reset_base() base_2 = self.dnf_manager._base self.assertEqual(self.dnf_manager._base, base_2) self.assertNotEqual(self.dnf_manager._base, base_1) def clear_cache_test(self): """Test the clear_cache method.""" self.dnf_manager.clear_cache() def set_default_configuration_test(self): """Test the default configuration of the DNF base.""" self._check_configuration( "cachedir = /tmp/dnf.cache", "pluginconfpath = /tmp/dnf.pluginconf", "logdir = /tmp/", ) self._check_configuration("installroot = /mnt/sysroot", "persistdir = /mnt/sysroot/var/lib/dnf") self._check_configuration("reposdir = " "/etc/yum.repos.d, " "/etc/anaconda.repos.d") self._check_substitutions({ "arch": "x86_64", "basearch": "x86_64", "releasever": "rawhide" }) @patch( "pyanaconda.modules.payloads.payload.dnf.dnf_manager.get_os_release_value" ) def set_module_platform_id_test(self, get_platform_id): """Test the configuration of module_platform_id.""" get_platform_id.return_value = "platform:f32" self.dnf_manager.reset_base() self._check_configuration("module_platform_id = platform:f32") def configure_proxy_test(self): """Test the proxy configuration.""" self.dnf_manager.configure_proxy("http://*****:*****@example.com/proxy") self._check_configuration( "proxy = http://example.com:3128", "proxy_username = user", "proxy_password = pass", ) self.dnf_manager.configure_proxy("@:/invalid") self._check_configuration( "proxy = ", "proxy_username = "******"proxy_password = "******"http://example.com/proxy") self._check_configuration( "proxy = http://example.com:3128", "proxy_username = "******"proxy_password = "******"proxy = ", "proxy_username = "******"proxy_password = "******"""Test the configuration of the DNF base.""" data = PackagesConfigurationData() self.dnf_manager.configure_base(data) self._check_configuration( "multilib_policy = best", "timeout = 30", "retries = 10", "install_weak_deps = 1", ) self.assertEqual(self.dnf_manager._ignore_broken_packages, False) self.assertEqual(self.dnf_manager._ignore_missing_packages, False) data.multilib_policy = MULTILIB_POLICY_ALL data.timeout = 100 data.retries = 5 data.broken_ignored = True data.missing_ignored = True data.weakdeps_excluded = True self.dnf_manager.configure_base(data) self._check_configuration( "multilib_policy = all", "timeout = 100", "retries = 5", "install_weak_deps = 0", ) self.assertEqual(self.dnf_manager._ignore_broken_packages, True) self.assertEqual(self.dnf_manager._ignore_missing_packages, True) def dump_configuration_test(self): """Test the dump of the DNF configuration.""" with self.assertLogs(level="DEBUG") as cm: self.dnf_manager.dump_configuration() msg = "DNF configuration:" self.assertTrue(any(map(lambda x: msg in x, cm.output))) msg = "installroot = /mnt/sysroot" self.assertTrue(any(map(lambda x: msg in x, cm.output))) def get_installation_size_test(self): """Test the get_installation_size method.""" # No transaction. size = self.dnf_manager.get_installation_size() self.assertEqual(size, Size("3000 MiB")) # Fake transaction. tsi_1 = Mock() tsi_1.pkg.installsize = 1024 * 100 tsi_1.pkg.files = ["/file"] * 10 tsi_2 = Mock() tsi_2.pkg.installsize = 1024 * 200 tsi_2.pkg.files = ["/file"] * 20 self.dnf_manager._base.transaction = [tsi_1, tsi_2] size = self.dnf_manager.get_installation_size() size = size.round_to_nearest("KiB", ROUND_UP) self.assertEqual(size, Size("528 KiB")) def get_download_size_test(self): """Test the get_download_size method.""" # No transaction. size = self.dnf_manager.get_download_size() self.assertEqual(size, Size(0)) # Fake transaction. tsi_1 = Mock() tsi_1.pkg.downloadsize = 1024 * 1024 * 100 tsi_2 = Mock() tsi_2.pkg.downloadsize = 1024 * 1024 * 200 self.dnf_manager._base.transaction = [tsi_1, tsi_2] size = self.dnf_manager.get_download_size() self.assertEqual(size, Size("450 MiB")) def environments_test(self): """Test the environments property.""" self.assertEqual(self.dnf_manager.environments, []) # Fake environments. env_1 = Mock(id="environment-1") env_2 = Mock(id="environment-2") env_3 = Mock(id="environment-3") # Fake comps. comps = Mock(environments=[env_1, env_2, env_3]) self.dnf_manager._base._comps = comps self.assertEqual(self.dnf_manager.environments, [ "environment-1", "environment-2", "environment-3", ]) @patch("dnf.module.module_base.ModuleBase.enable") def enable_modules_test(self, module_base_enable): """Test the enable_modules method.""" self.dnf_manager.enable_modules(module_specs=["m1", "m2:latest"]) module_base_enable.assert_called_once_with(["m1", "m2:latest"]) @patch("dnf.module.module_base.ModuleBase.enable") def enable_modules_error_test(self, module_base_enable): """Test the failed enable_modules method.""" module_base_enable.side_effect = MarkingErrors( module_depsolv_errors=["e1", "e2"]) with self.assertRaises(MarkingErrors): self.dnf_manager.enable_modules(module_specs=["m1", "m2:latest"]) @patch("dnf.module.module_base.ModuleBase.disable") def disable_modules_test(self, module_base_disable): """Test the enable_modules method.""" self.dnf_manager.disable_modules(module_specs=["m1", "m2:latest"]) module_base_disable.assert_called_once_with(["m1", "m2:latest"]) @patch("dnf.module.module_base.ModuleBase.disable") def disable_modules_error_test(self, module_base_disable): """Test the failed enable_modules method.""" module_base_disable.side_effect = MarkingErrors( module_depsolv_errors=["e1", "e2"]) with self.assertRaises(MarkingErrors): self.dnf_manager.disable_modules(module_specs=["m1", "m2:latest"]) @patch("dnf.base.Base.install_specs") def apply_specs_test(self, install_specs): """Test the apply_specs method.""" self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.assert_called_once_with(install=["@g1", "p1"], exclude=["@g2", "p2"], strict=True) @patch("dnf.base.Base.install_specs") def apply_specs_error_test(self, install_specs): """Test the apply_specs method with an error.""" install_specs.side_effect = MarkingErrors(error_group_specs=["@g1"]) with self.assertRaises(MarkingErrors): self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) @patch("dnf.base.Base.install_specs") def apply_specs_ignore_broken_test(self, install_specs): """Test the apply_specs method with ignored broken packages.""" self.dnf_manager._ignore_broken_packages = True self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.assert_called_once_with(install=["@g1", "p1"], exclude=["@g2", "p2"], strict=False) @patch("dnf.base.Base.install_specs") def apply_specs_ignore_missing_test(self, install_specs): """Test the apply_specs method with ignored missing packages.""" self.dnf_manager._ignore_missing_packages = True # Ignore a missing package. install_specs.side_effect = MarkingErrors(no_match_pkg_specs=["p1"]) self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) install_specs.assert_called_once_with(install=["@g1", "p1"], exclude=["@g2", "p2"], strict=True) # Don't ignore a broken transaction. install_specs.side_effect = MarkingErrors(error_pkg_specs=["p1"]) with self.assertRaises(MarkingErrors): self.dnf_manager.apply_specs(include_list=["@g1", "p1"], exclude_list=["@g2", "p2"]) @patch("dnf.base.Base.download_packages") @patch("dnf.base.Base.transaction") def download_packages_test(self, transaction, download_packages): """Test the download_packages method.""" callback = Mock() transaction.install_set = ["p1", "p2", "p3"] download_packages.side_effect = self._download_packages self.dnf_manager.download_packages(callback) callback.assert_has_calls([ call('Downloading 3 RPMs, 25 B / 300 B (8%) done.'), call('Downloading 3 RPMs, 75 B / 300 B (25%) done.'), call('Downloading 3 RPMs, 100 B / 300 B (33%) done.'), call('Downloading 3 RPMs, 125 B / 300 B (41%) done.'), call('Downloading 3 RPMs, 175 B / 300 B (58%) done.'), call('Downloading 3 RPMs, 200 B / 300 B (66%) done.'), call('Downloading 3 RPMs, 225 B / 300 B (75%) done.'), call('Downloading 3 RPMs, 275 B / 300 B (91%) done.'), call('Downloading 3 RPMs, 300 B / 300 B (100%) done.') ]) def _download_packages(self, packages, progress): """Simulate the download of packages.""" progress.start(total_files=3, total_size=300) for name in packages: payload = Mock() payload.__str__ = Mock(return_value=name) payload.download_size = 100 progress.last_time = 0 progress.progress(payload, 25) progress.last_time += 3600 progress.progress(payload, 50) progress.last_time = 0 progress.progress(payload, 75) progress.last_time = 0 progress.end(payload, STATUS_OK, "Message!") self.assertEqual(progress.downloads, {"p1": 100, "p2": 100, "p3": 100}) @patch("dnf.base.Base.download_packages") @patch("dnf.base.Base.transaction") def download_packages_failed_test(self, transaction, download_packages): """Test the download_packages method with failed packages.""" callback = Mock() transaction.install_set = ["p1", "p2", "p3"] download_packages.side_effect = self._download_packages_failed self.dnf_manager.download_packages(callback) callback.assert_has_calls([ call('Downloading 3 RPMs, 25 B / 300 B (8%) done.'), call('Downloading 3 RPMs, 50 B / 300 B (16%) done.'), call('Downloading 3 RPMs, 75 B / 300 B (25%) done.') ]) def _download_packages_failed(self, packages, progress): """Simulate the failed download of packages.""" progress.start(total_files=3, total_size=300) for name in packages: payload = Mock() payload.__str__ = Mock(return_value=name) payload.download_size = 100 progress.last_time = 0 progress.progress(payload, 25) progress.last_time = 0 progress.end(payload, STATUS_FAILED, "Message!") self.assertEqual(progress.downloads, {"p1": 25, "p2": 25, "p3": 25}) @patch("dnf.base.Base.do_transaction") def install_packages_test(self, do_transaction): """Test the install_packages method.""" calls = [] do_transaction.side_effect = self._install_packages self.dnf_manager.install_packages(calls.append) self.assertEqual(calls, [ 'Installing p1.x86_64 (0/3)', 'Installing p2.x86_64 (1/3)', 'Installing p3.x86_64 (2/3)', 'Performing post-installation setup tasks', 'Configuring p1.x86_64', 'Configuring p2.x86_64', 'Configuring p3.x86_64', 'Verifying p1.x86_64 (1/3)', 'Verifying p2.x86_64 (2/3)', 'Verifying p3.x86_64 (3/3)', ]) def _get_package(self, name): """Get a mocked package of the specified name.""" package = Mock(spec=Package) package.name = name package.arch = "x86_64" package.evr = "1.2-3" package.buildtime = 100 package.returnIdSum.return_value = ("", "1a2b3c") return package def _install_packages(self, progress): """Simulate the installation of packages.""" packages = list(map(self._get_package, ["p1", "p2", "p3"])) ts_total = len(packages) for ts_done, package in enumerate(packages): progress.progress(package, PKG_INSTALL, 0, 100, ts_done, ts_total) progress.progress(package, PKG_INSTALL, 50, 100, ts_done, ts_total) progress.progress(package, PKG_SCRIPTLET, 75, 100, ts_done, ts_total) progress.progress(package, PKG_INSTALL, 100, 100, ts_done + 1, ts_total) progress.progress(None, TRANS_POST, None, None, None, None) for ts_done, package in enumerate(packages): progress.progress(package, PKG_SCRIPTLET, 100, 100, ts_done + 1, ts_total) for ts_done, package in enumerate(packages): progress.progress(package, PKG_VERIFY, 100, 100, ts_done + 1, ts_total) @patch("dnf.base.Base.do_transaction") def install_packages_failed_test(self, do_transaction): """Test the failed install_packages method.""" calls = [] do_transaction.side_effect = self._install_packages_failed with self.assertRaises(PayloadInstallationError) as cm: self.dnf_manager.install_packages(calls.append) msg = "An error occurred during the transaction: " \ "The p1 package couldn't be installed!" self.assertEqual(str(cm.exception), msg) self.assertEqual(calls, []) def _install_packages_failed(self, progress): """Simulate the failed installation of packages.""" progress.error("The p1 package couldn't be installed!") @patch("dnf.base.Base.do_transaction") def install_packages_quit_test(self, do_transaction): """Test the terminated install_packages method.""" calls = [] do_transaction.side_effect = self._install_packages_quit with self.assertRaises(RuntimeError) as cm: self.dnf_manager.install_packages(calls.append) msg = "The transaction process has ended abruptly: " \ "Something went wrong with the p1 package!" self.assertIn(msg, str(cm.exception)) self.assertEqual(calls, []) def _install_packages_quit(self, progress): """Simulate the terminated installation of packages.""" raise IOError("Something went wrong with the p1 package!") def _add_repo(self, name, enabled=True): """Add the DNF repo object.""" repo = Repo(name, self.dnf_manager._base.conf) self.dnf_manager._base.repos.add(repo) if enabled: repo.enable() return repo def set_download_location_test(self): """Test the set_download_location method.""" r1 = self._add_repo("r1") r2 = self._add_repo("r2") r3 = self._add_repo("r3") self.dnf_manager.set_download_location("/my/download/location") self.assertEqual(r1.pkgdir, "/my/download/location") self.assertEqual(r2.pkgdir, "/my/download/location") self.assertEqual(r3.pkgdir, "/my/download/location") def download_location_test(self): """Test the download_location property.""" self.assertEqual(self.dnf_manager.download_location, None) self.dnf_manager.set_download_location("/my/location") self.assertEqual(self.dnf_manager.download_location, "/my/location") self.dnf_manager.reset_base() self.assertEqual(self.dnf_manager.download_location, None)