5
from smart.control import Control
6
from smart.cache import Provides
10
from landscape.package.facade import (
11
SmartFacade, TransactionError, DependencyError, SmartError)
13
from landscape.tests.helpers import LandscapeTest
14
from landscape.package.tests.helpers import (
15
SmartFacadeHelper, HASH1, HASH2, HASH3, PKGNAME1)
18
class SmartFacadeTest(LandscapeTest):
20
helpers = [SmartFacadeHelper]
22
def test_get_packages(self):
23
self.facade.reload_channels()
24
pkgs = self.facade.get_packages()
25
self.assertEquals(sorted(pkg.name for pkg in pkgs),
26
["name1", "name2", "name3"])
28
def test_get_packages_wont_return_non_debian_packages(self):
29
self.facade.reload_channels()
30
ctrl_mock = self.mocker.patch(Control)
31
class StubPackage(object): pass
32
cache_mock = ctrl_mock.getCache()
33
cache_mock.getPackages()
34
self.mocker.result([StubPackage(), StubPackage()])
36
self.assertEquals(self.facade.get_packages(), [])
38
def test_get_packages_by_name(self):
39
self.facade.reload_channels()
40
pkgs = self.facade.get_packages_by_name("name1")
41
self.assertEquals([pkg.name for pkg in pkgs], ["name1"])
42
pkgs = self.facade.get_packages_by_name("name2")
43
self.assertEquals([pkg.name for pkg in pkgs], ["name2"])
45
def test_get_packages_by_name_wont_return_non_debian_packages(self):
46
self.facade.reload_channels()
47
ctrl_mock = self.mocker.patch(Control)
48
class StubPackage(object): pass
49
cache_mock = ctrl_mock.getCache()
50
cache_mock.getPackages("name")
51
self.mocker.result([StubPackage(), StubPackage()])
53
self.assertEquals(self.facade.get_packages_by_name("name"), [])
55
def test_get_package_skeleton(self):
56
self.facade.reload_channels()
57
pkg1 = self.facade.get_packages_by_name("name1")[0]
58
pkg2 = self.facade.get_packages_by_name("name2")[0]
59
skeleton1 = self.facade.get_package_skeleton(pkg1)
60
skeleton2 = self.facade.get_package_skeleton(pkg2)
61
self.assertEquals(skeleton1.get_hash(), HASH1)
62
self.assertEquals(skeleton2.get_hash(), HASH2)
64
def test_build_skeleton_with_info(self):
65
self.facade.reload_channels()
66
pkg = self.facade.get_packages_by_name("name1")[0]
67
skeleton = self.facade.get_package_skeleton(pkg, True)
68
self.assertEquals(skeleton.section, "Group1")
69
self.assertEquals(skeleton.summary, "Summary1")
70
self.assertEquals(skeleton.description, "Description1")
71
self.assertEquals(skeleton.size, 1038)
72
self.assertEquals(skeleton.installed_size, 28672)
74
def test_get_package_hash(self):
75
self.facade.reload_channels()
76
pkg = self.facade.get_packages_by_name("name1")[0]
77
self.assertEquals(self.facade.get_package_hash(pkg), HASH1)
78
pkg = self.facade.get_packages_by_name("name2")[0]
79
self.assertEquals(self.facade.get_package_hash(pkg), HASH2)
81
def test_get_package_by_hash(self):
82
self.facade.reload_channels()
83
pkg = self.facade.get_package_by_hash(HASH1)
84
self.assertEquals(pkg.name, "name1")
85
pkg = self.facade.get_package_by_hash(HASH2)
86
self.assertEquals(pkg.name, "name2")
87
pkg = self.facade.get_package_by_hash("none")
88
self.assertEquals(pkg, None)
90
def test_reload_channels_clears_hash_cache(self):
92
self.facade.reload_channels()
95
# Hold a reference to packages.
96
pkg1 = self.facade.get_packages_by_name("name1")[0]
97
pkg2 = self.facade.get_packages_by_name("name2")[0]
98
pkg3 = self.facade.get_packages_by_name("name3")[0]
99
self.assertTrue(pkg1 and pkg2)
101
# Remove the package from the repository.
102
os.unlink(os.path.join(self.repository_dir, PKGNAME1))
104
# Forcibly change the mtime of our repository, so that Smart
105
# will consider it as changed (if the change is inside the
106
# same second the directory's mtime will be the same)
107
mtime = int(time.time()+1)
108
os.utime(self.repository_dir, (mtime, mtime))
111
self.facade.reload_channels()
113
# Only packages with name2 and name3 should be loaded, and they're
114
# not the same objects anymore.
116
sorted([pkg.name for pkg in self.facade.get_packages()]),
118
self.assertNotEquals(set(self.facade.get_packages()),
121
# The hash cache shouldn't include either of the old packages.
122
self.assertEquals(self.facade.get_package_hash(pkg1), None)
123
self.assertEquals(self.facade.get_package_hash(pkg2), None)
124
self.assertEquals(self.facade.get_package_hash(pkg3), None)
126
# Also, the hash for package1 shouldn't be present at all.
127
self.assertEquals(self.facade.get_package_by_hash(HASH1), None)
129
# While HASH2 and HASH3 should point to the new packages.
130
new_pkgs = self.facade.get_packages()
131
self.assertTrue(self.facade.get_package_by_hash(HASH2)
133
self.assertTrue(self.facade.get_package_by_hash(HASH3)
136
# Which are not the old packages.
137
self.assertFalse(pkg2 in new_pkgs)
138
self.assertFalse(pkg3 in new_pkgs)
140
def test_perform_changes_with_nothing_to_do(self):
141
"""perform_changes() should return None when there's nothing to do.
143
self.facade.reload_channels()
144
self.assertEquals(self.facade.perform_changes(), None)
146
def test_reset_marks(self):
147
"""perform_changes() should return None when there's nothing to do.
149
self.facade.reload_channels()
150
pkg = self.facade.get_packages_by_name("name1")[0]
151
self.facade.mark_install(pkg)
152
self.facade.reset_marks()
153
self.assertEquals(self.facade.perform_changes(), None)
155
def test_mark_install_transaction_error(self):
157
Mark package 'name1' for installation, and try to perform changes.
158
It should fail because 'name1' depends on 'requirename1'.
160
self.facade.reload_channels()
162
pkg = self.facade.get_packages_by_name("name1")[0]
163
self.facade.mark_install(pkg)
165
self.facade.perform_changes()
166
except TransactionError, exception:
170
self.assertTrue(exception, "TransactionError not raised")
171
self.assertIn("requirename", exception.args[0])
173
def test_mark_install_dependency_error(self):
175
Now we artificially inject the needed dependencies of 'name1'
176
in 'name2', but we don't mark 'name2' for installation, and
177
that should make perform_changes() fail with a dependency
178
error on the needed package.
180
self.facade.reload_channels()
182
provide1 = Provides("prerequirename1", "prerequireversion1")
183
provide2 = Provides("requirename1", "requireversion1")
184
pkg2 = self.facade.get_packages_by_name("name2")[0]
185
pkg2.provides += (provide1, provide2)
187
# We have to satisfy *both* packages.
188
provide1 = Provides("prerequirename2", "prerequireversion2")
189
provide2 = Provides("requirename2", "requireversion2")
190
pkg1 = self.facade.get_packages_by_name("name1")[0]
191
pkg1.provides += (provide1, provide2)
193
# Ask Smart to reprocess relationships.
194
self.facade.reload_cache()
196
self.assertEquals(pkg1.requires[0].providedby[0].packages[0], pkg2)
197
self.assertEquals(pkg1.requires[1].providedby[0].packages[0], pkg2)
199
self.facade.mark_install(pkg1)
201
self.facade.perform_changes()
202
except DependencyError, exception:
206
self.assertTrue(exception, "DependencyError not raised")
207
self.assertEquals(exception.packages, [pkg2])
209
def test_mark_remove_dependency_error(self):
211
Besides making 'name1' satisfy 'name2' and the contrary. We'll
212
mark both packages installed, so that we can get an error on
215
self.facade.reload_channels()
217
provide1 = Provides("prerequirename1", "prerequireversion1")
218
provide2 = Provides("requirename1", "requireversion1")
219
pkg2 = self.facade.get_packages_by_name("name2")[0]
220
pkg2.provides += (provide1, provide2)
222
# We have to satisfy *both* packages.
223
provide1 = Provides("prerequirename2", "prerequireversion2")
224
provide2 = Provides("requirename2", "requireversion2")
225
pkg1 = self.facade.get_packages_by_name("name1")[0]
226
pkg1.provides += (provide1, provide2)
228
# Ask Smart to reprocess relationships.
229
self.facade.reload_cache()
231
pkg1.installed = True
232
pkg2.installed = True
234
self.assertEquals(pkg1.requires[0].providedby[0].packages[0], pkg2)
235
self.assertEquals(pkg1.requires[1].providedby[0].packages[0], pkg2)
237
self.facade.mark_remove(pkg2)
239
output = self.facade.perform_changes()
240
except DependencyError, exception:
244
self.assertTrue(exception, "DependencyError not raised. Output: %s"
246
self.assertEquals(exception.packages, [pkg1])
248
def test_mark_upgrade_dependency_error(self):
249
"""Artificially make pkg2 upgrade pkg1, and mark pkg1 for upgrade."""
251
# The backend only works after initialized.
252
from smart.backends.deb.base import DebUpgrades, DebConflicts
254
self.facade.reload_channels()
256
pkg1 = self.facade.get_packages_by_name("name1")[0]
257
pkg2 = self.facade.get_packages_by_name("name2")[0]
259
# Artificially make pkg2 be self-satisfied, and make it upgrade and
260
# conflict with pkg1.
262
pkg2.upgrades = [DebUpgrades("name1", "=", "version1-release1")]
263
pkg2.conflicts = [DebConflicts("name1", "=", "version1-release1")]
265
# pkg1 will also be self-satisfied.
268
# Ask Smart to reprocess relationships.
269
self.facade.reload_cache()
271
# Mark the pkg1 as installed. Must be done after reloading
272
# the cache as reloading will reset it to the loader installed
274
pkg1.installed = True
276
# Check that the linkage worked.
277
self.assertEquals(pkg2.upgrades[0].providedby[0].packages[0], pkg1)
279
# Perform the upgrade test.
280
self.facade.mark_upgrade(pkg1)
282
self.facade.perform_changes()
283
except DependencyError, exception:
287
self.assertTrue(exception, "DependencyError not raised")
289
# Both packages should be included in the dependency error. One
290
# must be removed, and the other installed.
291
self.assertEquals(set(exception.packages), set([pkg1, pkg2]))
293
def test_perform_changes_with_logged_error(self):
294
self.log_helper.ignore_errors(".*dpkg")
296
self.facade.reload_channels()
298
pkg = self.facade.get_packages_by_name("name1")[0]
301
self.facade.reload_cache()
303
self.facade.mark_install(pkg)
306
output = self.facade.perform_changes()
307
except SmartError, exception:
312
self.assertTrue(exception,
313
"SmartError not raised. Output: %s" % repr(output))
314
# We can't check the whole message because the dpkg error can be
315
# localized. We can't use str(exception) either because it can contain
317
self.assertIn("ERROR", exception.args[0])
318
self.assertIn("(2)", exception.args[0])
319
self.assertIn("\n[unpack] name1_version1-release1\ndpkg: ",
322
def test_perform_changes_is_non_interactive(self):
323
from smart.backends.deb.pm import DebPackageManager
325
self.facade.reload_channels()
327
pkg = self.facade.get_packages_by_name("name1")[0]
330
self.facade.reload_cache()
332
self.facade.mark_install(pkg)
335
def check_environ(self, argv, output):
336
environ.append(os.environ.get("DEBIAN_FRONTEND"))
337
environ.append(os.environ.get("APT_LISTCHANGES_FRONTEND"))
340
DebPackageManager.dpkg, olddpkg = check_environ, DebPackageManager.dpkg
343
self.facade.perform_changes()
345
DebPackageManager.dpkg = olddpkg
347
self.assertEquals(environ, ["noninteractive", "none",
348
"noninteractive", "none"])
350
def test_deinit_cleans_the_state(self):
351
self.facade.reload_channels()
352
self.assertTrue(self.facade.get_package_by_hash(HASH1))
354
self.assertFalse(self.facade.get_package_by_hash(HASH1))
356
def test_deinit_deinits_smart(self):
357
self.facade.reload_channels()
358
self.assertTrue(smart.iface.object)
360
self.assertFalse(smart.iface.object)
362
def test_deinit_when_smart_wasnt_initialized(self):
363
self.assertFalse(smart.iface.object)
364
# Nothing bad should happen.
367
def test_reload_channels_wont_consider_non_debian_packages(self):
368
class StubPackage(object): pass
371
ctrl_mock = self.mocker.patch(Control)
372
cache_mock = ctrl_mock.getCache()
373
cache_mock.getPackages()
374
self.mocker.result([pkg])
377
self.facade.reload_channels()
378
self.assertEquals(self.facade.get_package_hash(pkg), None)