1# -*- coding: utf-8 -*- 2 3# Copyright (C) 2012-2018 Red Hat, Inc. 4# 5# This copyrighted material is made available to anyone wishing to use, 6# modify, copy, or redistribute it subject to the terms and conditions of 7# the GNU General Public License v.2, or (at your option) any later version. 8# This program is distributed in the hope that it will be useful, but WITHOUT 9# ANY WARRANTY expressed or implied, including the implied warranties of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 11# Public License for more details. You should have received a copy of the 12# GNU General Public License along with this program; if not, write to the 13# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 14# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the 15# source code or documentation are not subject to the GNU General Public 16# License and may only be used or replicated with the express permission of 17# Red Hat, Inc. 18# 19 20from __future__ import absolute_import 21from __future__ import unicode_literals 22 23import operator 24 25import libdnf.transaction 26 27import dnf.comps 28import dnf.util 29 30import tests.support 31from tests.support import mock 32 33 34class EmptyPersistorTest(tests.support.ResultTestCase): 35 """Test group operations with empty persistor.""" 36 37 REPOS = ['main'] 38 COMPS = True 39 40 @mock.patch('locale.getlocale', return_value=('cs_CZ', 'UTF-8')) 41 def test_group_install_locale(self, _unused): 42 grp = self.comps.group_by_pattern('Kritick\xe1 cesta (Z\xe1klad)') 43 cnt = self.base.group_install(grp.id, ('mandatory',)) 44 self.assertEqual(cnt, 2) 45 46 def test_finalize_comps_trans(self): 47 trans = dnf.comps.TransactionBunch() 48 trans.install = ('trampoline',) 49 self.assertGreater(self.base._add_comps_trans(trans), 0) 50 self.base._finalize_comps_trans() 51 self.assertIn('trampoline', self.base._goal.group_members) 52 (installed, removed) = self.installed_removed(self.base) 53 self.assertCountEqual(map(str, installed), ('trampoline-2.1-1.noarch',)) 54 self.assertEmpty(removed) 55 56 57class PresetPersistorTest(tests.support.ResultTestCase): 58 """Test group operations with some data in the persistor.""" 59 60 REPOS = ['main'] 61 COMPS = True 62 COMPS_SEED_HISTORY = True 63 64 def _install_test_env(self): 65 """Env installation itself does not handle packages. We need to handle 66 them manually for proper functionality of env remove""" 67 68 env_id = 'sugar-desktop-environment' 69 comps_env = self.comps._environment_by_id(env_id) 70 self.base.environment_install(comps_env.id, ('mandatory',)) 71 self._swdb_commit() 72 73 swdb_env = self.history.env.get(comps_env.id) 74 self.assertIsNotNone(swdb_env) 75 76 for comps_group in comps_env.mandatory_groups: 77 swdb_group = self.history.group.get(comps_group.id) 78 self.assertIsNotNone(swdb_group) 79 80 tsis = [] 81 seen_pkgs = set() 82 for swdb_env_group in swdb_env.getGroups(): 83 swdb_group = self.history.group.get(swdb_env_group.getGroupId()) 84 if not swdb_group: 85 continue 86 for swdb_pkg in swdb_group.getPackages(): 87 swdb_pkg.setInstalled(True) 88 pkgs = self.base.sack.query().filter(name=swdb_pkg.getName(), arch="x86_64").run() 89 if not pkgs: 90 continue 91 pkg = pkgs[0] 92 if pkg in seen_pkgs: 93 # prevent RPMs from being twice in a transaction and triggering unique constraint error 94 continue 95 seen_pkgs.add(pkg) 96 pkg._force_swdb_repoid = "main" 97 self.history.rpm.add_install(pkg, reason=libdnf.transaction.TransactionItemReason_GROUP) 98# tsi = dnf.transaction.TransactionItem( 99# dnf.transaction.INSTALL, 100# installed=pkg, 101# reason=libdnf.transaction.TransactionItemReason_GROUP 102# ) 103# tsis.append(tsi) 104 105 self._swdb_commit(tsis) 106 107 def _install_test_group(self): 108 """Group installation itself does not handle packages. We need to 109 handle them manually for proper functionality of group remove""" 110 group_id = 'somerset' 111 self.base.group_install(group_id, ('mandatory',)) 112 swdb_group = self.history.group._installed[group_id] 113 tsis = [] 114 for swdb_pkg in swdb_group.getPackages(): 115 swdb_pkg.setInstalled(True) 116 pkgs = self.base.sack.query().filter(name=swdb_pkg.getName(), arch="x86_64").run() 117 if not pkgs: 118 continue 119 pkg = pkgs[0] 120 pkg._force_swdb_repoid = "main" 121 self.history.rpm.add_install(pkg, reason=libdnf.transaction.TransactionItemReason_GROUP) 122# tsi = dnf.transaction.TransactionItem( 123# dnf.transaction.INSTALL, 124# installed=pkg, 125# reason=libdnf.transaction.TransactionItemReason_GROUP 126# ) 127# tsis.append(tsi) 128 129 self._swdb_commit(tsis) 130 self.base.reset(goal=True) 131 132 def test_env_group_remove(self): 133 self._install_test_env() 134 env_id = 'sugar-desktop-environment' 135 pkg_count = self.base.env_group_remove([env_id]) 136 self._swdb_commit() 137 self.assertEqual(3, pkg_count) 138 with tests.support.mock.patch('logging.Logger.error'): 139 self.assertRaises(dnf.exceptions.Error, 140 self.base.env_group_remove, 141 ['nonexistent']) 142 143 def test_environment_remove(self): 144 self._install_test_env() 145 env_id = 'sugar-desktop-environment' 146 swdb_env = self.history.env.get(env_id) 147 self.assertIsNotNone(swdb_env) 148 self.assertEqual(swdb_env.getEnvironmentId(), 'sugar-desktop-environment') 149 150 removed_pkg_count = self.base.environment_remove(env_id) 151 self.assertGreater(removed_pkg_count, 0) 152 self._swdb_commit() 153 154 swdb_env = self.history.env.get(env_id) 155 self.assertIsNone(swdb_env) 156 157 peppers = self.history.group.get('Peppers') 158 self.assertIsNone(peppers) 159 160 somerset = self.history.group.get('somerset') 161 self.assertIsNone(somerset) 162 163 def test_env_upgrade(self): 164 self._install_test_env() 165 cnt = self.base.environment_upgrade("sugar-desktop-environment") 166 self.assertEqual(5, cnt) 167 168 peppers = self.history.group.get('Peppers') 169 self.assertIsNotNone(peppers) 170 171 somerset = self.history.group.get('somerset') 172 self.assertIsNotNone(somerset) 173 174 def test_group_install(self): 175 comps_group = self.base.comps.group_by_pattern('Base') 176 pkg_count = self.base.group_install(comps_group.id, ('mandatory',)) 177 self.assertEqual(pkg_count, 2) 178 self._swdb_commit() 179 180 installed, removed = self.installed_removed(self.base) 181 self.assertEmpty(installed) 182 self.assertEmpty(removed) 183 swdb_group = self.history.group.get(comps_group.id) 184 self.assertIsNotNone(swdb_group) 185 186 def test_group_remove(self): 187 self._install_test_group() 188 group_id = 'somerset' 189 190 pkgs_removed = self.base.group_remove(group_id) 191 self.assertGreater(pkgs_removed, 0) 192 193 self._swdb_begin() 194 installed, removed = self.installed_removed(self.base) 195 self.assertEmpty(installed) 196 self.assertCountEqual([pkg.name for pkg in removed], ('pepper',)) 197 self._swdb_end() 198 199 200class ProblemGroupTest(tests.support.ResultTestCase): 201 """Test some cases involving problems in groups: packages that 202 don't exist, and packages that exist but cannot be installed. The 203 "broken" group lists three packages. "meaning-of-life", explicitly 204 'default', does not exist. "lotus", implicitly 'mandatory' (no 205 explicit type), exists and is installable. "brokendeps", 206 explicitly 'optional', exists but has broken dependencies. See 207 https://bugzilla.redhat.com/show_bug.cgi?id=1292892, 208 https://bugzilla.redhat.com/show_bug.cgi?id=1337731, 209 https://bugzilla.redhat.com/show_bug.cgi?id=1427365, and 210 https://bugzilla.redhat.com/show_bug.cgi?id=1461539 for some of 211 the background on this. 212 """ 213 214 REPOS = ['main', 'broken_group'] 215 COMPS = True 216 COMPS_SEED_PERSISTOR = True 217 218 def test_group_install_broken_mandatory(self): 219 """Here we will test installing the group with only mandatory 220 packages. We expect this to succeed, leaving out the 221 non-existent 'meaning-of-life': it should also log a warning, 222 but we don't test that. 223 """ 224 comps_group = self.base.comps.group_by_pattern('Broken Group') 225 swdb_group = self.history.group.get(comps_group.id) 226 self.assertIsNone(swdb_group) 227 228 cnt = self.base.group_install(comps_group.id, ('mandatory',)) 229 self._swdb_commit() 230 self.base.resolve() 231 # this counts packages *listed* in the group, so 2 232 self.assertEqual(cnt, 2) 233 234 inst, removed = self.installed_removed(self.base) 235 # the above should work, but only 'lotus' actually installed 236 self.assertLength(inst, 1) 237 self.assertEmpty(removed) 238 239 def test_group_install_broken_default(self): 240 """Here we will test installing the group with only mandatory 241 and default packages. Again we expect this to succeed: the new 242 factor is an entry pulling in librita if no-such-package is 243 also included or installed. We expect this not to actually 244 pull in librita (as no-such-package obviously *isn't* there), 245 but also not to cause a fatal error. 246 """ 247 comps_group = self.base.comps.group_by_pattern('Broken Group') 248 swdb_group = self.history.group.get(comps_group.id) 249 self.assertIsNone(swdb_group) 250 251 cnt = self.base.group_install(comps_group.id, ('mandatory', 'default')) 252 self._swdb_commit() 253 self.base.resolve() 254 # this counts packages *listed* in the group, so 3 255 self.assertEqual(cnt, 3) 256 257 inst, removed = self.installed_removed(self.base) 258 # the above should work, but only 'lotus' actually installed 259 self.assertLength(inst, 1) 260 self.assertEmpty(removed) 261 262 def test_group_install_broken_optional(self): 263 """Here we test installing the group with optional packages 264 included. We expect this to fail, as a package that exists but 265 has broken dependencies is now included. 266 """ 267 comps_group = self.base.comps.group_by_pattern('Broken Group') 268 swdb_group = self.history.group.get(comps_group.id) 269 self.assertIsNone(swdb_group) 270 271 cnt = self.base.group_install(comps_group.id, ('mandatory', 'default', 'optional')) 272 self.assertEqual(cnt, 4) 273 274 self._swdb_commit() 275 # this should fail, as optional 'brokendeps' is now pulled in 276 self.assertRaises(dnf.exceptions.DepsolveError, self.base.resolve) 277 278 def test_group_install_broken_optional_nonstrict(self): 279 """Here we test installing the group with optional packages 280 included, but with strict=False. We expect this to succeed, 281 skipping the package with broken dependencies. 282 """ 283 comps_group = self.base.comps.group_by_pattern('Broken Group') 284 swdb_group = self.history.group.get(comps_group.id) 285 self.assertIsNone(swdb_group) 286 287 cnt = self.base.group_install(comps_group.id, ('mandatory', 'default', 'optional'), 288 strict=False) 289 self._swdb_commit() 290 self.base.resolve() 291 self.assertEqual(cnt, 4) 292 293 inst, removed = self.installed_removed(self.base) 294 # the above should work, but only 'lotus' actually installed 295 self.assertLength(inst, 1) 296 self.assertEmpty(removed) 297 298 def test_group_install_missing_name(self): 299 comps_group = self.base.comps.group_by_pattern('missing-name-group') 300 301 cnt = self.base.group_install(comps_group.id, ('mandatory', 'default', 'optional'), 302 strict=False) 303 self._swdb_commit() 304 self.base.resolve() 305 self.assertEqual(cnt, 1) 306 307 308class EnvironmentInstallTest(tests.support.ResultTestCase): 309 """Set up a test where sugar is considered not installed.""" 310 311 REPOS = ['main'] 312 COMPS = True 313 COMPS_SEED_HISTORY = True 314 315 def test_environment_install(self): 316 # actually commit the pre-mocked comps, as otherwise 317 # 'sugar-desktop-environment' is already present in the open 318 # transaction and it wins over the one installed here 319 self._swdb_commit() 320 321 env_id = 'sugar-desktop-environment' 322 comps_env = self.comps.environment_by_pattern(env_id) 323 self.base.environment_install(comps_env.id, ('mandatory',)) 324 self._swdb_commit() 325 326 installed, _ = self.installed_removed(self.base) 327 self.assertCountEqual(map(operator.attrgetter('name'), installed), 328 ('trampoline', 'lotus')) 329 330 swdb_env = self.history.env.get(env_id) 331 self.assertCountEqual([i.getGroupId() for i in swdb_env.getGroups()], ('somerset', 'Peppers', 'base')) 332 333 peppers = self.history.group.get('Peppers') 334 self.assertIsNotNone(peppers) 335 336 somerset = self.history.group.get('somerset') 337 self.assertIsNotNone(somerset) 338 339 base = self.history.group.get('base') 340 self.assertIsNone(base) 341