Merge lp:~ahasenack/landscape-client/landscape-client-12.05-0ubuntu1-quantal into lp:ubuntu/quantal/landscape-client

Proposed by Andreas Hasenack
Status: Merged
Merged at revision: 46
Proposed branch: lp:~ahasenack/landscape-client/landscape-client-12.05-0ubuntu1-quantal
Merge into: lp:ubuntu/quantal/landscape-client
Diff against target: 5384 lines (+762/-3332)
39 files modified
debian/changelog (+41/-0)
debian/control (+6/-4)
debian/landscape-client.templates (+1/-1)
debian/landscape-common.templates (+1/-1)
debian/po/templates.pot (+28/-6)
debian/rules (+9/-6)
debian/source.lintian-overrides (+16/-0)
debian/source/format (+1/-0)
debian/watch (+2/-0)
landscape/__init__.py (+6/-2)
landscape/constants.py (+3/-2)
landscape/deployment.py (+1/-1)
landscape/manager/aptsources.py (+2/-2)
landscape/manager/tests/test_aptsources.py (+1/-1)
landscape/monitor/packagemonitor.py (+1/-1)
landscape/package/changer.py (+37/-119)
landscape/package/facade.py (+159/-494)
landscape/package/interface.py (+0/-84)
landscape/package/releaseupgrader.py (+2/-2)
landscape/package/reporter.py (+13/-110)
landscape/package/skeleton.py (+0/-48)
landscape/package/store.py (+0/-37)
landscape/package/taskhandler.py (+4/-8)
landscape/package/tests/helpers.py (+0/-39)
landscape/package/tests/test_changer.py (+202/-521)
landscape/package/tests/test_facade.py (+88/-735)
landscape/package/tests/test_interface.py (+0/-34)
landscape/package/tests/test_releaseupgrader.py (+2/-2)
landscape/package/tests/test_reporter.py (+94/-695)
landscape/package/tests/test_skeleton.py (+28/-87)
landscape/package/tests/test_store.py (+3/-103)
landscape/package/tests/test_taskhandler.py (+4/-48)
landscape/ui/view/tests/test_configuration.py (+3/-0)
landscape/ui/view/ui/landscape-client-settings.glade (+1/-1)
landscape/watchdog.py (+1/-1)
po/fr.po (+1/-1)
po/landscape-client.pot (+1/-1)
smart-update/Makefile (+0/-6)
smart-update/smart-update.c (+0/-129)
To merge this branch: bzr merge lp:~ahasenack/landscape-client/landscape-client-12.05-0ubuntu1-quantal
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+108569@code.launchpad.net

Description of the change

This updates landscape-client in quantal to upstream version 12.05.

Upstream now removes debian/* from the tarball, so this branch also addresses that. For details, please see the debian/changelog new entries.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2012-03-28 10:59:58 +0000
3+++ debian/changelog 2012-06-04 14:08:28 +0000
4@@ -1,3 +1,44 @@
5+landscape-client (12.05-0ubuntu1) quantal; urgency=low
6+
7+ * New upstream release 12.05 (r561 in trunk) (LP: #1004678).
8+ * Make all subpackages that depend on each other require the exact same
9+ version, instead of >= $version.
10+ * Added python-gi to client depends starting natty.
11+ * Make change-packages also handle package holds (LP: #972489).
12+ * Fix typo in glade file (LP: #983096).
13+ * Tidy up apt facade (LP: #985493).
14+ * Remove SmartFacade and its tests, no longer used (LP: #996269).
15+ * Remove check for apt version, since we won't release this for
16+ Hardy where that check matters (LP: #996837).
17+ * Remove methods that were smart specific. We no longer use smart
18+ (LP: #996841).
19+ * Remove smart-update helper binary. We no longer use smart
20+ (LP: #997408).
21+ * Remove test-mixins that were useful only during the apt-to-smart
22+ code migration. Now with smart gone, they are no longer necessary
23+ (LP: #997760).
24+ * Build the packages from precise onward, not just precise.
25+ * Assorted packaging fixes:
26+ - Switched to format 3.0 (quilt).
27+ - Added source lintian overrides, with comments.
28+ - Updated debian/rules:
29+ - Added build-arch and build-indep dummy target.
30+ - Build the GUI packages from precise onwards, and not just on precise.
31+ - Re-enable dh_lintian.
32+ - Strip the binaries (dh_strip), and also call dh_shlibdeps for the
33+ automatic shlibs dependency.
34+ - Added python-gi from natty onwards.
35+ - Used __Choices instead of _Choices in landscape-common.templates, it's
36+ better for translators.
37+ - Updated standard version to 3.8.2, the version from Lucid (oldest one
38+ we support)
39+ - Added shlibs depends.
40+ - Dropped deprecated ${Source-Version} and replaced it with
41+ ${binary:Version}
42+ - Require exact version of the sibling package instead of >=.
43+
44+ -- Andreas Hasenack <andreas@canonical.com> Fri, 01 Jun 2012 17:48:43 -0300
45+
46 landscape-client (12.04.3-0ubuntu1) precise; urgency=low
47
48 * Warn on unicode entry into settings UI (LP: #956612).
49
50=== modified file 'debian/control'
51--- debian/control 2012-03-22 10:10:39 +0000
52+++ debian/control 2012-06-04 14:08:28 +0000
53@@ -4,12 +4,13 @@
54 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
55 XSBC-Original-Maintainer: Landscape Team <landscape-team@canonical.com>
56 Build-Depends: debhelper (>= 5), po-debconf, python-dev, lsb-release, gawk, python-twisted-core, python-distutils-extra
57-Standards-Version: 3.8.0
58+Standards-Version: 3.8.2
59 XS-Python-Version: >= 2.4, << 2.8
60
61 Package: landscape-common
62 Architecture: any
63 Depends: ${python:Depends}, ${misc:Depends}, ${extra:Depends},
64+ ${shlibs:Depends},
65 python-gnupginterface,
66 python-twisted-core,
67 python-apt,
68@@ -33,9 +34,10 @@
69 Package: landscape-client
70 Architecture: any
71 Depends: ${python:Depends}, ${misc:Depends}, ${extra:Depends},
72+ ${shlibs:Depends},
73 python-twisted-web,
74 python-twisted-names,
75- landscape-common (>= ${Source-Version})
76+ landscape-common (= ${binary:Version})
77 Suggests: ${extra:Suggests}
78 Description: The Landscape administration system client
79 Landscape is a web-based tool for managing Ubuntu systems. This
80@@ -48,8 +50,8 @@
81 Package: landscape-client-ui
82 Architecture: any
83 Depends: ${python:Depends}, ${misc:Depends},
84- landscape-client (>= ${Source-Version}),
85- landscape-client-ui-install (>= ${Source-Version}),
86+ landscape-client (= ${binary:Version}),
87+ landscape-client-ui-install (= ${binary:Version}),
88 python-gi,
89 python-dbus,
90 policykit-1,
91
92=== modified file 'debian/landscape-client.templates'
93--- debian/landscape-client.templates 2012-03-19 09:33:34 +0000
94+++ debian/landscape-client.templates 2012-06-04 14:08:28 +0000
95@@ -64,7 +64,7 @@
96 Template: landscape-client/tags
97 Type: string
98 Default:
99-_Description: Initial tags for first registration
100+_Description: Initial tags for first registration:
101 Comma separated list of tags which will be assigned to this computer on its
102 first registration. Once the machine is registered, these tags can only be
103 changed using the Landscape server.
104
105=== modified file 'debian/landscape-common.templates'
106--- debian/landscape-common.templates 2012-03-19 09:33:34 +0000
107+++ debian/landscape-common.templates 2012-06-04 14:08:28 +0000
108@@ -6,7 +6,7 @@
109 # try to keep below ~71 characters.
110 # DO NOT USE commas (,) in Choices translations otherwise
111 # this will break the choices shown to users
112-_Choices: Do not display sysinfo on login, Cache sysinfo in /etc/motd, Run sysinfo on every login
113+__Choices: Do not display sysinfo on login, Cache sysinfo in /etc/motd, Run sysinfo on every login
114 Default: Cache sysinfo in /etc/motd
115 _Description: landscape-sysinfo configuration:
116 Landscape includes a tool and a set of modules that can display
117
118=== modified file 'debian/po/templates.pot'
119--- debian/po/templates.pot 2012-03-19 09:33:34 +0000
120+++ debian/po/templates.pot 2012-06-04 14:08:28 +0000
121@@ -6,9 +6,9 @@
122 #, fuzzy
123 msgid ""
124 msgstr ""
125-"Project-Id-Version: PACKAGE VERSION\n"
126+"Project-Id-Version: landscape-client\n"
127 "Report-Msgid-Bugs-To: landscape-client@packages.debian.org\n"
128-"POT-Creation-Date: 2012-03-07 17:07+0100\n"
129+"POT-Creation-Date: 2012-06-01 18:35-0300\n"
130 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
131 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
132 "Language-Team: LANGUAGE <LL@li.org>\n"
133@@ -152,7 +152,7 @@
134 #. Type: string
135 #. Description
136 #: ../landscape-client.templates:11001
137-msgid "Initial tags for first registration"
138+msgid "Initial tags for first registration:"
139 msgstr ""
140
141 #. Type: string
142@@ -187,9 +187,31 @@
143 #. DO NOT USE commas (,) in Choices translations otherwise
144 #. this will break the choices shown to users
145 #: ../landscape-common.templates:1001
146-msgid ""
147-"Do not display sysinfo on login, Cache sysinfo in /etc/motd, Run sysinfo on "
148-"every login"
149+msgid "Do not display sysinfo on login"
150+msgstr ""
151+
152+#. Type: select
153+#. Choices
154+#. Translators beware! the following three strings form a single
155+#. Choices menu. - Every one of these strings has to fit in a standard
156+#. 80 characters console, as the fancy screen setup takes up some space
157+#. try to keep below ~71 characters.
158+#. DO NOT USE commas (,) in Choices translations otherwise
159+#. this will break the choices shown to users
160+#: ../landscape-common.templates:1001
161+msgid "Cache sysinfo in /etc/motd"
162+msgstr ""
163+
164+#. Type: select
165+#. Choices
166+#. Translators beware! the following three strings form a single
167+#. Choices menu. - Every one of these strings has to fit in a standard
168+#. 80 characters console, as the fancy screen setup takes up some space
169+#. try to keep below ~71 characters.
170+#. DO NOT USE commas (,) in Choices translations otherwise
171+#. this will break the choices shown to users
172+#: ../landscape-common.templates:1001
173+msgid "Run sysinfo on every login"
174 msgstr ""
175
176 #. Type: select
177
178=== modified file 'debian/rules'
179--- debian/rules 2012-03-28 10:59:58 +0000
180+++ debian/rules 2012-06-04 14:08:28 +0000
181@@ -9,7 +9,7 @@
182 endif
183
184 dh_extra_flags = -plandscape-common -plandscape-client
185-ifneq (,$(filter $(dist_release),precise))
186+ifeq (,$(filter $(dist_release),hardy lucid natty oneiric))
187 # We want landscape-client-ui only from precise onward
188 dh_extra_flags += -plandscape-client-ui -plandscape-client-ui-install
189 endif
190@@ -30,6 +30,10 @@
191 landscape_common_substvars = debian/landscape-common.substvars
192 landscape_client_substvars = debian/landscape-client.substvars
193
194+build-arch: build
195+
196+build-indep: build
197+
198 build: build-stamp
199 build-stamp:
200 dh_testdir
201@@ -69,10 +73,7 @@
202 # do nothing
203 #
204 binary-arch: build install
205- # That's not present in Ubuntu releases we still support, so
206- # we're just installing the lintian overrides file by hand
207- # for now.
208- #dh_lintian
209+ dh_lintian
210 dh_testdir
211 dh_testroot
212 dh_installdocs
213@@ -82,8 +83,10 @@
214 dh_installinit -- start 45 2 3 4 5 . stop 15 0 1 6 .
215 dh_installlogrotate
216 dh_installdebconf
217+ dh_strip
218 dh_compress
219 dh_fixperms
220+ dh_shlibdeps
221
222 ifneq (,$(findstring $(dist_release),hardy))
223 # We depend on bug-fixed versions of python-dbus and pycurl on hardy
224@@ -100,7 +103,7 @@
225 ifeq (,$(filter $(dist_release),hardy lucid))
226 # Starting natty, no more hal or dbus
227 echo "extra:Depends=libpam-modules (>= 1.0.1-9ubuntu3)" >> $(landscape_common_substvars)
228- echo "extra:Depends=python-pycurl, gir1.2-gudev-1.0 (>= 165-0ubuntu2)" >> $(landscape_client_substvars)
229+ echo "extra:Depends=python-pycurl, gir1.2-gudev-1.0 (>= 165-0ubuntu2), python-gi" >> $(landscape_client_substvars)
230 echo "extra:Suggests=python-dbus, hal" >> $(landscape_client_substvars)
231 endif
232
233
234=== added directory 'debian/source'
235=== added file 'debian/source.lintian-overrides'
236--- debian/source.lintian-overrides 1970-01-01 00:00:00 +0000
237+++ debian/source.lintian-overrides 2012-06-04 14:08:28 +0000
238@@ -0,0 +1,16 @@
239+# we use dh_python or dh_python2 depending on the ubuntu release
240+# the package is being built on, this is detected dynamically
241+# in the rules file
242+landscape-client source: dh_python-is-obsolete
243+
244+# the package has to build on lucid, where the standards version
245+# is 3.8.2
246+landscape-client source: ancient-standards-version
247+
248+# it's a bug that should be fixed in quantal
249+landscape-client source: unknown-field-in-dsc original-maintainer
250+
251+# this is only used in a very specific client upgrade from
252+# the dbus to the amp version
253+landscape-client: start-stop-daemon-in-maintainer-script postinst:130
254+
255
256=== added file 'debian/source/format'
257--- debian/source/format 1970-01-01 00:00:00 +0000
258+++ debian/source/format 2012-06-04 14:08:28 +0000
259@@ -0,0 +1,1 @@
260+3.0 (quilt)
261
262=== added file 'debian/watch'
263--- debian/watch 1970-01-01 00:00:00 +0000
264+++ debian/watch 2012-06-04 14:08:28 +0000
265@@ -0,0 +1,2 @@
266+version=3
267+https://launchpad.net/landscape-client/+download https://launchpad.net/landscape-client/[^/]+/[^/]+/\+download/landscape-client-(.*)\.tar\.(?:bz2|gz)
268
269=== modified file 'landscape/__init__.py'
270--- landscape/__init__.py 2012-03-28 10:59:58 +0000
271+++ landscape/__init__.py 2012-06-04 14:08:28 +0000
272@@ -1,7 +1,7 @@
273 import sys
274
275 DEBIAN_REVISION = ""
276-UPSTREAM_VERSION = "12.04.2"
277+UPSTREAM_VERSION = "12.05"
278 VERSION = "%s%s" % (UPSTREAM_VERSION, DEBIAN_REVISION)
279
280 # The "server-api" field of outgoing messages will be set to this value, and
281@@ -32,7 +32,11 @@
282 # * Add "policy" field to "change-packages"
283 # * Add new "change-package-locks" client accepted message type.
284 #
285-CLIENT_API = "3.3"
286+# 3.4:
287+# * Add "hold" field to "change-packages"
288+# * Add "remove-hold" field to "change-packages"
289+
290+CLIENT_API = "3.4"
291
292 from twisted.python import util
293
294
295=== modified file 'landscape/constants.py'
296--- landscape/constants.py 2012-03-21 16:15:49 +0000
297+++ landscape/constants.py 2012-06-04 14:08:28 +0000
298@@ -12,6 +12,7 @@
299 SUCCESS_RESULT = 1
300 ERROR_RESULT = 100
301 DEPENDENCY_ERROR_RESULT = 101
302+CLIENT_VERSION_ERROR_RESULT = 102
303 POLICY_STRICT = 0
304 POLICY_ALLOW_INSTALLS = 1
305 POLICY_ALLOW_ALL_CHANGES = 2
306@@ -25,8 +26,8 @@
307 # package reporter.
308 # 2. We lost some package data, for example by a deb archive becoming
309 # inaccessible for a while. The earliest we can reasonably assume that to be
310-# resolved is in 60 minutes, when the smart cronjob runs again.
311+# resolved is in 60 minutes, when the package reporter runs again.
312
313 # So we'll give the problem one chance to resolve itself, by only waiting for
314-# one run of smart update.
315+# one run of apt-update.
316 UNKNOWN_PACKAGE_DATA_TIMEOUT = 70 * 60
317
318=== modified file 'landscape/deployment.py'
319--- landscape/deployment.py 2012-03-19 09:33:34 +0000
320+++ landscape/deployment.py 2012-06-04 14:08:28 +0000
321@@ -282,7 +282,7 @@
322 - C{quiet} (C{False})
323 - C{log_dir} (C{"/var/log/landscape"})
324 - C{log_level} (C{"info"})
325- - C{url} (C{"http://landcape.canonical.com/message-system"})
326+ - C{url} (C{"http://landscape.canonical.com/message-system"})
327 - C{ping_url} (C{"http://landscape.canonical.com/ping"})
328 - C{ssl_public_key}
329 - C{server_autodiscover} (C{"false"})
330
331=== modified file 'landscape/manager/aptsources.py'
332--- landscape/manager/aptsources.py 2012-03-19 09:33:34 +0000
333+++ landscape/manager/aptsources.py 2012-06-04 14:08:28 +0000
334@@ -156,8 +156,8 @@
335 """Once the repositories are modified, trigger a reporter run."""
336 reporter = find_reporter_command()
337
338- # Force a smart-update run, because the sources.list has changed
339- args = ["--force-smart-update"]
340+ # Force an apt-update run, because the sources.list has changed
341+ args = ["--force-apt-update"]
342
343 if self.registry.config.config is not None:
344 args.append("--config=%s" % self.registry.config.config)
345
346=== modified file 'landscape/manager/tests/test_aptsources.py'
347--- landscape/manager/tests/test_aptsources.py 2012-03-19 09:33:34 +0000
348+++ landscape/manager/tests/test_aptsources.py 2012-06-04 14:08:28 +0000
349@@ -388,7 +388,7 @@
350
351 def _run_process(command, args, env={}, path=None, uid=None, gid=None):
352 self.assertEqual(find_reporter_command(), command)
353- self.assertEqual(["--force-smart-update", "--config=%s" %
354+ self.assertEqual(["--force-apt-update", "--config=%s" %
355 self.manager.config.config], args)
356 deferred.callback(("ok", "", 0))
357 return deferred
358
359=== modified file 'landscape/monitor/packagemonitor.py'
360--- landscape/monitor/packagemonitor.py 2012-03-19 09:33:34 +0000
361+++ landscape/monitor/packagemonitor.py 2012-06-04 14:08:28 +0000
362@@ -58,7 +58,7 @@
363
364 class FakeFacade(object):
365 """
366- A fake facade to workaround the issue that the SmartFacade
367+ A fake facade to workaround the issue that the AptFacade
368 essentially allows only once instance per process.
369 """
370
371
372=== modified file 'landscape/package/changer.py'
373--- landscape/package/changer.py 2012-03-19 09:33:34 +0000
374+++ landscape/package/changer.py 2012-06-04 14:08:28 +0000
375@@ -9,8 +9,8 @@
376 from twisted.internet.defer import maybeDeferred, succeed
377
378 from landscape.constants import (
379- SUCCESS_RESULT, ERROR_RESULT, DEPENDENCY_ERROR_RESULT, POLICY_STRICT,
380- POLICY_ALLOW_INSTALLS, POLICY_ALLOW_ALL_CHANGES,
381+ SUCCESS_RESULT, ERROR_RESULT, DEPENDENCY_ERROR_RESULT,
382+ POLICY_STRICT, POLICY_ALLOW_INSTALLS, POLICY_ALLOW_ALL_CHANGES,
383 UNKNOWN_PACKAGE_DATA_TIMEOUT)
384
385 from landscape.lib.fs import create_file
386@@ -18,7 +18,7 @@
387 from landscape.package.taskhandler import (
388 PackageTaskHandler, PackageTaskHandlerConfiguration, PackageTaskError,
389 run_task_handler)
390-from landscape.manager.manager import FAILED, SUCCEEDED
391+from landscape.manager.manager import FAILED
392
393
394 class UnknownPackageData(Exception):
395@@ -38,7 +38,7 @@
396 """Value object to hold the results of change packages operation.
397
398 @ivar code: The result code of the requested changes.
399- @ivar text: The output from Smart.
400+ @ivar text: The output from Apt.
401 @ivar installs: Possible additional packages that need to be installed
402 in order to fulfill the request.
403 @ivar removals: Possible additional packages that need to be removed
404@@ -80,10 +80,6 @@
405 # Nothing was done
406 return
407
408- # In order to let the reporter run smart-update cleanly,
409- # we have to deinitialize Smart, so that the write lock
410- # gets released
411- self._facade.deinit()
412 if os.getuid() == 0:
413 os.setgid(grp.getgrnam("landscape").gr_gid)
414 os.setuid(pwd.getpwnam("landscape").pw_uid)
415@@ -103,8 +99,6 @@
416 return result.addErrback(self.unknown_package_data_error, task)
417 if message["type"] == "change-package-locks":
418 return self.handle_change_package_locks(message)
419- if message["type"] == "change-package-holds":
420- return self.handle_change_package_holds(message)
421
422 def unknown_package_data_error(self, failure, task):
423 """Handle L{UnknownPackageData} data errors.
424@@ -145,7 +139,7 @@
425 self._facade.clear_channels()
426
427 def init_channels(self, binaries=()):
428- """Initialize the Smart channels as needed.
429+ """Initialize the Apt channels as needed.
430
431 @param binaries: A possibly empty list of 3-tuples of the form
432 (hash, id, deb), holding the hash, the id and the content of
433@@ -168,12 +162,16 @@
434
435 self._facade.ensure_channels_reloaded()
436
437- def mark_packages(self, upgrade=False, install=(), remove=(), reset=True):
438+ def mark_packages(self, upgrade=False, install=(), remove=(),
439+ hold=(), remove_hold=(), reset=True):
440 """Mark packages for upgrade, installation or removal.
441
442 @param upgrade: If C{True} mark all installed packages for upgrade.
443 @param install: A list of package ids to be marked for installation.
444 @param remove: A list of package ids to be marked for removal.
445+ @param hold: A list of package ids to be marked for holding.
446+ @param remove_hold: A list of package ids to be marked to have a hold
447+ removed.
448 @param reset: If C{True} all existing marks will be reset.
449 """
450 if reset:
451@@ -182,16 +180,19 @@
452 if upgrade:
453 self._facade.mark_global_upgrade()
454
455- for ids, mark_func in [(install, self._facade.mark_install),
456- (remove, self._facade.mark_remove)]:
457- for id in ids:
458- hash = self._store.get_id_hash(id)
459+ for mark_function, mark_ids in [
460+ (self._facade.mark_install, install),
461+ (self._facade.mark_remove, remove),
462+ (self._facade.mark_hold, hold),
463+ (self._facade.mark_remove_hold, remove_hold)]:
464+ for mark_id in mark_ids:
465+ hash = self._store.get_id_hash(mark_id)
466 if hash is None:
467- raise UnknownPackageData(id)
468+ raise UnknownPackageData(mark_id)
469 package = self._facade.get_package_by_hash(hash)
470 if package is None:
471 raise UnknownPackageData(hash)
472- mark_func(package)
473+ mark_function(package)
474
475 def change_packages(self, policy):
476 """Perform the requested changes.
477@@ -202,10 +203,9 @@
478 @return: A L{ChangePackagesResult} holding the details about the
479 outcome of the requested changes.
480 """
481- # Delay importing these so that we don't import Smart unless
482+ # Delay importing these so that we don't import Apt unless
483 # we really need to.
484- from landscape.package.facade import (
485- DependencyError, TransactionError, SmartError)
486+ from landscape.package.facade import DependencyError, TransactionError
487
488 result = ChangePackagesResult()
489 count = 0
490@@ -213,7 +213,7 @@
491 count += 1
492 try:
493 result.text = self._facade.perform_changes()
494- except (TransactionError, SmartError), exception:
495+ except TransactionError, exception:
496 result.code = ERROR_RESULT
497 result.text = exception.args[0]
498 except DependencyError, exception:
499@@ -264,10 +264,11 @@
500 """Handle a C{change-packages} message."""
501
502 self.init_channels(message.get("binaries", ()))
503- self.mark_packages(message.get("upgrade-all", False),
504- message.get("install", ()),
505- message.get("remove", ()))
506-
507+ self.mark_packages(upgrade=message.get("upgrade-all", False),
508+ install=message.get("install", ()),
509+ remove=message.get("remove", ()),
510+ hold=message.get("hold", ()),
511+ remove_hold=message.get("remove-hold", ()))
512 result = self.change_packages(message.get("policy", POLICY_STRICT))
513 self._clear_binaries()
514
515@@ -289,99 +290,16 @@
516 def handle_change_package_locks(self, message):
517 """Handle a C{change-package-locks} message.
518
519- Create and delete package locks as requested by the given C{message}.
520- """
521-
522- if not self._facade.supports_package_locks:
523- response = {
524- "type": "operation-result",
525- "operation-id": message.get("operation-id"),
526- "status": FAILED,
527- "result-text": "This client doesn't support package locks.",
528- "result-code": 1}
529- return self._broker.send_message(response, True)
530-
531- for lock in message.get("create", ()):
532- self._facade.set_package_lock(*lock)
533- for lock in message.get("delete", ()):
534- self._facade.remove_package_lock(*lock)
535- self._facade.save_config()
536-
537- response = {"type": "operation-result",
538- "operation-id": message.get("operation-id"),
539- "status": SUCCEEDED,
540- "result-text": "Package locks successfully changed.",
541- "result-code": 0}
542-
543- logging.info("Queuing message with change package locks results to "
544- "exchange urgently.")
545- return self._broker.send_message(response, True)
546-
547- def _send_change_package_holds_response(self, response):
548- """Log that a package holds result is sent and send the response."""
549- logging.info("Queuing message with change package holds results to "
550- "exchange urgently.")
551- return self._broker.send_message(response, True)
552-
553- def handle_change_package_holds(self, message):
554- """Handle a C{change-package-holds} message.
555-
556- Create and delete package holds as requested by the given C{message}.
557- """
558- if not self._facade.supports_package_holds:
559- response = {
560- "type": "operation-result",
561- "operation-id": message.get("operation-id"),
562- "status": FAILED,
563- "result-text": "This client doesn't support package holds.",
564- "result-code": 1}
565- return self._send_change_package_holds_response(response)
566-
567- not_installed = set()
568- holds_to_create = message.get("create", [])
569- versions_to_create = set()
570- for id in holds_to_create:
571- hash = self._store.get_id_hash(id)
572- hold_version = self._facade.get_package_by_hash(hash)
573- if (hold_version
574- and self._facade.is_package_installed(hold_version)):
575- versions_to_create.add((hold_version.package, hold_version))
576- else:
577- not_installed.add(str(id))
578- holds_to_remove = message.get("delete", [])
579- versions_to_remove = set()
580- for id in holds_to_remove:
581- hash = self._store.get_id_hash(id)
582- hold_version = self._facade.get_package_by_hash(hash)
583- if (hold_version
584- and self._facade.is_package_installed(hold_version)):
585- versions_to_remove.add((hold_version.package, hold_version))
586-
587- if not_installed:
588- response = {
589- "type": "operation-result",
590- "operation-id": message.get("operation-id"),
591- "status": FAILED,
592- "result-text": "Package holds not changed, since the" +
593- " following packages are not installed: %s" % (
594- ", ".join(sorted(not_installed))),
595- "result-code": 1}
596- return self._send_change_package_holds_response(response)
597-
598- for package, hold_version in versions_to_create:
599- self._facade.set_package_hold(hold_version)
600- for package, hold_version in versions_to_remove:
601- self._facade.remove_package_hold(hold_version)
602-
603- self._facade.reload_channels()
604-
605- response = {"type": "operation-result",
606- "operation-id": message.get("operation-id"),
607- "status": SUCCEEDED,
608- "result-text": "Package holds successfully changed.",
609- "result-code": 0}
610-
611- return self._send_change_package_holds_response(response)
612+ Package locks aren't supported anymore.
613+ """
614+
615+ response = {
616+ "type": "operation-result",
617+ "operation-id": message.get("operation-id"),
618+ "status": FAILED,
619+ "result-text": "This client doesn't support package locks.",
620+ "result-code": 1}
621+ return self._broker.send_message(response, True)
622
623 @staticmethod
624 def find_command():
625
626=== modified file 'landscape/package/facade.py'
627--- landscape/package/facade.py 2012-03-21 16:15:49 +0000
628+++ landscape/package/facade.py 2012-06-04 14:08:28 +0000
629@@ -5,15 +5,6 @@
630 from cStringIO import StringIO
631 from operator import attrgetter
632
633-has_smart = True
634-try:
635- import smart
636- from smart.transaction import (
637- Transaction, PolicyInstall, PolicyUpgrade, PolicyRemove, Failed)
638- from smart.const import INSTALL, REMOVE, UPGRADE, ALWAYS, NEVER
639-except ImportError:
640- has_smart = False
641-
642 # Importing apt throws a FutureWarning on hardy, that we don't want to
643 # see.
644 import warnings
645@@ -24,19 +15,13 @@
646 import apt_inst
647 import apt_pkg
648
649-has_new_enough_apt = True
650 from aptsources.sourceslist import SourcesList
651-try:
652- from apt.progress.text import AcquireProgress
653- from apt.progress.base import InstallProgress
654-except ImportError:
655- AcquireProgress = object
656- InstallProgress = object
657- has_new_enough_apt = False
658+from apt.progress.text import AcquireProgress
659+from apt.progress.base import InstallProgress
660
661 from landscape.lib.fs import append_file, create_file, read_file
662 from landscape.constants import UBUNTU_PATH
663-from landscape.package.skeleton import build_skeleton, build_skeleton_apt
664+from landscape.package.skeleton import build_skeleton_apt
665
666
667 class TransactionError(Exception):
668@@ -54,10 +39,6 @@
669 ", ".join([str(package) for package in self.packages]))
670
671
672-class SmartError(Exception):
673- """Raised when Smart fails in an undefined way."""
674-
675-
676 class ChannelError(Exception):
677 """Raised when channels fail to load."""
678
679@@ -108,8 +89,6 @@
680 database.
681 """
682
683- supports_package_holds = True
684- supports_package_locks = False
685 _dpkg_status = "/var/lib/dpkg/status"
686
687 def __init__(self, root=None):
688@@ -127,6 +106,8 @@
689 self._version_installs = []
690 self._global_upgrade = False
691 self._version_removals = []
692+ self._version_hold_creations = []
693+ self._version_hold_removals = []
694 self.refetch_package_index = False
695
696 def _ensure_dir_structure(self):
697@@ -150,9 +131,6 @@
698 os.makedirs(full_path)
699 return full_path
700
701- def deinit(self):
702- """This method exists solely to be compatible with C{SmartFacade}."""
703-
704 def get_packages(self):
705 """Get all the packages available in the channels."""
706 return self._hash2pkg.itervalues()
707@@ -167,17 +145,6 @@
708 if (self.is_package_installed(version)
709 and self._is_package_held(version.package))]
710
711- def get_package_locks(self):
712- """Return all set package locks.
713-
714- @return: A C{list} of ternary tuples, contaning the name, relation
715- and version details for each lock currently set on the system.
716-
717- XXX: This method isn't implemented yet. It's here to make the
718- transition to Apt in the package reporter easier.
719- """
720- return []
721-
722 def get_package_holds(self):
723 """Return the name of all the packages that are on hold."""
724 return [version.package.name for version in self.get_locked_packages()]
725@@ -204,7 +171,8 @@
726
727 @param version: The version of the package to unhold.
728 """
729- if not self._is_package_held(version.package):
730+ if (not self.is_package_installed(version) or
731+ not self._is_package_held(version.package)):
732 return
733 self._set_dpkg_selections(version.package.name + " install")
734
735@@ -556,50 +524,125 @@
736 all_info.append(info + or_divider.join(relation_infos))
737 return "\n".join(all_info)
738
739- def perform_changes(self):
740- """Perform the pending package operations."""
741- # Try to enforce non-interactivity
742+ def _set_frontend_noninteractive(self):
743+ """
744+ Set the environment to avoid attempts by apt to interact with a user.
745+ """
746 os.environ["DEBIAN_FRONTEND"] = "noninteractive"
747 os.environ["APT_LISTCHANGES_FRONTEND"] = "none"
748 os.environ["APT_LISTBUGS_FRONTEND"] = "none"
749+
750+ def _default_path_when_missing(self):
751+ """
752+ If no PATH is set in the environment, use the Ubuntu default PATH.
753+
754+ When the client is launched from the landscape-client-settings-ui the
755+ PATH variable is incorrectly set, this method rectifies that.
756+ """
757 # dpkg will fail if no path is set.
758 if "PATH" not in os.environ:
759 os.environ["PATH"] = UBUNTU_PATH
760+
761+ def _setup_dpkg_for_changes(self):
762+ """
763+ Setup environment and apt options for successful package operations.
764+ """
765+ self._set_frontend_noninteractive()
766+ self._default_path_when_missing()
767 apt_pkg.config.clear("DPkg::options")
768 apt_pkg.config.set("DPkg::options::", "--force-confold")
769
770+ def _perform_hold_changes(self):
771+ """
772+ Perform pending hold operations on packages.
773+ """
774+ hold_changes = (len(self._version_hold_creations) > 0 or
775+ len(self._version_hold_removals) > 0)
776+ if not hold_changes:
777+ return None
778+ not_installed = [version for version in
779+ self._version_hold_creations
780+ if not self.is_package_installed(version)]
781+ if not_installed:
782+ raise TransactionError(
783+ "Cannot perform the changes, since the following " +
784+ "packages are not installed: %s" % ", ".join(
785+ [version.package.name
786+ for version in sorted(not_installed)]))
787+
788+ for version in self._version_hold_creations:
789+ self.set_package_hold(version)
790+
791+ for version in self._version_hold_removals:
792+ self.remove_package_hold(version)
793+
794+ return "Package holds successfully changed."
795+
796+ def _commit_package_changes(self):
797+ """
798+ Commit cached APT operations and give feedback on the results as a
799+ string.
800+ """
801+ fetch_output = StringIO()
802+ # Redirect stdout and stderr to a file. We need to work with the
803+ # file descriptors, rather than sys.stdout/stderr, since dpkg is
804+ # run in a subprocess.
805+ fd, install_output_path = tempfile.mkstemp()
806+ old_stdout = os.dup(1)
807+ old_stderr = os.dup(2)
808+ os.dup2(fd, 1)
809+ os.dup2(fd, 2)
810+ install_progress = LandscapeInstallProgress()
811+ try:
812+ self._cache.commit(
813+ fetch_progress=LandscapeAcquireProgress(fetch_output),
814+ install_progress=install_progress)
815+ if not install_progress.dpkg_exited:
816+ raise SystemError("dpkg didn't exit cleanly.")
817+ except SystemError, error:
818+ result_text = (
819+ fetch_output.getvalue() + read_file(install_output_path))
820+ raise TransactionError(error.args[0] +
821+ "\n\nPackage operation log:\n" +
822+ result_text)
823+ else:
824+ result_text = (
825+ fetch_output.getvalue() + read_file(install_output_path))
826+ finally:
827+ # Restore stdout and stderr.
828+ os.dup2(old_stdout, 1)
829+ os.dup2(old_stderr, 2)
830+ os.remove(install_output_path)
831+ return result_text
832+
833+ def _preprocess_installs(self, fixer):
834+ for version in self._version_installs:
835+ # Set the candidate version, so that the version we want to
836+ # install actually is the one getting installed.
837+ version.package.candidate = version
838+ # Set auto_fix=False to avoid removing the package we asked to
839+ # install when we need to resolve dependencies.
840+ version.package.mark_install(auto_fix=False)
841+ fixer.clear(version.package._pkg)
842+ fixer.protect(version.package._pkg)
843+
844+ def _preprocess_removes(self, fixer):
845 held_package_names = set()
846+
847 package_installs = set(
848 version.package for version in self._version_installs)
849+
850 package_upgrades = set(
851 version.package for version in self._version_removals
852 if version.package in package_installs)
853- version_changes = self._version_installs[:]
854- version_changes.extend(self._version_removals)
855- if not version_changes and not self._global_upgrade:
856- return None
857- fixer = apt_pkg.ProblemResolver(self._cache._depcache)
858- already_broken_packages = self._get_broken_packages()
859- for version in self._version_installs:
860- # Set the candidate version, so that the version we want to
861- # install actually is the one getting installed.
862- version.package.candidate = version
863- version.package.mark_install(auto_fix=False)
864- # If we need to resolve dependencies, try avoiding having
865- # the package we asked to be installed from being removed.
866- # (This is what would have been done if auto_fix would have
867- # been True.
868- fixer.clear(version.package._pkg)
869- fixer.protect(version.package._pkg)
870- if self._global_upgrade:
871- self._cache.upgrade(dist_upgrade=True)
872+
873 for version in self._version_removals:
874 if self._is_package_held(version.package):
875 held_package_names.add(version.package.name)
876 if version.package in package_upgrades:
877 # The server requests the old version to be removed for
878 # upgrades, since Smart worked that way. For Apt we have
879- # to take care not to mark upgraded packages for # removal.
880+ # to take care not to mark upgraded packages for removal.
881 continue
882 version.package.mark_delete(auto_fix=False)
883 # Configure the resolver in the same way
884@@ -614,50 +657,65 @@
885 "Can't perform the changes, since the following packages" +
886 " are held: %s" % ", ".join(sorted(held_package_names)))
887
888+ def _preprocess_global_upgrade(self):
889+ if self._global_upgrade:
890+ self._cache.upgrade(dist_upgrade=True)
891+
892+ def _resolve_broken_packages(self, fixer, already_broken_packages):
893+ """
894+ Attempt to automatically resolve problems with broken packages.
895+ """
896 now_broken_packages = self._get_broken_packages()
897 if now_broken_packages != already_broken_packages:
898 try:
899 fixer.resolve(True)
900 except SystemError, error:
901- raise TransactionError(
902- error.args[0] + "\n" + self._get_unmet_dependency_info())
903+ raise TransactionError(error.args[0] + "\n" +
904+ self._get_unmet_dependency_info())
905+
906+ def _preprocess_package_changes(self):
907+ version_changes = self._version_installs[:]
908+ version_changes.extend(self._version_removals)
909+ if (not version_changes and not self._global_upgrade):
910+ return []
911+ already_broken_packages = self._get_broken_packages()
912+ fixer = apt_pkg.ProblemResolver(self._cache._depcache)
913+ self._preprocess_installs(fixer)
914+ self._preprocess_global_upgrade()
915+ self._preprocess_removes(fixer)
916+ self._resolve_broken_packages(fixer, already_broken_packages)
917+ return version_changes
918+
919+ def _perform_package_changes(self):
920+ """
921+ Perform pending install/remove/upgrade operations.
922+ """
923+ version_changes = self._preprocess_package_changes()
924 if not self._check_changes(version_changes):
925 return None
926- fetch_output = StringIO()
927- # Redirect stdout and stderr to a file. We need to work with the
928- # file descriptors, rather than sys.stdout/stderr, since dpkg is
929- # run in a subprocess.
930- fd, install_output_path = tempfile.mkstemp()
931- old_stdout = os.dup(1)
932- old_stderr = os.dup(2)
933- os.dup2(fd, 1)
934- os.dup2(fd, 2)
935- install_progress = LandscapeInstallProgress()
936- try:
937- self._cache.commit(
938- fetch_progress=LandscapeAcquireProgress(fetch_output),
939- install_progress=install_progress)
940- if not install_progress.dpkg_exited:
941- raise SystemError("dpkg didn't exit cleanly.")
942- except SystemError, error:
943- result_text = (
944- fetch_output.getvalue() + read_file(install_output_path))
945- raise TransactionError(
946- error.args[0] + "\n\nPackage operation log:\n" + result_text)
947- else:
948- result_text = (
949- fetch_output.getvalue() + read_file(install_output_path))
950- finally:
951- # Restore stdout and stderr.
952- os.dup2(old_stdout, 1)
953- os.dup2(old_stderr, 2)
954- os.remove(install_output_path)
955- return result_text
956+ return self._commit_package_changes()
957+
958+ def perform_changes(self):
959+ """
960+ Perform the pending package operations.
961+ """
962+ self._setup_dpkg_for_changes()
963+ hold_result_text = self._perform_hold_changes()
964+ package_result_text = self._perform_package_changes()
965+ results = []
966+ if package_result_text is not None:
967+ results.append(package_result_text)
968+ if hold_result_text is not None:
969+ results.append(hold_result_text)
970+ if len(results) > 0:
971+ return " ".join(results)
972
973 def reset_marks(self):
974 """Clear the pending package operations."""
975 del self._version_installs[:]
976 del self._version_removals[:]
977+ del self._version_hold_removals[:]
978+ del self._version_hold_creations[:]
979 self._global_upgrade = False
980 self._cache.clear()
981
982@@ -673,403 +731,10 @@
983 """Mark the package for removal."""
984 self._version_removals.append(version)
985
986-
987-class SmartFacade(object):
988- """Wrapper for tasks using Smart.
989-
990- This object wraps Smart features, in a way that makes using and testing
991- these features slightly more comfortable.
992-
993- @param smart_init_kwargs: A dictionary that can be used to pass specific
994- keyword parameters to to L{smart.init}.
995- """
996-
997- _deb_package_type = None
998- supports_package_holds = False
999- supports_package_locks = True
1000-
1001- def __init__(self, smart_init_kwargs={}, sysconf_args=None):
1002- if not has_smart:
1003- raise RuntimeError(
1004- "Smart needs to be installed if SmartFacade is used.")
1005- self._smart_init_kwargs = smart_init_kwargs.copy()
1006- self._smart_init_kwargs.setdefault("interface", "landscape")
1007- self._sysconfig_args = sysconf_args or {}
1008- self._reset()
1009-
1010- def _reset(self):
1011- # This attribute is initialized lazily in the _get_ctrl() method.
1012- self._ctrl = None
1013- self._pkg2hash = {}
1014- self._hash2pkg = {}
1015- self._marks = {}
1016- self._caching = ALWAYS
1017- self._channels_reloaded = False
1018-
1019- def deinit(self):
1020- """Deinitialize the Facade and the Smart library."""
1021- if self._ctrl:
1022- smart.deinit()
1023- self._reset()
1024-
1025- def _get_ctrl(self):
1026- if self._ctrl is None:
1027- if self._smart_init_kwargs.get("interface") == "landscape":
1028- from landscape.package.interface import (
1029- install_landscape_interface)
1030- install_landscape_interface()
1031- self._ctrl = smart.init(**self._smart_init_kwargs)
1032- for key, value in self._sysconfig_args.items():
1033- smart.sysconf.set(key, value, soft=True)
1034- smart.initDistro(self._ctrl)
1035- smart.initPlugins()
1036- smart.sysconf.set("pm-iface-output", True, soft=True)
1037- smart.sysconf.set("deb-non-interactive", True, soft=True)
1038-
1039- # We can't import it before hand because reaching .deb.* depends
1040- # on initialization (yeah, sucky).
1041- from smart.backends.deb.base import DebPackage
1042- self._deb_package_type = DebPackage
1043-
1044- self.smart_initialized()
1045- return self._ctrl
1046-
1047- def smart_initialized(self):
1048- """Hook called when the Smart library is initialized."""
1049-
1050- def ensure_channels_reloaded(self):
1051- """Reload the channels if they haven't been reloaded yet."""
1052- if self._channels_reloaded:
1053- return
1054- self._channels_reloaded = True
1055- self.reload_channels()
1056-
1057- def reload_channels(self, force_reload_binaries=False):
1058- """
1059- Reload Smart channels, getting all the cache (packages) in memory.
1060-
1061- @raise: L{ChannelError} if Smart fails to reload the channels.
1062- """
1063- ctrl = self._get_ctrl()
1064-
1065- try:
1066- reload_result = ctrl.reloadChannels(caching=self._caching)
1067- except smart.Error:
1068- failed = True
1069- else:
1070- # Raise an error only if we are trying to download remote lists
1071- failed = not reload_result and self._caching == NEVER
1072- if failed:
1073- raise ChannelError("Smart failed to reload channels (%s)"
1074- % smart.sysconf.get("channels"))
1075-
1076- self._hash2pkg.clear()
1077- self._pkg2hash.clear()
1078-
1079- for pkg in self.get_packages():
1080- hash = self.get_package_skeleton(pkg, False).get_hash()
1081- self._hash2pkg[hash] = pkg
1082- self._pkg2hash[pkg] = hash
1083-
1084- self.channels_reloaded()
1085-
1086- def channels_reloaded(self):
1087- """Hook called after Smart channels are reloaded."""
1088-
1089- def get_package_skeleton(self, pkg, with_info=True):
1090- """Return a skeleton for the provided package.
1091-
1092- The skeleton represents the basic structure of the package.
1093-
1094- @param pkg: Package to build skeleton from.
1095- @param with_info: If True, the skeleton will include information
1096- useful for sending data to the server. Such information isn't
1097- necessary if the skeleton will be used to build a hash.
1098-
1099- @return: a L{PackageSkeleton} object.
1100- """
1101- return build_skeleton(pkg, with_info)
1102-
1103- def get_package_hash(self, pkg):
1104- """Return a hash from the given package.
1105-
1106- @param pkg: a L{smart.backends.deb.base.DebPackage} objects
1107- """
1108- return self._pkg2hash.get(pkg)
1109-
1110- def get_package_hashes(self):
1111- """Get the hashes of all the packages available in the channels."""
1112- return self._pkg2hash.values()
1113-
1114- def get_packages(self):
1115- """
1116- Get all the packages available in the channels.
1117-
1118- @return: a C{list} of L{smart.backends.deb.base.DebPackage} objects
1119- """
1120- return [pkg for pkg in self._get_ctrl().getCache().getPackages()
1121- if isinstance(pkg, self._deb_package_type)]
1122-
1123- def get_locked_packages(self):
1124- """Get all packages in the channels matching the set locks."""
1125- return smart.pkgconf.filterByFlag("lock", self.get_packages())
1126-
1127- def get_packages_by_name(self, name):
1128- """
1129- Get all available packages matching the provided name.
1130-
1131- @return: a C{list} of L{smart.backends.deb.base.DebPackage} objects
1132- """
1133- return [pkg for pkg in self._get_ctrl().getCache().getPackages(name)
1134- if isinstance(pkg, self._deb_package_type)]
1135-
1136- def get_package_by_hash(self, hash):
1137- """
1138- Get all available packages matching the provided hash.
1139-
1140- @return: a C{list} of L{smart.backends.deb.base.DebPackage} objects
1141- """
1142- return self._hash2pkg.get(hash)
1143-
1144- def mark_install(self, pkg):
1145- self._marks[pkg] = INSTALL
1146-
1147- def mark_remove(self, pkg):
1148- self._marks[pkg] = REMOVE
1149-
1150- def mark_upgrade(self, pkg):
1151- self._marks[pkg] = UPGRADE
1152-
1153- def mark_global_upgrade(self):
1154- """Upgrade all installed packages."""
1155- for package in self.get_packages():
1156- if self.is_package_installed(package):
1157- self.mark_upgrade(package)
1158-
1159- def reset_marks(self):
1160- self._marks.clear()
1161-
1162- def perform_changes(self):
1163- ctrl = self._get_ctrl()
1164- cache = ctrl.getCache()
1165-
1166- transaction = Transaction(cache)
1167-
1168- policy = PolicyInstall
1169-
1170- only_remove = True
1171- for pkg, oper in self._marks.items():
1172- if oper == UPGRADE:
1173- policy = PolicyUpgrade
1174- if oper != REMOVE:
1175- only_remove = False
1176- transaction.enqueue(pkg, oper)
1177-
1178- if only_remove:
1179- policy = PolicyRemove
1180-
1181- transaction.setPolicy(policy)
1182-
1183- try:
1184- transaction.run()
1185- except Failed, e:
1186- raise TransactionError(e.args[0])
1187- changeset = transaction.getChangeSet()
1188-
1189- if not changeset:
1190- return None # Nothing to do.
1191-
1192- missing = []
1193- for pkg, op in changeset.items():
1194- if self._marks.get(pkg) != op:
1195- missing.append(pkg)
1196- if missing:
1197- raise DependencyError(missing)
1198-
1199- try:
1200- self._ctrl.commitChangeSet(changeset)
1201- except smart.Error, e:
1202- raise TransactionError(e.args[0])
1203-
1204- output = smart.iface.get_output_for_landscape()
1205- failed = smart.iface.has_failed_for_landscape()
1206-
1207- smart.iface.reset_for_landscape()
1208-
1209- if failed:
1210- raise SmartError(output)
1211- return output
1212-
1213- def reload_cache(self):
1214- cache = self._get_ctrl().getCache()
1215- cache.reset()
1216- cache.load()
1217-
1218- def get_arch(self):
1219- """
1220- Get the host dpkg architecture.
1221- """
1222- self._get_ctrl()
1223- from smart.backends.deb.loader import DEBARCH
1224- return DEBARCH
1225-
1226- def set_arch(self, arch):
1227- """
1228- Set the host dpkg architecture.
1229-
1230- To take effect it must be called before L{reload_channels}.
1231-
1232- @param arch: the dpkg architecture to use (e.g. C{"i386"})
1233- """
1234- self._get_ctrl()
1235- smart.sysconf.set("deb-arch", arch)
1236-
1237- # XXX workaround Smart setting DEBARCH statically in the
1238- # smart.backends.deb.base module
1239- import smart.backends.deb.loader as loader
1240- loader.DEBARCH = arch
1241-
1242- def set_caching(self, mode):
1243- """
1244- Set Smart's caching mode.
1245-
1246- @param mode: The caching mode to pass to Smart's C{reloadChannels}
1247- when calling L{reload_channels} (e.g C{smart.const.NEVER} or
1248- C{smart.const.ALWAYS}).
1249- """
1250- self._caching = mode
1251-
1252- def reset_channels(self):
1253- """Remove all configured Smart channels."""
1254- self._get_ctrl()
1255- smart.sysconf.set("channels", {}, soft=True)
1256-
1257- def add_channel(self, alias, channel):
1258- """
1259- Add a Smart channel.
1260-
1261- This method can be called more than once to set multiple channels.
1262- To take effect it must be called before L{reload_channels}.
1263-
1264- @param alias: A string identifying the channel to be added.
1265- @param channel: A C{dict} holding information about the channel to
1266- add (see the Smart API for details about valid keys and values).
1267- """
1268- channels = self.get_channels()
1269- channels.update({alias: channel})
1270- smart.sysconf.set("channels", channels, soft=True)
1271-
1272- def add_channel_apt_deb(self, url, codename, components):
1273- """Add a Smart channel of type C{"apt-deb"}.
1274-
1275- @see: L{add_channel}
1276- """
1277- alias = codename
1278- channel = {"baseurl": url, "distribution": codename,
1279- "components": components, "type": "apt-deb"}
1280- self.add_channel(alias, channel)
1281-
1282- def add_channel_deb_dir(self, path):
1283- """Add a Smart channel of type C{"deb-dir"}.
1284-
1285- @see: L{add_channel}
1286- """
1287- alias = path
1288- channel = {"path": path, "type": "deb-dir"}
1289- self.add_channel(alias, channel)
1290-
1291- def clear_channels(self):
1292- """Clear channels.
1293-
1294- This method exists to be compatible with AptFacade. Smart
1295- doesn't need to clear its channels.
1296- """
1297-
1298- def get_channels(self):
1299- """
1300- @return: A C{dict} of all configured channels.
1301- """
1302- self._get_ctrl()
1303- return smart.sysconf.get("channels")
1304-
1305- def get_package_locks(self):
1306- """Return all set package locks.
1307-
1308- @return: A C{list} of ternary tuples, contaning the name, relation
1309- and version details for each lock currently set on the system.
1310- """
1311- self._get_ctrl()
1312- locks = []
1313- locks_by_name = smart.pkgconf.getFlagTargets("lock")
1314- for name in locks_by_name:
1315- for condition in locks_by_name[name]:
1316- relation = condition[0] or ""
1317- version = condition[1] or ""
1318- locks.append((name, relation, version))
1319- return locks
1320-
1321- def _validate_lock_condition(self, relation, version):
1322- if relation and not version:
1323- raise RuntimeError("Package lock version not provided")
1324- if version and not relation:
1325- raise RuntimeError("Package lock relation not provided")
1326-
1327- def set_package_lock(self, name, relation=None, version=None):
1328- """Set a new package lock.
1329-
1330- Any package matching the given name and possibly the given version
1331- condition will be locked.
1332-
1333- @param name: The name a package must match in order to be locked.
1334- @param relation: Optionally, the relation of the version condition the
1335- package must satisfy in order to be considered as locked.
1336- @param version: Optionally, the version associated with C{relation}.
1337-
1338- @note: If used at all, the C{relation} and C{version} parameter must be
1339- both provided.
1340- """
1341- self._validate_lock_condition(relation, version)
1342- self._get_ctrl()
1343- smart.pkgconf.setFlag("lock", name, relation, version)
1344-
1345- def remove_package_lock(self, name, relation=None, version=None):
1346- """Remove a package lock."""
1347- self._validate_lock_condition(relation, version)
1348- self._get_ctrl()
1349- smart.pkgconf.clearFlag("lock", name=name, relation=relation,
1350- version=version)
1351-
1352- def save_config(self):
1353- """Flush the current smart configuration to disk."""
1354- control = self._get_ctrl()
1355- control.saveSysConf()
1356-
1357- def is_package_installed(self, package):
1358- """Is the package installed?"""
1359- return package.installed
1360-
1361- def is_package_available(self, package):
1362- """Is the package available for installation?"""
1363- for loader in package.loaders:
1364- # Is the package also in a non-installed
1365- # loader? IOW, "available".
1366- if not loader.getInstalled():
1367- return True
1368- return False
1369-
1370- def is_package_upgrade(self, package):
1371- """Is the package an upgrade for another installed package?"""
1372- is_upgrade = False
1373- for upgrade in package.upgrades:
1374- for provides in upgrade.providedby:
1375- for provides_package in provides.packages:
1376- if provides_package.installed:
1377- is_upgrade = True
1378- break
1379- else:
1380- continue
1381- break
1382- else:
1383- continue
1384- break
1385- return is_upgrade
1386+ def mark_hold(self, version):
1387+ """Mark the package to be held."""
1388+ self._version_hold_creations.append(version)
1389+
1390+ def mark_remove_hold(self, version):
1391+ """Mark the package to have its hold removed."""
1392+ self._version_hold_removals.append(version)
1393
1394=== removed file 'landscape/package/interface.py'
1395--- landscape/package/interface.py 2012-03-19 09:33:34 +0000
1396+++ landscape/package/interface.py 1970-01-01 00:00:00 +0000
1397@@ -1,84 +0,0 @@
1398-import logging
1399-import types
1400-import sys
1401-
1402-try:
1403- import smart.interfaces
1404- from smart.interface import Interface
1405- from smart.const import ERROR, WARNING, INFO, DEBUG
1406-except ImportError:
1407- # Smart is optional if AptFacade is being used.
1408- Interface = object
1409-
1410-
1411-class LandscapeInterface(Interface):
1412-
1413- __output = ""
1414- __failed = False
1415-
1416- def reset_for_landscape(self):
1417- """Reset output and failed flag."""
1418- self.__failed = False
1419- self.__output = u""
1420-
1421- def get_output_for_landscape(self):
1422- """showOutput() is cached, and returned by this method."""
1423- return self.__output
1424-
1425- def has_failed_for_landscape(self):
1426- """Return true if any error() messages were logged."""
1427- return self.__failed
1428-
1429- def error(self, msg):
1430- self.__failed = True
1431- # Calling these logging.* functions here instead of message()
1432- # below will output the message or not depending on the debug
1433- # level set in landscape-client, rather than the one set in
1434- # Smart's configuration.
1435- logging.error("[Smart] %s", msg)
1436- super(LandscapeInterface, self).error(msg)
1437-
1438- def warning(self, msg):
1439- logging.warning("[Smart] %s", msg)
1440- super(LandscapeInterface, self).warning(msg)
1441-
1442- def info(self, msg):
1443- logging.info("[Smart] %s", msg)
1444- super(LandscapeInterface, self).info(msg)
1445-
1446- def debug(self, msg):
1447- logging.debug("[Smart] %s", msg)
1448- super(LandscapeInterface, self).debug(msg)
1449-
1450- def message(self, level, msg):
1451- prefix = {ERROR: "ERROR", WARNING: "WARNING",
1452- INFO: "INFO", DEBUG: "DEBUG"}.get(level)
1453- self.showOutput("%s: %s\n" % (prefix, msg))
1454-
1455- def showOutput(self, output):
1456- if not isinstance(output, unicode):
1457- try:
1458- output = output.decode("utf-8")
1459- except UnicodeDecodeError:
1460- output = output.decode("ascii", "replace")
1461- self.__output += output
1462-
1463-
1464-class LandscapeInterfaceModule(types.ModuleType):
1465-
1466- def __init__(self):
1467- super(LandscapeInterfaceModule, self).__init__("landscape")
1468-
1469- def create(self, ctrl, command=None, argv=None):
1470- return LandscapeInterface(ctrl)
1471-
1472-
1473-def install_landscape_interface():
1474- if "smart.interfaces.landscape" not in sys.modules:
1475- # Plug the interface in a place Smart will recognize.
1476- smart.interfaces.landscape = LandscapeInterfaceModule()
1477- sys.modules["smart.interfaces.landscape"] = smart.interfaces.landscape
1478-
1479-
1480-def uninstall_landscape_interface():
1481- sys.modules.pop("smart.interfaces.landscape", None)
1482
1483=== modified file 'landscape/package/releaseupgrader.py'
1484--- landscape/package/releaseupgrader.py 2011-07-18 15:16:18 +0000
1485+++ landscape/package/releaseupgrader.py 2012-06-04 14:08:28 +0000
1486@@ -301,8 +301,8 @@
1487
1488 reporter = find_reporter_command()
1489
1490- # Force a smart-update run, because the sources.list has changed
1491- args = ["--force-smart-update"]
1492+ # Force an apt-update run, because the sources.list has changed
1493+ args = ["--force-apt-update"]
1494
1495 if self._config.config is not None:
1496 args.append("--config=%s" % self._config.config)
1497
1498=== modified file 'landscape/package/reporter.py'
1499--- landscape/package/reporter.py 2012-03-19 09:33:34 +0000
1500+++ landscape/package/reporter.py 2012-06-04 14:08:28 +0000
1501@@ -12,7 +12,6 @@
1502 from landscape.lib.fs import touch_file
1503 from landscape.lib import bpickle
1504
1505-from landscape.package.facade import AptFacade
1506 from landscape.package.taskhandler import (
1507 PackageTaskHandlerConfiguration, PackageTaskHandler, run_task_handler)
1508 from landscape.package.store import UnknownHashIDRequest, FakePackageStore
1509@@ -31,9 +30,9 @@
1510 reporter-specific options.
1511 """
1512 parser = super(PackageReporterConfiguration, self).make_parser()
1513- parser.add_option("--force-smart-update", default=False,
1514+ parser.add_option("--force-apt-update", default=False,
1515 action="store_true",
1516- help="Force running smart-update.")
1517+ help="Force running apt-update.")
1518 return parser
1519
1520
1521@@ -41,15 +40,14 @@
1522 """Report information about the system packages.
1523
1524 @cvar queue_name: Name of the task queue to pick tasks from.
1525- @cvar smart_update_interval: Time interval in minutes to pass to
1526- the C{--after} command line option of C{smart-update}.
1527+ @cvar apt_update_interval: Don't update the APT index more often
1528+ than the given interval in minutes.
1529 """
1530 config_factory = PackageReporterConfiguration
1531
1532 queue_name = "reporter"
1533
1534- smart_update_interval = 60
1535- smart_update_filename = "/usr/lib/landscape/smart-update"
1536+ apt_update_interval = 60
1537 apt_update_filename = "/usr/lib/landscape/apt-update"
1538 sources_list_filename = "/etc/apt/sources.list"
1539 sources_list_directory = "/etc/apt/sources.list.d"
1540@@ -57,13 +55,7 @@
1541 def run(self):
1542 result = Deferred()
1543
1544- if isinstance(self._facade, AptFacade):
1545- # Update APT cache if APT facade is enabled.
1546- result.addCallback(lambda x: self.run_apt_update())
1547- else:
1548- # Run smart-update before anything else, to make sure that
1549- # the SmartFacade will load freshly updated channels
1550- result.addCallback(lambda x: self.run_smart_update())
1551+ result.addCallback(lambda x: self.run_apt_update())
1552
1553 # If the appropriate hash=>id db is not there, fetch it
1554 result.addCallback(lambda x: self.fetch_hash_id_db())
1555@@ -183,44 +175,6 @@
1556
1557 return False
1558
1559- def run_smart_update(self):
1560- """Run smart-update and log a warning in case of non-zero exit code.
1561-
1562- @return: a deferred returning (out, err, code)
1563- """
1564- if self._config.force_smart_update or self._apt_sources_have_changed():
1565- args = ()
1566- else:
1567- args = ("--after", str(self.smart_update_interval))
1568- result = spawn_process(self.smart_update_filename, args=args)
1569-
1570- def callback((out, err, code)):
1571- # smart-update --after N will exit with error code 1 when it
1572- # doesn't actually run the update code because to enough time
1573- # has passed yet, but we don't actually consider it a failure.
1574- smart_failed = False
1575- if code != 0 and code != 1:
1576- smart_failed = True
1577- if code == 1 and err.strip() != "":
1578- smart_failed = True
1579- if smart_failed:
1580- logging.warning("'%s' exited with status %d (%s)" % (
1581- self.smart_update_filename, code, err))
1582- logging.debug("'%s' exited with status %d (out='%s', err='%s'" % (
1583- self.smart_update_filename, code, out, err))
1584- touch_file(self._config.update_stamp_filename)
1585- if not smart_failed and not self._facade.get_channels():
1586- code = 1
1587- err = "There are no APT sources configured in %s or %s." % (
1588- self.sources_list_filename, self.sources_list_directory)
1589- deferred = self._broker.call_if_accepted(
1590- "package-reporter-result", self.send_result, code, err)
1591- deferred.addCallback(lambda ignore: (out, err, code))
1592- return deferred
1593-
1594- result.addCallback(callback)
1595- return result
1596-
1597 def _apt_update_timeout_expired(self, interval):
1598 """Check if the apt-update timeout has passed."""
1599 stamp = self._config.update_stamp_filename
1600@@ -237,8 +191,8 @@
1601
1602 @return: a deferred returning (out, err, code)
1603 """
1604- if (self._config.force_smart_update or self._apt_sources_have_changed()
1605- or self._apt_update_timeout_expired(self.smart_update_interval)):
1606+ if (self._config.force_apt_update or self._apt_sources_have_changed()
1607+ or self._apt_update_timeout_expired(self.apt_update_interval)):
1608
1609 result = spawn_process(self.apt_update_filename)
1610
1611@@ -323,7 +277,6 @@
1612 self._store.clear_available_upgrades()
1613 self._store.clear_installed()
1614 self._store.clear_locked()
1615- self._store.clear_package_locks()
1616
1617 # Don't clear the hash_id_requests table because the messages
1618 # associated with the existing requests might still have to be
1619@@ -405,7 +358,7 @@
1620 def request_unknown_hashes(self):
1621 """Detect available packages for which we have no hash=>id mappings.
1622
1623- This method will verify if there are packages that Smart knows
1624+ This method will verify if there are packages that APT knows
1625 about but for which we don't have an id yet (no hash => id
1626 translation), and deliver a message (unknown-package-hashes)
1627 to request them.
1628@@ -466,16 +419,13 @@
1629 reactor.
1630 """
1631
1632- def changes_detected(results):
1633- # Release all smart locks, in case the changer runs after us.
1634- self._facade.deinit()
1635- if True in results:
1636+ def changes_detected(result):
1637+ if result:
1638 # Something has changed, notify the broker.
1639 return self._broker.fire_event("package-data-changed")
1640
1641- result = gather_results([self.detect_packages_changes(),
1642- self.detect_package_locks_changes()])
1643- return result.addCallback(changes_detected)
1644+ deferred = self.detect_packages_changes()
1645+ return deferred.addCallback(changes_detected)
1646
1647 def detect_packages_changes(self):
1648 """Detect changes in the universe of known packages.
1649@@ -609,53 +559,6 @@
1650
1651 return result
1652
1653- def detect_package_locks_changes(self):
1654- """Detect changes in known package locks.
1655-
1656- This method will verify if there are package locks that:
1657-
1658- - are now set, and were not;
1659- - were previously set but are not anymore;
1660-
1661- In all cases, the server is notified of the new situation
1662- with a "packages" message.
1663-
1664- @return: A deferred resulting in C{True} if package lock changes were
1665- detected with respect to the previous run, or C{False} otherwise.
1666- """
1667- old_package_locks = set(self._store.get_package_locks())
1668- current_package_locks = set(self._facade.get_package_locks())
1669-
1670- set_package_locks = current_package_locks - old_package_locks
1671- unset_package_locks = old_package_locks - current_package_locks
1672-
1673- message = {}
1674- if set_package_locks:
1675- message["created"] = sorted(set_package_locks)
1676- if unset_package_locks:
1677- message["deleted"] = sorted(unset_package_locks)
1678-
1679- if not message:
1680- return succeed(False)
1681-
1682- message["type"] = "package-locks"
1683- result = self.send_message(message)
1684-
1685- logging.info("Queuing message with changes in known package locks:"
1686- " %d created, %d deleted." %
1687- (len(set_package_locks), len(unset_package_locks)))
1688-
1689- def update_currently_known(result):
1690- if set_package_locks:
1691- self._store.add_package_locks(set_package_locks)
1692- if unset_package_locks:
1693- self._store.remove_package_locks(unset_package_locks)
1694- return True
1695-
1696- result.addCallback(update_currently_known)
1697-
1698- return result
1699-
1700
1701 class FakeGlobalReporter(PackageReporter):
1702 """
1703
1704=== modified file 'landscape/package/skeleton.py'
1705--- landscape/package/skeleton.py 2012-03-19 09:33:34 +0000
1706+++ landscape/package/skeleton.py 2012-06-04 14:08:28 +0000
1707@@ -47,54 +47,6 @@
1708 return digest.digest()
1709
1710
1711-def build_skeleton(pkg, with_info=False, with_unicode=False):
1712- if not build_skeleton.inited:
1713- build_skeleton.inited = True
1714- global DebPackage, DebNameProvides, DebOrDepends
1715-
1716- # Importing from backends depends on smart.init().
1717- from smart.backends.deb.base import (
1718- DebPackage, DebNameProvides, DebOrDepends)
1719-
1720- if not isinstance(pkg, DebPackage):
1721- raise PackageTypeError()
1722-
1723- if with_unicode:
1724- skeleton = PackageSkeleton(DEB_PACKAGE, unicode(pkg.name),
1725- unicode(pkg.version))
1726- else:
1727- skeleton = PackageSkeleton(DEB_PACKAGE, pkg.name, pkg.version)
1728- relations = set()
1729- for relation in pkg.provides:
1730- if isinstance(relation, DebNameProvides):
1731- relations.add((DEB_NAME_PROVIDES, str(relation)))
1732- else:
1733- relations.add((DEB_PROVIDES, str(relation)))
1734- for relation in pkg.requires:
1735- if isinstance(relation, DebOrDepends):
1736- relations.add((DEB_OR_REQUIRES, str(relation)))
1737- else:
1738- relations.add((DEB_REQUIRES, str(relation)))
1739- for relation in pkg.upgrades:
1740- relations.add((DEB_UPGRADES, str(relation)))
1741- for relation in pkg.conflicts:
1742- relations.add((DEB_CONFLICTS, str(relation)))
1743-
1744- skeleton.relations = sorted(relations)
1745-
1746- if with_info:
1747- info = pkg.loaders.keys()[0].getInfo(pkg)
1748- skeleton.section = info.getGroup()
1749- skeleton.summary = info.getSummary()
1750- skeleton.description = info.getDescription()
1751- skeleton.size = sum(info.getSize(url) for url in info.getURLs())
1752- skeleton.installed_size = info.getInstalledSize()
1753-
1754- return skeleton
1755-
1756-build_skeleton.inited = False
1757-
1758-
1759 def relation_to_string(relation_tuple):
1760 """Convert an apt relation to a string representation.
1761
1762
1763=== modified file 'landscape/package/store.py'
1764--- landscape/package/store.py 2012-03-19 09:33:34 +0000
1765+++ landscape/package/store.py 2012-06-04 14:08:28 +0000
1766@@ -249,40 +249,6 @@
1767 cursor.execute("DELETE FROM locked")
1768
1769 @with_cursor
1770- def get_package_locks(self, cursor):
1771- """Get all package locks."""
1772- cursor.execute("SELECT name, relation, version FROM package_locks")
1773- return [(row[0], row[1], row[2]) for row in cursor.fetchall()]
1774-
1775- @with_cursor
1776- def add_package_locks(self, cursor, locks):
1777- """Add a list of package locks to the store.
1778-
1779- @param locks: A C{list} of ternary tuples each one contains the
1780- name, the relation and the version of the package lock to be added.
1781- """
1782- for name, relation, version in locks:
1783- cursor.execute("REPLACE INTO package_locks VALUES (?, ?, ?)",
1784- (name, relation or "", version or "",))
1785-
1786- @with_cursor
1787- def remove_package_locks(self, cursor, locks):
1788- """Remove a list of package locks from the store.
1789-
1790- @param locks: A C{list} of ternary tuples each one contains the name,
1791- the relation and the version of the package lock to be removed.
1792- """
1793- for name, relation, version in locks:
1794- cursor.execute("DELETE FROM package_locks WHERE name=? AND "
1795- "relation=? AND version=?",
1796- (name, relation or "", version or ""))
1797-
1798- @with_cursor
1799- def clear_package_locks(self, cursor):
1800- """Remove all package locks."""
1801- cursor.execute("DELETE FROM package_locks")
1802-
1803- @with_cursor
1804 def add_hash_id_request(self, cursor, hashes):
1805 hashes = list(hashes)
1806 cursor.execute("INSERT INTO hash_id_request (hashes, timestamp)"
1807@@ -458,9 +424,6 @@
1808 # try block.
1809 cursor = db.cursor()
1810 try:
1811- cursor.execute("CREATE TABLE package_locks"
1812- " (name TEXT NOT NULL, relation TEXT, version TEXT,"
1813- " UNIQUE(name, relation, version))")
1814 cursor.execute("CREATE TABLE locked"
1815 " (id INTEGER PRIMARY KEY)")
1816 cursor.execute("CREATE TABLE available"
1817
1818=== modified file 'landscape/package/taskhandler.py'
1819--- landscape/package/taskhandler.py 2012-03-19 09:33:34 +0000
1820+++ landscape/package/taskhandler.py 2012-06-04 14:08:28 +0000
1821@@ -254,19 +254,15 @@
1822 words = re.findall("[A-Z][a-z]+", cls.__name__)
1823 init_logging(config, "-".join(word.lower() for word in words))
1824
1825- # Setup our umask for Smart to use, this needs to setup file permissions to
1826+ # Setup our umask for Apt to use, this needs to setup file permissions to
1827 # 0644 so...
1828 os.umask(022)
1829
1830 package_store = cls.package_store_class(config.store_filename)
1831 # Delay importing of the facades so that we don't
1832- # import Smart unless we need to.
1833- from landscape.package.facade import (
1834- AptFacade, SmartFacade, has_new_enough_apt)
1835- if has_new_enough_apt:
1836- package_facade = AptFacade()
1837- else:
1838- package_facade = SmartFacade()
1839+ # import Apt unless we need to.
1840+ from landscape.package.facade import AptFacade
1841+ package_facade = AptFacade()
1842
1843 def finish():
1844 connector.disconnect()
1845
1846=== modified file 'landscape/package/tests/helpers.py'
1847--- landscape/package/tests/helpers.py 2012-03-19 09:33:34 +0000
1848+++ landscape/package/tests/helpers.py 2012-06-04 14:08:28 +0000
1849@@ -3,12 +3,6 @@
1850 import textwrap
1851 import time
1852
1853-try:
1854- import smart
1855-except ImportError:
1856- # Smart is optional if AptFacade is being used.
1857- pass
1858-
1859 import apt_inst
1860 import apt_pkg
1861
1862@@ -127,39 +121,6 @@
1863 test_case.facade.add_channel_deb_dir(test_case.repository_dir)
1864
1865
1866-class SmartHelper(object):
1867-
1868- def set_up(self, test_case):
1869- test_case.smart_dir = test_case.makeDir()
1870- test_case.smart_config = test_case.makeFile("")
1871- test_case.repository_dir = test_case.makeDir()
1872- create_simple_repository(test_case.repository_dir)
1873-
1874- def tear_down(self, test_case):
1875- if smart.iface.object:
1876- smart.deinit()
1877-
1878-
1879-class SmartFacadeHelper(SmartHelper):
1880-
1881- def set_up(self, test_case):
1882- super(SmartFacadeHelper, self).set_up(test_case)
1883-
1884- from landscape.package.facade import SmartFacade
1885-
1886- class Facade(SmartFacade):
1887- repository_dir = test_case.repository_dir
1888-
1889- def smart_initialized(self):
1890- self.reset_channels()
1891- self.add_channel_deb_dir(test_case.repository_dir)
1892-
1893- test_case.Facade = Facade
1894- test_case.facade = Facade({"datadir": test_case.smart_dir,
1895- "configfile": test_case.smart_config},
1896- {"sync-apt-sources": False})
1897-
1898-
1899 PKGNAME1 = "name1_version1-release1_all.deb"
1900 PKGNAME2 = "name2_version2-release2_all.deb"
1901 PKGNAME3 = "name3_version3-release3_all.deb"
1902
1903=== modified file 'landscape/package/tests/test_changer.py'
1904--- landscape/package/tests/test_changer.py 2012-03-21 16:15:49 +0000
1905+++ landscape/package/tests/test_changer.py 2012-06-04 14:08:28 +0000
1906@@ -6,12 +6,6 @@
1907
1908 from twisted.internet.defer import Deferred
1909
1910-try:
1911- from smart.cache import Provides
1912-except ImportError:
1913- # Smart is optional if AptFacade is being used.
1914- pass
1915-
1916 from landscape.lib.fs import create_file, read_file, touch_file
1917 from landscape.package.changer import (
1918 PackageChanger, main, find_changer_command, UNKNOWN_PACKAGE_DATA_TIMEOUT,
1919@@ -19,19 +13,107 @@
1920 POLICY_ALLOW_ALL_CHANGES, ERROR_RESULT)
1921 from landscape.package.store import PackageStore
1922 from landscape.package.facade import (
1923- DependencyError, TransactionError, SmartError, has_new_enough_apt)
1924+ DependencyError, TransactionError)
1925 from landscape.package.changer import (
1926 PackageChangerConfiguration, ChangePackagesResult)
1927 from landscape.tests.mocker import ANY
1928 from landscape.tests.helpers import (
1929 LandscapeTest, BrokerServiceHelper)
1930 from landscape.package.tests.helpers import (
1931- SmartFacadeHelper, HASH1, HASH2, HASH3, PKGDEB1, PKGDEB2, PKGNAME2,
1932+ HASH1, HASH2, HASH3, PKGDEB1, PKGDEB2,
1933 AptFacadeHelper, SimpleRepositoryHelper)
1934-from landscape.manager.manager import FAILED, SUCCEEDED
1935-
1936-
1937-class PackageChangerTestMixin(object):
1938+from landscape.manager.manager import FAILED
1939+
1940+
1941+class AptPackageChangerTest(LandscapeTest):
1942+
1943+ helpers = [AptFacadeHelper, SimpleRepositoryHelper, BrokerServiceHelper]
1944+
1945+ def setUp(self):
1946+
1947+ def set_up(ignored):
1948+
1949+ self.store = PackageStore(self.makeFile())
1950+ self.config = PackageChangerConfiguration()
1951+ self.config.data_path = self.makeDir()
1952+ os.mkdir(self.config.package_directory)
1953+ os.mkdir(self.config.binaries_path)
1954+ touch_file(self.config.update_stamp_filename)
1955+ self.changer = PackageChanger(
1956+ self.store, self.facade, self.remote, self.config)
1957+ service = self.broker_service
1958+ service.message_store.set_accepted_types(["change-packages-result",
1959+ "operation-result"])
1960+
1961+ result = super(AptPackageChangerTest, self).setUp()
1962+ return result.addCallback(set_up)
1963+
1964+ def set_pkg1_installed(self):
1965+ """Return the hash of a package that is installed."""
1966+ self._add_system_package("foo")
1967+ self.facade.reload_channels()
1968+ [foo] = self.facade.get_packages_by_name("foo")
1969+ return self.facade.get_package_hash(foo)
1970+
1971+ def set_pkg2_satisfied(self):
1972+ """Return the hash of a package that can be installed."""
1973+ self._add_package_to_deb_dir(self.repository_dir, "bar")
1974+ self.facade.reload_channels()
1975+ [bar] = self.facade.get_packages_by_name("bar")
1976+ return self.facade.get_package_hash(bar)
1977+
1978+ def set_pkg1_and_pkg2_satisfied(self):
1979+ """Make a package depend on another package.
1980+
1981+ Return the hashes of the two packages.
1982+ """
1983+ self._add_package_to_deb_dir(
1984+ self.repository_dir, "foo", control_fields={"Depends": "bar"})
1985+ self._add_package_to_deb_dir(self.repository_dir, "bar")
1986+ self.facade.reload_channels()
1987+ [foo] = self.facade.get_packages_by_name("foo")
1988+ [bar] = self.facade.get_packages_by_name("bar")
1989+ return (
1990+ self.facade.get_package_hash(foo),
1991+ self.facade.get_package_hash(bar))
1992+
1993+ def set_pkg2_upgrades_pkg1(self):
1994+ """Make it so that one package upgrades another.
1995+
1996+ Return the hashes of the two packages.
1997+ """
1998+ self._add_system_package("foo", version="1.0")
1999+ self._add_package_to_deb_dir(self.repository_dir, "foo", version="2.0")
2000+ self.facade.reload_channels()
2001+ foo_1, foo_2 = sorted(self.facade.get_packages_by_name("foo"))
2002+ return (
2003+ self.facade.get_package_hash(foo_1),
2004+ self.facade.get_package_hash(foo_2))
2005+
2006+ def remove_pkg2(self):
2007+ """Remove package name2 from its repository."""
2008+ packages_file = os.path.join(self.repository_dir, "Packages")
2009+ packages_contents = read_file(packages_file)
2010+ packages_contents = "\n\n".join(
2011+ [stanza for stanza in packages_contents.split("\n\n")
2012+ if "Package: name2" not in stanza])
2013+ create_file(packages_file, packages_contents)
2014+
2015+ def get_transaction_error_message(self):
2016+ """Return part of the apt transaction error message."""
2017+ return "Unable to correct problems"
2018+
2019+ def get_binaries_channels(self, binaries_path):
2020+ """Return the channels that will be used for the binaries."""
2021+ return [{"baseurl": "file://%s" % binaries_path,
2022+ "components": "",
2023+ "distribution": "./",
2024+ "type": "deb"}]
2025+
2026+ def get_package_name(self, version):
2027+ """Return the name of the package."""
2028+ return version.package.name
2029+
2030
2031 def disable_clear_channels(self):
2032 """Disable clear_channels(), so that it doesn't remove test setup.
2033@@ -441,7 +523,7 @@
2034
2035 def test_tasks_are_isolated_cache(self):
2036 """
2037- The package (apt/smart) cache should be reset between task runs.
2038+ The package (APT) cache should be reset between task runs.
2039 In this test, we try to run two different operations, first
2040 installing package 2, then removing package 1. Both tasks will
2041 fail for lack of superuser privileges. If the package cache
2042@@ -533,7 +615,7 @@
2043 """
2044 Besides asking for individual changes, the server may also request
2045 the client to perform a global upgrade. This would be the equivalent
2046- of a "smart upgrade" command being executed in the command line.
2047+ of a "apt-get upgrade" command being executed in the command line.
2048 """
2049 hash1, hash2 = self.set_pkg2_upgrades_pkg1()
2050 self.store.set_hash_ids({hash1: 1, hash2: 2})
2051@@ -638,8 +720,7 @@
2052 """
2053 After the package changer has run, we want the package-reporter to run
2054 to report the recent changes. If we're running as root, we want to
2055- change to the "landscape" user and "landscape" group. We also want to
2056- deinitialize Smart to let the reporter run smart-update cleanly.
2057+ change to the "landscape" user and "landscape" group.
2058 """
2059
2060 # We are running as root
2061@@ -647,13 +728,8 @@
2062 getuid_mock()
2063 self.mocker.result(0)
2064
2065- # The order matters (first smart then gid and finally uid)
2066 self.mocker.order()
2067
2068- # Deinitialize smart
2069- facade_mock = self.mocker.patch(self.facade)
2070- facade_mock.deinit()
2071-
2072 # We want to return a known gid
2073 grnam_mock = self.mocker.replace("grp.getgrnam")
2074 grnam_mock("landscape")
2075@@ -810,27 +886,6 @@
2076 "type": "change-packages-result"}])
2077 return result.addCallback(got_result)
2078
2079- def test_smart_error_with_unicode_data(self):
2080- self.store.set_hash_ids({HASH1: 1})
2081- self.store.add_task("changer",
2082- {"type": "change-packages", "install": [1],
2083- "operation-id": 123})
2084-
2085- def raise_error(self):
2086- raise SmartError(u"áéíóú")
2087- self.replace_perform_changes(raise_error)
2088- self.disable_clear_channels()
2089-
2090- result = self.changer.handle_tasks()
2091-
2092- def got_result(result):
2093- self.assertMessages(self.get_pending_messages(),
2094- [{"operation-id": 123,
2095- "result-code": 100,
2096- "result-text": u"áéíóú",
2097- "type": "change-packages-result"}])
2098- return result.addCallback(got_result)
2099-
2100 def test_update_stamp_exists(self):
2101 """
2102 L{PackageChanger.update_exists} returns C{True} if the
2103@@ -892,360 +947,6 @@
2104 self.assertFalse(os.path.exists(existing_deb_path))
2105
2106
2107-class SmartPackageChangerTest(LandscapeTest, PackageChangerTestMixin):
2108-
2109- helpers = [SmartFacadeHelper, BrokerServiceHelper]
2110-
2111- def setUp(self):
2112-
2113- def set_up(ignored):
2114-
2115- self.store = PackageStore(self.makeFile())
2116- self.config = PackageChangerConfiguration()
2117- self.config.data_path = self.makeDir()
2118- os.mkdir(self.config.package_directory)
2119- os.mkdir(self.config.binaries_path)
2120- touch_file(self.config.update_stamp_filename)
2121- self.changer = PackageChanger(
2122- self.store, self.facade, self.remote, self.config)
2123- service = self.broker_service
2124- service.message_store.set_accepted_types(["change-packages-result",
2125- "operation-result"])
2126-
2127- result = super(SmartPackageChangerTest, self).setUp()
2128- return result.addCallback(set_up)
2129-
2130- def set_pkg1_installed(self):
2131- previous = self.Facade.channels_reloaded
2132-
2133- def callback(self):
2134- previous(self)
2135- self.get_packages_by_name("name1")[0].installed = True
2136- self.Facade.channels_reloaded = callback
2137- return HASH1
2138-
2139- def set_pkg2_upgrades_pkg1(self):
2140- previous = self.Facade.channels_reloaded
2141-
2142- def callback(self):
2143- from smart.backends.deb.base import DebUpgrades
2144- previous(self)
2145- [pkg2] = self.get_packages_by_name("name2")
2146- pkg2.upgrades += (DebUpgrades("name1", "=", "version1-release1"),)
2147- self.reload_cache() # Relink relations.
2148- self.Facade.channels_reloaded = callback
2149- self.set_pkg2_satisfied()
2150- self.set_pkg1_installed()
2151- return HASH1, HASH2
2152-
2153- def set_pkg2_satisfied(self):
2154- previous = self.Facade.channels_reloaded
2155-
2156- def callback(self):
2157- previous(self)
2158- [pkg2] = self.get_packages_by_name("name2")
2159- pkg2.requires = ()
2160- self.reload_cache() # Relink relations.
2161- self.Facade.channels_reloaded = callback
2162- return HASH2
2163-
2164- def set_pkg1_and_pkg2_satisfied(self):
2165- previous = self.Facade.channels_reloaded
2166-
2167- def callback(self):
2168- previous(self)
2169-
2170- provide1 = Provides("prerequirename1", "prerequireversion1")
2171- provide2 = Provides("requirename1", "requireversion1")
2172- [pkg2] = self.get_packages_by_name("name2")
2173- pkg2.provides += (provide1, provide2)
2174-
2175- provide1 = Provides("prerequirename2", "prerequireversion2")
2176- provide2 = Provides("requirename2", "requireversion2")
2177- [pkg1] = self.get_packages_by_name("name1")
2178- pkg1.provides += (provide1, provide2)
2179-
2180- # Ask Smart to reprocess relationships.
2181- self.reload_cache()
2182- self.Facade.channels_reloaded = callback
2183- return HASH1, HASH2
2184-
2185- def remove_pkg2(self):
2186- os.remove(os.path.join(self.repository_dir, PKGNAME2))
2187-
2188- def get_transaction_error_message(self):
2189- return "requirename1 = requireversion1"
2190-
2191- def get_binaries_channels(self, binaries_path):
2192- return {binaries_path: {"type": "deb-dir",
2193- "path": binaries_path}}
2194-
2195- def get_package_name(self, package):
2196- return package.name
2197-
2198- def test_change_package_locks(self):
2199- """
2200- The L{PackageChanger.handle_tasks} method appropriately creates and
2201- deletes package locks as requested by the C{change-package-locks}
2202- message.
2203- """
2204- self.facade.set_package_lock("bar")
2205- self.store.add_task("changer", {"type": "change-package-locks",
2206- "create": [("foo", ">=", "1.0")],
2207- "delete": [("bar", None, None)],
2208- "operation-id": 123})
2209-
2210- def assert_result(result):
2211- self.facade.deinit()
2212- self.assertEqual(self.facade.get_package_locks(),
2213- [("foo", ">=", "1.0")])
2214- self.assertIn("Queuing message with change package locks results "
2215- "to exchange urgently.", self.logfile.getvalue())
2216- self.assertMessages(self.get_pending_messages(),
2217- [{"type": "operation-result",
2218- "operation-id": 123,
2219- "status": SUCCEEDED,
2220- "result-text": "Package locks successfully"
2221- " changed.",
2222- "result-code": 0}])
2223-
2224- result = self.changer.handle_tasks()
2225- return result.addCallback(assert_result)
2226-
2227- def test_change_package_locks_create_with_already_existing(self):
2228- """
2229- The L{PackageChanger.handle_tasks} method gracefully handles requests
2230- for creating package locks that already exist.
2231- """
2232- self.facade.set_package_lock("foo")
2233- self.store.add_task("changer", {"type": "change-package-locks",
2234- "create": [("foo", None, None)],
2235- "operation-id": 123})
2236-
2237- def assert_result(result):
2238- self.facade.deinit()
2239- self.assertEqual(self.facade.get_package_locks(),
2240- [("foo", "", "")])
2241- self.assertMessages(self.get_pending_messages(),
2242- [{"type": "operation-result",
2243- "operation-id": 123,
2244- "status": SUCCEEDED,
2245- "result-text": "Package locks successfully"
2246- " changed.",
2247- "result-code": 0}])
2248-
2249- result = self.changer.handle_tasks()
2250- return result.addCallback(assert_result)
2251-
2252- def test_change_package_locks_delete_without_already_existing(self):
2253- """
2254- The L{PackageChanger.handle_tasks} method gracefully handles requests
2255- for deleting package locks that don't exist.
2256- """
2257- self.store.add_task("changer", {"type": "change-package-locks",
2258- "delete": [("foo", ">=", "1.0")],
2259- "operation-id": 123})
2260-
2261- def assert_result(result):
2262- self.facade.deinit()
2263- self.assertEqual(self.facade.get_package_locks(), [])
2264- self.assertMessages(self.get_pending_messages(),
2265- [{"type": "operation-result",
2266- "operation-id": 123,
2267- "status": SUCCEEDED,
2268- "result-text": "Package locks successfully"
2269- " changed.",
2270- "result-code": 0}])
2271-
2272- result = self.changer.handle_tasks()
2273- return result.addCallback(assert_result)
2274-
2275- def test_dpkg_error(self):
2276- """
2277- Verify that errors emitted by dpkg are correctly reported to
2278- the server as problems.
2279-
2280- This test is to make sure that Smart reports the problem
2281- correctly. It doesn't make sense for AptFacade, since there we
2282- don't call dpkg.
2283- """
2284- self.log_helper.ignore_errors(".*dpkg")
2285-
2286- installed_hash = self.set_pkg1_installed()
2287- self.store.set_hash_ids({installed_hash: 1})
2288- self.store.add_task("changer",
2289- {"type": "change-packages", "remove": [1],
2290- "operation-id": 123})
2291-
2292- result = self.changer.handle_tasks()
2293-
2294- def got_result(result):
2295- messages = self.get_pending_messages()
2296- self.assertEqual(len(messages), 1, "Too many messages")
2297- message = messages[0]
2298- self.assertEqual(message["operation-id"], 123)
2299- self.assertEqual(message["result-code"], 100)
2300- self.assertEqual(message["type"], "change-packages-result")
2301- text = message["result-text"]
2302- # We can't test the actual content of the message because the dpkg
2303- # error can be localized
2304- self.assertIn("\n[remove] name1_version1-release1\ndpkg: ", text)
2305- self.assertIn("ERROR", text)
2306- self.assertIn("(2)", text)
2307- return result.addCallback(got_result)
2308-
2309- def test_change_package_holds(self):
2310- """
2311- If C{SmartFacade} is used, the L{PackageChanger.handle_tasks}
2312- method fails the activity, since it can't add or remove dpkg holds.
2313- """
2314- self.facade.reload_channels()
2315- self.store.add_task("changer", {"type": "change-package-holds",
2316- "create": [1],
2317- "delete": [2],
2318- "operation-id": 123})
2319-
2320- def assert_result(result):
2321- self.assertIn("Queuing message with change package holds results "
2322- "to exchange urgently.", self.logfile.getvalue())
2323- self.assertMessages(
2324- self.get_pending_messages(),
2325- [{"type": "operation-result",
2326- "operation-id": 123,
2327- "status": FAILED,
2328- "result-text": "This client doesn't support package holds.",
2329- "result-code": 1}])
2330-
2331- result = self.changer.handle_tasks()
2332- return result.addCallback(assert_result)
2333-
2334- def test_global_upgrade(self):
2335- """
2336- Besides asking for individual changes, the server may also request
2337- the client to perform a global upgrade. This would be the equivalent
2338- of a "smart upgrade" command being executed in the command line.
2339-
2340- This test should be run for both C{AptFacade} and
2341- C{SmartFacade}, but due to the smart test setting up that two
2342- packages with different names upgrade each other, the message
2343- doesn't correctly report that the old version should be
2344- uninstalled. The test is still useful, since it shows that the
2345- message contains the changes that smart says are needed.
2346-
2347- Making the test totally correct is a lot of work, that is not
2348- worth doing, since we're removing smart soon.
2349- """
2350- hash1, hash2 = self.set_pkg2_upgrades_pkg1()
2351- self.store.set_hash_ids({hash1: 1, hash2: 2})
2352-
2353- self.store.add_task("changer",
2354- {"type": "change-packages", "upgrade-all": True,
2355- "operation-id": 123})
2356-
2357- result = self.changer.handle_tasks()
2358-
2359- def got_result(result):
2360- self.assertMessages(self.get_pending_messages(),
2361- [{"operation-id": 123,
2362- "must-install": [2],
2363- "result-code": 101,
2364- "type": "change-packages-result"}])
2365-
2366- return result.addCallback(got_result)
2367-
2368-
2369-class AptPackageChangerTest(LandscapeTest, PackageChangerTestMixin):
2370-
2371- if not has_new_enough_apt:
2372- skip = "Can't use AptFacade on hardy"
2373-
2374- helpers = [AptFacadeHelper, SimpleRepositoryHelper, BrokerServiceHelper]
2375-
2376- def setUp(self):
2377-
2378- def set_up(ignored):
2379-
2380- self.store = PackageStore(self.makeFile())
2381- self.config = PackageChangerConfiguration()
2382- self.config.data_path = self.makeDir()
2383- os.mkdir(self.config.package_directory)
2384- os.mkdir(self.config.binaries_path)
2385- touch_file(self.config.update_stamp_filename)
2386- self.changer = PackageChanger(
2387- self.store, self.facade, self.remote, self.config)
2388- service = self.broker_service
2389- service.message_store.set_accepted_types(["change-packages-result",
2390- "operation-result"])
2391-
2392- result = super(AptPackageChangerTest, self).setUp()
2393- return result.addCallback(set_up)
2394-
2395- def set_pkg1_installed(self):
2396- """Return the hash of a package that is installed."""
2397- self._add_system_package("foo")
2398- self.facade.reload_channels()
2399- [foo] = self.facade.get_packages_by_name("foo")
2400- return self.facade.get_package_hash(foo)
2401-
2402- def set_pkg2_satisfied(self):
2403- """Return the hash of a package that can be installed."""
2404- self._add_package_to_deb_dir(self.repository_dir, "bar")
2405- self.facade.reload_channels()
2406- [bar] = self.facade.get_packages_by_name("bar")
2407- return self.facade.get_package_hash(bar)
2408-
2409- def set_pkg1_and_pkg2_satisfied(self):
2410- """Make a package depend on another package.
2411-
2412- Return the hashes of the two packages.
2413- """
2414- self._add_package_to_deb_dir(
2415- self.repository_dir, "foo", control_fields={"Depends": "bar"})
2416- self._add_package_to_deb_dir(self.repository_dir, "bar")
2417- self.facade.reload_channels()
2418- [foo] = self.facade.get_packages_by_name("foo")
2419- [bar] = self.facade.get_packages_by_name("bar")
2420- return (
2421- self.facade.get_package_hash(foo),
2422- self.facade.get_package_hash(bar))
2423-
2424- def set_pkg2_upgrades_pkg1(self):
2425- """Make it so that one package upgrades another.
2426-
2427- Return the hashes of the two packages.
2428- """
2429- self._add_system_package("foo", version="1.0")
2430- self._add_package_to_deb_dir(self.repository_dir, "foo", version="2.0")
2431- self.facade.reload_channels()
2432- foo_1, foo_2 = sorted(self.facade.get_packages_by_name("foo"))
2433- return (
2434- self.facade.get_package_hash(foo_1),
2435- self.facade.get_package_hash(foo_2))
2436-
2437- def remove_pkg2(self):
2438- """Remove package name2 from its repository."""
2439- packages_file = os.path.join(self.repository_dir, "Packages")
2440- packages_contents = read_file(packages_file)
2441- packages_contents = "\n\n".join(
2442- [stanza for stanza in packages_contents.split("\n\n")
2443- if "Package: name2" not in stanza])
2444- create_file(packages_file, packages_contents)
2445-
2446- def get_transaction_error_message(self):
2447- """Return part of the apt transaction error message."""
2448- return "Unable to correct problems"
2449-
2450- def get_binaries_channels(self, binaries_path):
2451- """Return the channels that will be used for the binaries."""
2452- return [{"baseurl": "file://%s" % binaries_path,
2453- "components": "",
2454- "distribution": "./",
2455- "type": "deb"}]
2456-
2457- def get_package_name(self, version):
2458- """Return the name of the package."""
2459- return version.package.name
2460-
2461 def test_binaries_available_in_cache(self):
2462 """
2463 If binaries are included in the changes-packages message, those
2464@@ -1275,7 +976,7 @@
2465 def test_change_package_holds(self):
2466 """
2467 The L{PackageChanger.handle_tasks} method appropriately creates and
2468- deletes package holds as requested by the C{change-package-holds}
2469+ deletes package holds as requested by the C{change-packages}
2470 message.
2471 """
2472 self._add_system_package("foo")
2473@@ -1292,23 +993,22 @@
2474 old_mtime = time.time() - 10
2475 os.utime(self.facade._dpkg_status, (old_mtime, old_mtime))
2476 self.facade.reload_channels()
2477- self.store.add_task("changer", {"type": "change-package-holds",
2478- "create": [foo.package.id],
2479- "delete": [bar.package.id],
2480+ self.store.add_task("changer", {"type": "change-packages",
2481+ "hold": [foo.package.id],
2482+ "remove-hold": [bar.package.id],
2483 "operation-id": 123})
2484
2485 def assert_result(result):
2486 self.facade.reload_channels()
2487 self.assertEqual(["foo"], self.facade.get_package_holds())
2488- self.assertIn("Queuing message with change package holds results "
2489+ self.assertIn("Queuing response with change package results "
2490 "to exchange urgently.", self.logfile.getvalue())
2491 self.assertMessages(
2492 self.get_pending_messages(),
2493- [{"type": "operation-result",
2494+ [{"type": "change-packages-result",
2495 "operation-id": 123,
2496- "status": SUCCEEDED,
2497 "result-text": "Package holds successfully changed.",
2498- "result-code": 0}])
2499+ "result-code": 1}])
2500
2501 result = self.changer.handle_tasks()
2502 return result.addCallback(assert_result)
2503@@ -1316,7 +1016,7 @@
2504 def test_create_package_holds_with_identical_version(self):
2505 """
2506 The L{PackageChanger.handle_tasks} method appropriately creates
2507- holds as requested by the C{change-package-holds} message even
2508+ holds as requested by the C{change-packages} message even
2509 when versions from two different packages are the same.
2510 """
2511 self._add_system_package("foo", version="1.1")
2512@@ -1327,12 +1027,13 @@
2513 [foo] = self.facade.get_packages_by_name("foo")
2514 [bar] = self.facade.get_packages_by_name("bar")
2515 self.facade.reload_channels()
2516- self.store.add_task("changer", {"type": "change-package-holds",
2517- "create": [foo.package.id,
2518- bar.package.id],
2519+ self.store.add_task("changer", {"type": "change-packages",
2520+ "hold": [foo.package.id,
2521+ bar.package.id],
2522 "operation-id": 123})
2523
2524 def assert_result(result):
2525+ self.facade.reload_channels()
2526 self.assertEqual(["foo", "bar"], self.facade.get_package_holds())
2527
2528 result = self.changer.handle_tasks()
2529@@ -1341,7 +1042,7 @@
2530 def test_delete_package_holds_with_identical_version(self):
2531 """
2532 The L{PackageChanger.handle_tasks} method appropriately deletes
2533- holds as requested by the C{change-package-holds} message even
2534+ holds as requested by the C{change-packages} message even
2535 when versions from two different packages are the same.
2536 """
2537 self._add_system_package("foo", version="1.1")
2538@@ -1354,12 +1055,13 @@
2539 self.facade.set_package_hold(foo)
2540 self.facade.set_package_hold(bar)
2541 self.facade.reload_channels()
2542- self.store.add_task("changer", {"type": "change-package-holds",
2543- "delete": [foo.package.id,
2544- bar.package.id],
2545+ self.store.add_task("changer", {"type": "change-packages",
2546+ "remove-hold": [foo.package.id,
2547+ bar.package.id],
2548 "operation-id": 123})
2549
2550 def assert_result(result):
2551+ self.facade.reload_channels()
2552 self.assertEqual([], self.facade.get_package_holds())
2553
2554 result = self.changer.handle_tasks()
2555@@ -1367,7 +1069,7 @@
2556
2557 def test_change_package_holds_create_already_held(self):
2558 """
2559- If the C{change-package-holds} message requests to add holds for
2560+ If the C{change-packages} message requests to add holds for
2561 packages that are already held, the activity succeeds, since the
2562 end result is that the requested package holds are there.
2563 """
2564@@ -1377,29 +1079,28 @@
2565 [foo] = self.facade.get_packages_by_name("foo")
2566 self.facade.set_package_hold(foo)
2567 self.facade.reload_channels()
2568- self.store.add_task("changer", {"type": "change-package-holds",
2569- "create": [foo.package.id],
2570+ self.store.add_task("changer", {"type": "change-packages",
2571+ "hold": [foo.package.id],
2572 "operation-id": 123})
2573
2574 def assert_result(result):
2575 self.facade.reload_channels()
2576 self.assertEqual(["foo"], self.facade.get_package_holds())
2577- self.assertIn("Queuing message with change package holds results "
2578+ self.assertIn("Queuing response with change package results "
2579 "to exchange urgently.", self.logfile.getvalue())
2580 self.assertMessages(
2581 self.get_pending_messages(),
2582- [{"type": "operation-result",
2583+ [{"type": "change-packages-result",
2584 "operation-id": 123,
2585- "status": SUCCEEDED,
2586 "result-text": "Package holds successfully changed.",
2587- "result-code": 0}])
2588+ "result-code": 1}])
2589
2590 result = self.changer.handle_tasks()
2591 return result.addCallback(assert_result)
2592
2593 def test_change_package_holds_create_other_version_installed(self):
2594 """
2595- If the C{change-package-holds} message requests to add holds for
2596+ If the C{change-packages} message requests to add holds for
2597 packages that have a different version installed than the one
2598 being requested to hold, the activity fails.
2599
2600@@ -1420,30 +1121,29 @@
2601 self.facade.get_package_hash(bar1): 3,
2602 self.facade.get_package_hash(bar2): 4})
2603 self.facade.reload_channels()
2604- self.store.add_task("changer", {"type": "change-package-holds",
2605- "create": [2, 3],
2606+ self.store.add_task("changer", {"type": "change-packages",
2607+ "hold": [2, 3],
2608 "operation-id": 123})
2609
2610 def assert_result(result):
2611 self.facade.reload_channels()
2612 self.assertEqual([], self.facade.get_package_holds())
2613- self.assertIn("Queuing message with change package holds results "
2614+ self.assertIn("Queuing response with change package results "
2615 "to exchange urgently.", self.logfile.getvalue())
2616 self.assertMessages(
2617 self.get_pending_messages(),
2618- [{"type": "operation-result",
2619+ [{"type": "change-packages-result",
2620 "operation-id": 123,
2621- "status": FAILED,
2622- "result-text": "Package holds not changed, since the" +
2623- " following packages are not installed: 2",
2624- "result-code": 1}])
2625+ "result-text": "Cannot perform the changes, since the" +
2626+ " following packages are not installed: foo",
2627+ "result-code": 100}])
2628
2629 result = self.changer.handle_tasks()
2630 return result.addCallback(assert_result)
2631
2632 def test_change_package_holds_create_not_installed(self):
2633 """
2634- If the C{change-package-holds} message requests to add holds for
2635+ If the C{change-packages} message requests to add holds for
2636 packages that aren't installed, the whole activity is failed. If
2637 multiple holds are specified, those won't be added. There's no
2638 difference between a package that is available in some
2639@@ -1460,62 +1160,71 @@
2640 [foo] = self.facade.get_packages_by_name("foo")
2641 [bar] = self.facade.get_packages_by_name("bar")
2642 [baz] = self.facade.get_packages_by_name("baz")
2643- self.store.add_task("changer", {"type": "change-package-holds",
2644- "create": [foo.package.id,
2645- bar.package.id,
2646- baz.package.id],
2647+ self.store.add_task("changer", {"type": "change-packages",
2648+ "hold": [foo.package.id,
2649+ bar.package.id,
2650+ baz.package.id],
2651 "operation-id": 123})
2652
2653 def assert_result(result):
2654 self.facade.reload_channels()
2655 self.assertEqual([], self.facade.get_package_holds())
2656- self.assertIn("Queuing message with change package holds results "
2657+ self.assertIn("Queuing response with change package results "
2658 "to exchange urgently.", self.logfile.getvalue())
2659 self.assertMessages(
2660 self.get_pending_messages(),
2661- [{"type": "operation-result",
2662+ [{"type": "change-packages-result",
2663 "operation-id": 123,
2664- "status": FAILED,
2665- "result-text": "Package holds not changed, since the "
2666+ "result-text": "Cannot perform the changes, since the "
2667 "following packages are not installed: "
2668- "%s, %s" % tuple(sorted([bar.package.id,
2669- baz.package.id])),
2670- "result-code": 1}])
2671+ "%s, %s" % tuple(sorted([bar.package.name,
2672+ baz.package.name])),
2673+ "result-code": 100}])
2674
2675 result = self.changer.handle_tasks()
2676 return result.addCallback(assert_result)
2677
2678 def test_change_package_holds_create_unknown_hash(self):
2679 """
2680- If the C{change-package-holds} message requests to add holds for
2681- packages that the client doesn't know about, it's being treated
2682- as the packages not being installed.
2683+ If the C{change-packages} message requests to add holds for
2684+ packages that the client doesn't know about results in a not yet
2685+ synchronized message and a failure of the operation.
2686 """
2687- self.facade.reload_channels()
2688- self.store.add_task("changer", {"type": "change-package-holds",
2689- "create": [1],
2690- "operation-id": 123})
2691-
2692- def assert_result(result):
2693- self.facade.reload_channels()
2694- self.assertEqual([], self.facade.get_package_holds())
2695- self.assertIn("Queuing message with change package holds results "
2696- "to exchange urgently.", self.logfile.getvalue())
2697- self.assertMessages(
2698- self.get_pending_messages(),
2699- [{"type": "operation-result",
2700- "operation-id": 123,
2701- "status": FAILED,
2702- "result-text": "Package holds not changed, since the" +
2703- " following packages are not installed: 1",
2704- "result-code": 1}])
2705-
2706- result = self.changer.handle_tasks()
2707- return result.addCallback(assert_result)
2708+
2709+ self.store.add_task("changer",
2710+ {"type": "change-packages",
2711+ "hold": [123],
2712+ "operation-id": 123})
2713+
2714+ time_mock = self.mocker.replace("time.time")
2715+ time_mock()
2716+ self.mocker.result(time.time() + UNKNOWN_PACKAGE_DATA_TIMEOUT)
2717+ self.mocker.count(1, None)
2718+ self.mocker.replay()
2719+
2720+ try:
2721+ result = self.changer.handle_tasks()
2722+ self.mocker.verify()
2723+ finally:
2724+ # Reset it earlier so that Twisted has the true time function.
2725+ self.mocker.reset()
2726+
2727+ self.assertIn("Package data not yet synchronized with server (123)",
2728+ self.logfile.getvalue())
2729+
2730+ def got_result(result):
2731+ message = {"type": "change-packages-result",
2732+ "operation-id": 123,
2733+ "result-code": 100,
2734+ "result-text": "Package data has changed. "
2735+ "Please retry the operation."}
2736+ self.assertMessages(self.get_pending_messages(), [message])
2737+ self.assertEqual(self.store.get_next_task("changer"), None)
2738+ return result.addCallback(got_result)
2739
2740 def test_change_package_holds_delete_not_held(self):
2741 """
2742- If the C{change-package-holds} message requests to remove holds
2743+ If the C{change-packages} message requests to remove holds
2744 for packages that aren't held, the activity succeeds if the
2745 right version is installed, since the end result is that the
2746 hold is removed.
2747@@ -1524,29 +1233,28 @@
2748 self.facade.reload_channels()
2749 self._hash_packages_by_name(self.facade, self.store, "foo")
2750 [foo] = self.facade.get_packages_by_name("foo")
2751- self.store.add_task("changer", {"type": "change-package-holds",
2752- "delete": [foo.package.id],
2753+ self.store.add_task("changer", {"type": "change-packages",
2754+ "remove-hold": [foo.package.id],
2755 "operation-id": 123})
2756
2757 def assert_result(result):
2758 self.facade.reload_channels()
2759 self.assertEqual([], self.facade.get_package_holds())
2760- self.assertIn("Queuing message with change package holds results "
2761+ self.assertIn("Queuing response with change package results "
2762 "to exchange urgently.", self.logfile.getvalue())
2763 self.assertMessages(
2764 self.get_pending_messages(),
2765- [{"type": "operation-result",
2766+ [{"type": "change-packages-result",
2767 "operation-id": 123,
2768- "status": SUCCEEDED,
2769 "result-text": "Package holds successfully changed.",
2770- "result-code": 0}])
2771+ "result-code": 1}])
2772
2773 result = self.changer.handle_tasks()
2774 return result.addCallback(assert_result)
2775
2776 def test_change_package_holds_delete_different_version_held(self):
2777 """
2778- If the C{change-package-holds} message requests to remove holds
2779+ If the C{change-packages} message requests to remove holds
2780 for packages that aren't held, the activity succeeds if the
2781 right version is installed, since the end result is that the
2782 hold is removed.
2783@@ -1556,60 +1264,34 @@
2784 self.repository_dir, "foo", version="2.0")
2785 self.facade.reload_channels()
2786 [foo1, foo2] = sorted(self.facade.get_packages_by_name("foo"))
2787- self.facade.set_package_hold(foo1)
2788 self.store.set_hash_ids({self.facade.get_package_hash(foo1): 1,
2789 self.facade.get_package_hash(foo2): 2})
2790+ self.facade.mark_install(foo1)
2791+ self.facade.mark_hold(foo1)
2792+ self.facade.perform_changes()
2793 self.facade.reload_channels()
2794- self.store.add_task("changer", {"type": "change-package-holds",
2795- "delete": [2],
2796+ self.store.add_task("changer", {"type": "change-packages",
2797+ "remove-hold": [2],
2798 "operation-id": 123})
2799
2800 def assert_result(result):
2801 self.facade.reload_channels()
2802 self.assertEqual(["foo"], self.facade.get_package_holds())
2803- self.assertIn("Queuing message with change package holds results "
2804- "to exchange urgently.", self.logfile.getvalue())
2805- self.assertMessages(
2806- self.get_pending_messages(),
2807- [{"type": "operation-result",
2808- "operation-id": 123,
2809- "status": SUCCEEDED,
2810- "result-text": "Package holds successfully changed.",
2811- "result-code": 0}])
2812-
2813- result = self.changer.handle_tasks()
2814- return result.addCallback(assert_result)
2815-
2816- def test_change_package_holds_delete_unknown_hash(self):
2817- """
2818- If the C{change-package-holds} message requests to remove holds
2819- for packages that aren't known by the client, the activity
2820- succeeds, since the end result is that the package isn't
2821- held at that version.
2822- """
2823- self.store.add_task("changer", {"type": "change-package-holds",
2824- "delete": [1],
2825- "operation-id": 123})
2826-
2827- def assert_result(result):
2828- self.facade.reload_channels()
2829- self.assertEqual([], self.facade.get_package_holds())
2830- self.assertIn("Queuing message with change package holds results "
2831- "to exchange urgently.", self.logfile.getvalue())
2832- self.assertMessages(
2833- self.get_pending_messages(),
2834- [{"type": "operation-result",
2835- "operation-id": 123,
2836- "status": SUCCEEDED,
2837- "result-text": "Package holds successfully changed.",
2838- "result-code": 0}])
2839+ self.assertIn("Queuing response with change package results "
2840+ "to exchange urgently.", self.logfile.getvalue())
2841+ self.assertMessages(
2842+ self.get_pending_messages(),
2843+ [{"type": "change-packages-result",
2844+ "operation-id": 123,
2845+ "result-text": "Package holds successfully changed.",
2846+ "result-code": 1}])
2847
2848 result = self.changer.handle_tasks()
2849 return result.addCallback(assert_result)
2850
2851 def test_change_package_holds_delete_not_installed(self):
2852 """
2853- If the C{change-package-holds} message requests to remove holds
2854+ If the C{change-packages} message requests to remove holds
2855 for packages that aren't installed, the activity succeeds, since
2856 the end result is still that the package isn't held at the
2857 requested version.
2858@@ -1618,31 +1300,30 @@
2859 self.facade.reload_channels()
2860 self._hash_packages_by_name(self.facade, self.store, "foo")
2861 [foo] = self.facade.get_packages_by_name("foo")
2862- self.store.add_task("changer", {"type": "change-package-holds",
2863- "delete": [foo.package.id],
2864+ self.store.add_task("changer", {"type": "change-packages",
2865+ "remove-hold": [foo.package.id],
2866 "operation-id": 123})
2867
2868 def assert_result(result):
2869 self.facade.reload_channels()
2870 self.assertEqual([], self.facade.get_package_holds())
2871- self.assertIn("Queuing message with change package holds results "
2872+ self.assertIn("Queuing response with change package results "
2873 "to exchange urgently.", self.logfile.getvalue())
2874 self.assertMessages(
2875 self.get_pending_messages(),
2876- [{"type": "operation-result",
2877+ [{"type": "change-packages-result",
2878 "operation-id": 123,
2879- "status": SUCCEEDED,
2880 "result-text": "Package holds successfully changed.",
2881- "result-code": 0}])
2882+ "result-code": 1}])
2883
2884 result = self.changer.handle_tasks()
2885 return result.addCallback(assert_result)
2886
2887 def test_change_package_locks(self):
2888 """
2889- If C{AptFacade} is used, the L{PackageChanger.handle_tasks}
2890- method fails the activity, since it can't add or remove locks because
2891- apt doesn't support this.
2892+ The L{PackageChanger.handle_tasks} method fails
2893+ change-package-locks activities, since it can't add or remove
2894+ locks because apt doesn't support this.
2895 """
2896 self.store.add_task("changer", {"type": "change-package-locks",
2897 "create": [("foo", ">=", "1.0")],
2898
2899=== modified file 'landscape/package/tests/test_facade.py'
2900--- landscape/package/tests/test_facade.py 2012-03-21 16:15:49 +0000
2901+++ landscape/package/tests/test_facade.py 2012-06-04 14:08:28 +0000
2902@@ -1,40 +1,22 @@
2903-import time
2904 import os
2905-import re
2906-import sys
2907 import textwrap
2908 import tempfile
2909
2910-try:
2911- import smart
2912- from smart.control import Control
2913- from smart.cache import Provides
2914- from smart.const import NEVER, ALWAYS
2915-except ImportError:
2916- # Smart is optional if AptFacade is being used.
2917- pass
2918-
2919 import apt_pkg
2920 from apt.package import Package
2921 from aptsources.sourceslist import SourcesList
2922
2923-from twisted.internet import reactor
2924-from twisted.internet.defer import Deferred
2925-from twisted.internet.utils import getProcessOutputAndValue
2926-
2927 from landscape.constants import UBUNTU_PATH
2928 from landscape.lib.fs import read_file, create_file
2929-from landscape.package import facade as facade_module
2930 from landscape.package.facade import (
2931- TransactionError, DependencyError, ChannelError, SmartError, AptFacade,
2932- has_new_enough_apt)
2933+ TransactionError, DependencyError, ChannelError, AptFacade)
2934
2935 from landscape.tests.mocker import ANY
2936 from landscape.tests.helpers import LandscapeTest, EnvironSaverHelper
2937 from landscape.package.tests.helpers import (
2938- SmartFacadeHelper, HASH1, HASH2, HASH3, PKGNAME1, PKGNAME2, PKGNAME3,
2939- PKGNAME4, PKGDEB4, PKGDEB1, PKGNAME_MINIMAL, PKGDEB_MINIMAL,
2940- create_full_repository, create_deb, AptFacadeHelper,
2941+ HASH1, HASH2, HASH3, PKGNAME1, PKGNAME2, PKGNAME3,
2942+ PKGDEB1, PKGNAME_MINIMAL, PKGDEB_MINIMAL,
2943+ create_deb, AptFacadeHelper,
2944 create_simple_repository)
2945
2946
2947@@ -60,9 +42,6 @@
2948
2949 class AptFacadeTest(LandscapeTest):
2950
2951- if not has_new_enough_apt:
2952- skip = "Can't use AptFacade on hardy"
2953-
2954 helpers = [AptFacadeHelper, EnvironSaverHelper]
2955
2956 def version_sortkey(self, version):
2957@@ -1564,16 +1543,24 @@
2958 self._add_package_to_deb_dir(deb_dir, "bar", version="1.5")
2959 self._add_system_package("baz")
2960 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")
2961+ self._add_system_package("quux", version="1.0")
2962+ self._add_system_package("wibble", version="1.0")
2963 self.facade.reload_channels()
2964 [foo] = self.facade.get_packages_by_name("foo")
2965 self.facade.mark_install(foo)
2966 self.facade.mark_global_upgrade()
2967 [baz] = self.facade.get_packages_by_name("baz")
2968 self.facade.mark_remove(baz)
2969+ [quux] = self.facade.get_packages_by_name("quux")
2970+ self.facade.mark_hold(quux)
2971+ [wibble] = self.facade.get_packages_by_name("wibble")
2972+ self.facade.mark_remove_hold(wibble)
2973 self.facade.reset_marks()
2974 self.assertEqual(self.facade._version_installs, [])
2975 self.assertEqual(self.facade._version_removals, [])
2976 self.assertFalse(self.facade._global_upgrade)
2977+ self.assertEqual(self.facade._version_hold_creations, [])
2978+ self.assertEqual(self.facade._version_hold_removals, [])
2979 self.assertEqual(self.facade.perform_changes(), None)
2980
2981 def test_reset_marks_resets_cache(self):
2982@@ -2349,50 +2336,81 @@
2983 self.assertEqual(
2984 ["baz", "foo"], sorted(self.facade.get_package_holds()))
2985
2986- def test_set_package_hold(self):
2987- """
2988- C{set_package_hold} marks a package to be on hold.
2989- """
2990- self._add_system_package("foo")
2991- self.facade.reload_channels()
2992- [foo] = self.facade.get_packages_by_name("foo")
2993- self.facade.set_package_hold(foo)
2994- self.facade.reload_channels()
2995-
2996- self.assertEqual(["foo"], self.facade.get_package_holds())
2997-
2998- def test_set_package_hold_existing_hold(self):
2999- """
3000- If a package is already hel, C{set_package_hold} doesn't return
3001- an error.
3002- """
3003- self._add_system_package(
3004- "foo", control_fields={"Status": "hold ok installed"})
3005- self.facade.reload_channels()
3006- [foo] = self.facade.get_packages_by_name("foo")
3007- self.facade.set_package_hold(foo)
3008- self.facade.reload_channels()
3009-
3010- self.assertEqual(["foo"], self.facade.get_package_holds())
3011-
3012- def test_remove_package_hold(self):
3013- """
3014- C{remove_package_hold} marks a package not to be on hold.
3015- """
3016- self._add_system_package(
3017- "foo", control_fields={"Status": "hold ok installed"})
3018- self.facade.reload_channels()
3019- [foo] = self.facade.get_packages_by_name("foo")
3020- self.facade.remove_package_hold(foo)
3021+ def test_mark_hold_and_perform_hold_changes(self):
3022+ """
3023+ Test that L{perform_hold_changes} holds packages that have previously
3024+ been marked for hold.
3025+ """
3026+ self._add_system_package("foo")
3027+ self.facade.reload_channels()
3028+ [foo] = self.facade.get_packages_by_name("foo")
3029+ self.facade.mark_hold(foo)
3030+ self.assertEqual("Package holds successfully changed.",
3031+ self.facade._perform_hold_changes())
3032+ self.facade.reload_channels()
3033+ self.assertEqual(["foo"], self.facade.get_package_holds())
3034+
3035+ def test_mark_hold(self):
3036+ """
3037+ C{mark_hold} marks a package to be held.
3038+ """
3039+ self._add_system_package("foo")
3040+ self.facade.reload_channels()
3041+ [foo] = self.facade.get_packages_by_name("foo")
3042+ self.facade.mark_hold(foo)
3043+ self.facade.perform_changes()
3044+ self.facade.reload_channels()
3045+ self.assertEqual(["foo"], self.facade.get_package_holds())
3046+
3047+ def test_two_holds_with_the_same_version_id(self):
3048+ """
3049+ Test C{mark_hold} can distinguish between two different packages with
3050+ the same version number (the version number is used to make the unique
3051+ hash for the package version).
3052+ """
3053+ self._add_system_package("foo", version="1.0")
3054+ self._add_system_package("bar", version="1.0")
3055+ self.facade.reload_channels()
3056+ [foo] = self.facade.get_packages_by_name("foo")
3057+ [bar] = self.facade.get_packages_by_name("bar")
3058+ self.facade.mark_hold(foo)
3059+ self.facade.mark_hold(bar)
3060+ self.assertEqual(2, len(self.facade._version_hold_creations))
3061+
3062+ def test_mark_hold_existing_hold(self):
3063+ """
3064+ If a package is already held, C{mark_hold} and
3065+ C{perform_changes} won't return an error.
3066+ """
3067+ self._add_system_package(
3068+ "foo", control_fields={"Status": "hold ok installed"})
3069+ self.facade.reload_channels()
3070+ [foo] = self.facade.get_packages_by_name("foo")
3071+ self.facade.mark_hold(foo)
3072+ self.facade.perform_changes()
3073+ self.facade.reload_channels()
3074+
3075+ self.assertEqual(["foo"], self.facade.get_package_holds())
3076+
3077+ def test_mark_remove_hold(self):
3078+ """
3079+ C{mark_remove_hold} marks a package as not held.
3080+ """
3081+ self._add_system_package(
3082+ "foo", control_fields={"Status": "hold ok installed"})
3083+ self.facade.reload_channels()
3084+ [foo] = self.facade.get_packages_by_name("foo")
3085+ self.facade.mark_remove_hold(foo)
3086+ self.facade.perform_changes()
3087 self.facade.reload_channels()
3088
3089 self.assertEqual([], self.facade.get_package_holds())
3090
3091- def test_remove_package_hold_no_package(self):
3092+ def test_mark_remove_hold_no_package(self):
3093 """
3094- If a package doesn't exist, C{remove_package_hold} doesn't
3095- return an error. It's up to the caller to make sure that the
3096- package exist, if it's important.
3097+ If a package doesn't exist, C{mark_remove_hold} followed by
3098+ C{perform_changes} doesn't return an error. It's up to the caller to
3099+ make sure that the package exist, if it's important.
3100 """
3101 self._add_system_package("foo")
3102 deb_dir = self.makeDir()
3103@@ -2400,21 +2418,23 @@
3104 self.facade.add_channel_apt_deb("file://%s" % deb_dir, "./")
3105 self.facade.reload_channels()
3106 [bar] = self.facade.get_packages_by_name("bar")
3107- self.facade.remove_package_hold(bar)
3108+ self.facade.mark_remove_hold(bar)
3109+ self.facade.perform_changes()
3110 self.facade.reload_channels()
3111
3112 self.assertEqual([], self.facade.get_package_holds())
3113
3114- def test_remove_package_hold_no_hold(self):
3115+ def test_mark_remove_hold_no_hold(self):
3116 """
3117 If a package isn't held, the existing selection is retained when
3118- C{remove_package_hold} is called.
3119+ C{mark_remove_hold} and C{perform_changes} are called.
3120 """
3121 self._add_system_package(
3122 "foo", control_fields={"Status": "deinstall ok installed"})
3123 self.facade.reload_channels()
3124 [foo] = self.facade.get_packages_by_name("foo")
3125- self.facade.remove_package_hold(foo)
3126+ self.facade.mark_remove_hold(foo)
3127+ self.facade.perform_changes()
3128 self.facade.reload_channels()
3129
3130 self.assertEqual([], self.facade.get_package_holds())
3131@@ -2430,670 +2450,3 @@
3132 test_wb_mark_install_upgrade_non_main_arch_dependency_error.skip = (
3133 skip_message)
3134 test_wb_mark_install_upgrade_non_main_arch.skip = skip_message
3135-
3136-
3137-class SmartFacadeTest(LandscapeTest):
3138-
3139- helpers = [SmartFacadeHelper]
3140-
3141- def test_needs_smart(self):
3142- """
3143- If the Smart python modules can't be imported, a C{RuntimeError}
3144- is raised when trying to create a C{SmartFacade}.
3145- """
3146-
3147- def reset_has_smart():
3148- facade_module.has_smart = old_has_smart
3149-
3150- self.addCleanup(reset_has_smart)
3151- old_has_smart = facade_module.has_smart
3152- facade_module.has_smart = False
3153-
3154- self.assertRaises(RuntimeError, self.Facade)
3155-
3156- def test_get_packages(self):
3157- self.facade.reload_channels()
3158- pkgs = self.facade.get_packages()
3159- self.assertEqual(sorted(pkg.name for pkg in pkgs),
3160- ["name1", "name2", "name3"])
3161-
3162- def test_get_packages_wont_return_non_debian_packages(self):
3163- self.facade.reload_channels()
3164- ctrl_mock = self.mocker.patch(Control)
3165-
3166- class StubPackage(object):
3167- pass
3168-
3169- cache_mock = ctrl_mock.getCache()
3170- cache_mock.getPackages()
3171- self.mocker.result([StubPackage(), StubPackage()])
3172- self.mocker.replay()
3173- self.assertEqual(self.facade.get_packages(), [])
3174-
3175- def test_get_packages_by_name(self):
3176- self.facade.reload_channels()
3177- pkgs = self.facade.get_packages_by_name("name1")
3178- self.assertEqual([pkg.name for pkg in pkgs], ["name1"])
3179- pkgs = self.facade.get_packages_by_name("name2")
3180- self.assertEqual([pkg.name for pkg in pkgs], ["name2"])
3181-
3182- def test_get_packages_by_name_wont_return_non_debian_packages(self):
3183- self.facade.reload_channels()
3184- ctrl_mock = self.mocker.patch(Control)
3185-
3186- class StubPackage(object):
3187- pass
3188-
3189- cache_mock = ctrl_mock.getCache()
3190- cache_mock.getPackages("name")
3191- self.mocker.result([StubPackage(), StubPackage()])
3192- self.mocker.replay()
3193- self.assertEqual(self.facade.get_packages_by_name("name"), [])
3194-
3195- def test_get_package_skeleton(self):
3196- self.facade.reload_channels()
3197- [pkg1] = self.facade.get_packages_by_name("name1")
3198- [pkg2] = self.facade.get_packages_by_name("name2")
3199- skeleton1 = self.facade.get_package_skeleton(pkg1)
3200- skeleton2 = self.facade.get_package_skeleton(pkg2)
3201- self.assertEqual(skeleton1.get_hash(), HASH1)
3202- self.assertEqual(skeleton2.get_hash(), HASH2)
3203-
3204- def test_build_skeleton_with_info(self):
3205- self.facade.reload_channels()
3206- [pkg] = self.facade.get_packages_by_name("name1")
3207- skeleton = self.facade.get_package_skeleton(pkg, True)
3208- self.assertEqual(skeleton.section, "Group1")
3209- self.assertEqual(skeleton.summary, "Summary1")
3210- self.assertEqual(skeleton.description, "Description1")
3211- self.assertEqual(skeleton.size, 1038)
3212- self.assertEqual(skeleton.installed_size, 28672)
3213-
3214- def test_get_package_hash(self):
3215- self.facade.reload_channels()
3216- [pkg] = self.facade.get_packages_by_name("name1")
3217- self.assertEqual(self.facade.get_package_hash(pkg), HASH1)
3218- [pkg] = self.facade.get_packages_by_name("name2")
3219- self.assertEqual(self.facade.get_package_hash(pkg), HASH2)
3220-
3221- def test_get_package_hashes(self):
3222- self.facade.reload_channels()
3223- hashes = self.facade.get_package_hashes()
3224- self.assertEqual(sorted(hashes), sorted([HASH1, HASH2, HASH3]))
3225-
3226- def test_get_package_by_hash(self):
3227- self.facade.reload_channels()
3228- pkg = self.facade.get_package_by_hash(HASH1)
3229- self.assertEqual(pkg.name, "name1")
3230- pkg = self.facade.get_package_by_hash(HASH2)
3231- self.assertEqual(pkg.name, "name2")
3232- pkg = self.facade.get_package_by_hash("none")
3233- self.assertEqual(pkg, None)
3234-
3235- def test_reload_channels_clears_hash_cache(self):
3236- # Load hashes.
3237- self.facade.reload_channels()
3238-
3239- # Hold a reference to packages.
3240- [pkg1] = self.facade.get_packages_by_name("name1")
3241- [pkg2] = self.facade.get_packages_by_name("name2")
3242- [pkg3] = self.facade.get_packages_by_name("name3")
3243- self.assertTrue(pkg1 and pkg2)
3244-
3245- # Remove the package from the repository.
3246- os.unlink(os.path.join(self.repository_dir, PKGNAME1))
3247-
3248- # Forcibly change the mtime of our repository, so that Smart
3249- # will consider it as changed (if the change is inside the
3250- # same second the directory's mtime will be the same)
3251- mtime = int(time.time() + 1)
3252- os.utime(self.repository_dir, (mtime, mtime))
3253-
3254- # Reload channels.
3255- self.facade.reload_channels()
3256-
3257- # Only packages with name2 and name3 should be loaded, and they're
3258- # not the same objects anymore.
3259- self.assertEqual(
3260- sorted([pkg.name for pkg in self.facade.get_packages()]),
3261- ["name2", "name3"])
3262- self.assertNotEquals(set(self.facade.get_packages()),
3263- set([pkg2, pkg3]))
3264-
3265- # The hash cache shouldn't include either of the old packages.
3266- self.assertEqual(self.facade.get_package_hash(pkg1), None)
3267- self.assertEqual(self.facade.get_package_hash(pkg2), None)
3268- self.assertEqual(self.facade.get_package_hash(pkg3), None)
3269-
3270- # Also, the hash for package1 shouldn't be present at all.
3271- self.assertEqual(self.facade.get_package_by_hash(HASH1), None)
3272-
3273- # While HASH2 and HASH3 should point to the new packages.
3274- new_pkgs = self.facade.get_packages()
3275- self.assertTrue(self.facade.get_package_by_hash(HASH2)
3276- in new_pkgs)
3277- self.assertTrue(self.facade.get_package_by_hash(HASH3)
3278- in new_pkgs)
3279-
3280- # Which are not the old packages.
3281- self.assertFalse(pkg2 in new_pkgs)
3282- self.assertFalse(pkg3 in new_pkgs)
3283-
3284- def test_ensure_reload_channels(self):
3285- """
3286- The L{SmartFacade.ensure_channels_reloaded} can be called more
3287- than once, but channels will be reloaded only the first time.
3288- """
3289- self.assertEqual(len(self.facade.get_packages()), 0)
3290- self.facade.ensure_channels_reloaded()
3291- self.assertEqual(len(self.facade.get_packages()), 3)
3292-
3293- # Calling it once more won't reload channels again.
3294- self.facade.get_packages_by_name("name1")[0].installed = True
3295- self.facade.ensure_channels_reloaded()
3296- self.assertTrue(self.facade.get_packages_by_name("name1")[0].installed)
3297-
3298- def test_perform_changes_with_nothing_to_do(self):
3299- """perform_changes() should return None when there's nothing to do.
3300- """
3301- self.facade.reload_channels()
3302- self.assertEqual(self.facade.perform_changes(), None)
3303-
3304- def test_reset_marks(self):
3305- """perform_changes() should return None when there's nothing to do.
3306- """
3307- self.facade.reload_channels()
3308- [pkg] = self.facade.get_packages_by_name("name1")
3309- self.facade.mark_install(pkg)
3310- self.facade.reset_marks()
3311- self.assertEqual(self.facade.perform_changes(), None)
3312-
3313- def test_mark_install_transaction_error(self):
3314- """
3315- Mark package 'name1' for installation, and try to perform changes.
3316- It should fail because 'name1' depends on 'requirename1'.
3317- """
3318- self.facade.reload_channels()
3319-
3320- [pkg] = self.facade.get_packages_by_name("name1")
3321- self.facade.mark_install(pkg)
3322- exception = self.assertRaises(TransactionError,
3323- self.facade.perform_changes)
3324- self.assertIn("requirename", exception.args[0])
3325-
3326- def test_mark_install_dependency_error(self):
3327- """
3328- Now we artificially inject the needed dependencies of 'name1'
3329- in 'name2', but we don't mark 'name2' for installation, and
3330- that should make perform_changes() fail with a dependency
3331- error on the needed package.
3332- """
3333- self.facade.reload_channels()
3334-
3335- provide1 = Provides("prerequirename1", "prerequireversion1")
3336- provide2 = Provides("requirename1", "requireversion1")
3337- [pkg2] = self.facade.get_packages_by_name("name2")
3338- pkg2.provides += (provide1, provide2)
3339-
3340- # We have to satisfy *both* packages.
3341- provide1 = Provides("prerequirename2", "prerequireversion2")
3342- provide2 = Provides("requirename2", "requireversion2")
3343- [pkg1] = self.facade.get_packages_by_name("name1")
3344- pkg1.provides += (provide1, provide2)
3345-
3346- # Ask Smart to reprocess relationships.
3347- self.facade.reload_cache()
3348-
3349- self.assertEqual(pkg1.requires[0].providedby[0].packages[0], pkg2)
3350- self.assertEqual(pkg1.requires[1].providedby[0].packages[0], pkg2)
3351-
3352- self.facade.mark_install(pkg1)
3353- try:
3354- self.facade.perform_changes()
3355- except DependencyError, exception:
3356- pass
3357- else:
3358- exception = None
3359- self.assertTrue(exception, "DependencyError not raised")
3360- self.assertEqual(exception.packages, [pkg2])
3361-
3362- def test_mark_remove_dependency_error(self):
3363- """
3364- Besides making 'name1' satisfy 'name2' and the contrary. We'll
3365- mark both packages installed, so that we can get an error on
3366- removal.
3367- """
3368- self.facade.reload_channels()
3369-
3370- provide1 = Provides("prerequirename1", "prerequireversion1")
3371- provide2 = Provides("requirename1", "requireversion1")
3372- [pkg2] = self.facade.get_packages_by_name("name2")
3373- pkg2.provides += (provide1, provide2)
3374-
3375- # We have to satisfy *both* packages.
3376- provide1 = Provides("prerequirename2", "prerequireversion2")
3377- provide2 = Provides("requirename2", "requireversion2")
3378- [pkg1] = self.facade.get_packages_by_name("name1")
3379- pkg1.provides += (provide1, provide2)
3380-
3381- # Ask Smart to reprocess relationships.
3382- self.facade.reload_cache()
3383-
3384- pkg1.installed = True
3385- pkg2.installed = True
3386-
3387- self.assertEqual(pkg1.requires[0].providedby[0].packages[0], pkg2)
3388- self.assertEqual(pkg1.requires[1].providedby[0].packages[0], pkg2)
3389-
3390- self.facade.mark_remove(pkg2)
3391- try:
3392- output = self.facade.perform_changes()
3393- except DependencyError, exception:
3394- output = ""
3395- else:
3396- exception = None
3397- self.assertTrue(exception, "DependencyError not raised. Output: %s"
3398- % repr(output))
3399- self.assertEqual(exception.packages, [pkg1])
3400-
3401- def test_mark_upgrade_dependency_error(self):
3402- """Artificially make pkg2 upgrade pkg1, and mark pkg1 for upgrade."""
3403-
3404- # The backend only works after initialized.
3405- from smart.backends.deb.base import DebUpgrades, DebConflicts
3406-
3407- self.facade.reload_channels()
3408-
3409- [pkg1] = self.facade.get_packages_by_name("name1")
3410- [pkg2] = self.facade.get_packages_by_name("name2")
3411-
3412- # Artificially make pkg2 be self-satisfied, and make it upgrade and
3413- # conflict with pkg1.
3414- pkg2.requires = []
3415- pkg2.upgrades = [DebUpgrades("name1", "=", "version1-release1")]
3416- pkg2.conflicts = [DebConflicts("name1", "=", "version1-release1")]
3417-
3418- # pkg1 will also be self-satisfied.
3419- pkg1.requires = []
3420-
3421- # Ask Smart to reprocess relationships.
3422- self.facade.reload_cache()
3423-
3424- # Mark the pkg1 as installed. Must be done after reloading
3425- # the cache as reloading will reset it to the loader installed
3426- # status.
3427- pkg1.installed = True
3428-
3429- # Check that the linkage worked.
3430- self.assertEqual(pkg2.upgrades[0].providedby[0].packages[0], pkg1)
3431-
3432- # Perform the upgrade test.
3433- self.facade.mark_upgrade(pkg1)
3434- try:
3435- self.facade.perform_changes()
3436- except DependencyError, exception:
3437- pass
3438- else:
3439- exception = None
3440- self.assertTrue(exception, "DependencyError not raised")
3441-
3442- # Both packages should be included in the dependency error. One
3443- # must be removed, and the other installed.
3444- self.assertEqual(set(exception.packages), set([pkg1, pkg2]))
3445-
3446- def test_perform_changes_with_logged_error(self):
3447- self.log_helper.ignore_errors(".*dpkg")
3448-
3449- self.facade.reload_channels()
3450-
3451- [pkg] = self.facade.get_packages_by_name("name1")
3452- pkg.requires = ()
3453-
3454- self.facade.reload_cache()
3455-
3456- self.facade.mark_install(pkg)
3457-
3458- try:
3459- output = self.facade.perform_changes()
3460- except SmartError, exception:
3461- output = ""
3462- else:
3463- exception = None
3464-
3465- self.assertTrue(exception,
3466- "SmartError not raised. Output: %s" % repr(output))
3467- # We can't check the whole message because the dpkg error can be
3468- # localized. We can't use str(exception) either because it can contain
3469- # unicode
3470- self.assertIn("ERROR", exception.args[0])
3471- self.assertIn("(2)", exception.args[0])
3472- self.assertIn("\n[unpack] name1_version1-release1\ndpkg: ",
3473- exception.args[0])
3474-
3475- def test_perform_changes_is_non_interactive(self):
3476- from smart.backends.deb.pm import DebPackageManager
3477-
3478- self.facade.reload_channels()
3479-
3480- [pkg] = self.facade.get_packages_by_name("name1")
3481- pkg.requires = ()
3482-
3483- self.facade.reload_cache()
3484-
3485- self.facade.mark_install(pkg)
3486-
3487- environ = []
3488-
3489- def check_environ(self, argv, output):
3490- environ.append(os.environ.get("DEBIAN_FRONTEND"))
3491- environ.append(os.environ.get("APT_LISTCHANGES_FRONTEND"))
3492- return 0
3493-
3494- DebPackageManager.dpkg, olddpkg = check_environ, DebPackageManager.dpkg
3495-
3496- try:
3497- self.facade.perform_changes()
3498- finally:
3499- DebPackageManager.dpkg = olddpkg
3500-
3501- self.assertEqual(environ, ["noninteractive", "none",
3502- "noninteractive", "none"])
3503-
3504- def test_perform_changes_with_policy_remove(self):
3505- """
3506- When requested changes are only about removing packages, we set
3507- the Smart transaction policy to C{PolicyRemove}.
3508- """
3509- create_deb(self.repository_dir, PKGNAME4, PKGDEB4)
3510- self.facade.reload_channels()
3511-
3512- # Importing these modules fail if Smart is not initialized
3513- from smart.backends.deb.base import DebRequires
3514-
3515- pkg1 = self.facade.get_package_by_hash(HASH1)
3516- pkg1.requires.append(DebRequires("name3", ">=", "version3-release3"))
3517-
3518- pkg3 = self.facade.get_package_by_hash(HASH3)
3519-
3520- # Ask Smart to reprocess relationships.
3521- self.facade.reload_cache()
3522-
3523- pkg1.installed = True
3524- pkg3.installed = True
3525-
3526- self.facade.mark_remove(pkg3)
3527- error = self.assertRaises(DependencyError, self.facade.perform_changes)
3528- [missing] = error.packages
3529- self.assertIdentical(pkg1, missing)
3530-
3531- def test_perform_changes_with_commit_change_set_errors(self):
3532-
3533- self.facade.reload_channels()
3534-
3535- [pkg] = self.facade.get_packages_by_name("name1")
3536- pkg.requires = ()
3537-
3538- self.facade.mark_install(pkg)
3539-
3540- ctrl_mock = self.mocker.patch(Control)
3541- ctrl_mock.commitChangeSet(ANY)
3542- self.mocker.throw(smart.Error("commit error"))
3543- self.mocker.replay()
3544-
3545- self.assertRaises(TransactionError, self.facade.perform_changes)
3546-
3547- def test_deinit_cleans_the_state(self):
3548- self.facade.reload_channels()
3549- self.assertTrue(self.facade.get_package_by_hash(HASH1))
3550- self.facade.deinit()
3551- self.assertFalse(self.facade.get_package_by_hash(HASH1))
3552-
3553- def test_deinit_deinits_smart(self):
3554- self.facade.reload_channels()
3555- self.assertTrue(smart.iface.object)
3556- self.facade.deinit()
3557- self.assertFalse(smart.iface.object)
3558-
3559- def test_deinit_when_smart_wasnt_initialized(self):
3560- self.assertFalse(smart.iface.object)
3561- # Nothing bad should happen.
3562- self.facade.deinit()
3563-
3564- def test_reload_channels_wont_consider_non_debian_packages(self):
3565-
3566- class StubPackage(object):
3567- pass
3568-
3569- pkg = StubPackage()
3570-
3571- ctrl_mock = self.mocker.patch(Control)
3572- cache_mock = ctrl_mock.getCache()
3573- cache_mock.getPackages()
3574- self.mocker.result([pkg])
3575- self.mocker.replay()
3576-
3577- self.facade.reload_channels()
3578- self.assertEqual(self.facade.get_package_hash(pkg), None)
3579-
3580- def test_reload_channels_with_channel_error(self):
3581- """
3582- The L{SmartFacade.reload_channels} method raises a L{ChannelsError} if
3583- smart fails to load the configured channels.
3584- """
3585- ctrl_mock = self.mocker.patch(Control)
3586- ctrl_mock.reloadChannels(caching=ALWAYS)
3587- self.mocker.throw(smart.Error(u"Channel information is locked"))
3588- self.mocker.replay()
3589- self.assertRaises(ChannelError, self.facade.reload_channels)
3590-
3591- def test_reset_add_get_channels(self):
3592-
3593- channels = [("alias0", {"type": "test"}),
3594- ("alias1", {"type": "test"})]
3595-
3596- self.facade.reset_channels()
3597-
3598- self.assertEqual(self.facade.get_channels(), {})
3599-
3600- self.facade.add_channel(*channels[0])
3601- self.facade.add_channel(*channels[1])
3602-
3603- self.assertEqual(self.facade.get_channels(), dict(channels))
3604-
3605- def test_add_apt_deb_channel(self):
3606- """
3607- The L{SmartFacade.add_channel_apt_deb} add a Smart channel of
3608- type C{"apt-deb"}.
3609- """
3610- self.facade.reset_channels()
3611- self.facade.add_channel_apt_deb("http://url/", "name", "component")
3612- self.assertEqual(self.facade.get_channels(),
3613- {"name": {"baseurl": "http://url/",
3614- "distribution": "name",
3615- "components": "component",
3616- "type": "apt-deb"}})
3617-
3618- def test_add_deb_dir_channel(self):
3619- """
3620- The L{SmartFacade.add_channel_deb_dir} add a Smart channel of
3621- type C{"deb-dir"}.
3622- """
3623- self.facade.reset_channels()
3624- self.facade.add_channel_deb_dir("/my/repo")
3625- self.assertEqual(self.facade.get_channels(),
3626- {"/my/repo": {"path": "/my/repo",
3627- "type": "deb-dir"}})
3628-
3629- def test_get_arch(self):
3630- """
3631- The L{SmartFacade.get_arch} should return the system dpkg
3632- architecture.
3633- """
3634- deferred = Deferred()
3635-
3636- def do_test():
3637- result = getProcessOutputAndValue("/usr/bin/dpkg",
3638- ("--print-architecture",))
3639-
3640- def callback((out, err, code)):
3641- self.assertEqual(self.facade.get_arch(), out.strip())
3642- result.addCallback(callback)
3643- result.chainDeferred(deferred)
3644-
3645- reactor.callWhenRunning(do_test)
3646- return deferred
3647-
3648- def test_set_arch_multiple_times(self):
3649-
3650- repo = create_full_repository(self.makeDir())
3651-
3652- self.facade.set_arch("i386")
3653- self.facade.reset_channels()
3654- self.facade.add_channel_apt_deb(repo.url, repo.codename,
3655- " ".join(repo.components))
3656- self.facade.reload_channels()
3657-
3658- pkgs = self.facade.get_packages()
3659- self.assertEqual(len(pkgs), 2)
3660- self.assertEqual(pkgs[0].name, "syslinux")
3661- self.assertEqual(pkgs[1].name, "kairos")
3662-
3663- self.facade.deinit()
3664- self.facade.set_arch("amd64")
3665- self.facade.reset_channels()
3666- self.facade.add_channel_apt_deb(repo.url, repo.codename,
3667- " ".join(repo.components))
3668- self.facade.reload_channels()
3669-
3670- pkgs = self.facade.get_packages()
3671- self.assertEqual(len(pkgs), 2)
3672- self.assertEqual(pkgs[0].name, "libclthreads2")
3673- self.assertEqual(pkgs[1].name, "kairos")
3674-
3675- def test_set_caching_with_reload_error(self):
3676-
3677- alias = "alias"
3678- channel = {"type": "deb-dir",
3679- "path": "/does/not/exist"}
3680-
3681- self.facade.reset_channels()
3682- self.facade.add_channel(alias, channel)
3683- self.facade.set_caching(NEVER)
3684-
3685- self.assertRaises(ChannelError, self.facade.reload_channels)
3686- self.facade._channels = {}
3687-
3688- ignore_re = re.compile("\[Smart\].*'alias'.*/does/not/exist")
3689-
3690- self.log_helper.ignored_exception_regexes = [ignore_re]
3691-
3692- def test_init_landscape_plugins(self):
3693- """
3694- The landscape plugin which helps managing proxies is loaded when smart
3695- is initialized: this sets a smart configuration variable and load the
3696- module.
3697- """
3698- self.facade.reload_channels()
3699- self.assertTrue(smart.sysconf.get("use-landscape-proxies"))
3700- self.assertIn("smart.plugins.landscape", sys.modules)
3701-
3702- def test_get_package_locks_with_no_lock(self):
3703- """
3704- If no package locks are set, L{SmartFacade.get_package_locks} returns
3705- an empty C{list}.
3706- """
3707- self.assertEqual(self.facade.get_package_locks(), [])
3708-
3709- def test_get_package_locks_with_one_lock(self):
3710- """
3711- If one lock is set, the list of locks contains one item.
3712- """
3713- self.facade.set_package_lock("name1", "<", "version1")
3714- self.assertEqual(self.facade.get_package_locks(),
3715- [("name1", "<", "version1")])
3716-
3717- def test_get_package_locks_with_many_locks(self):
3718- """
3719- It's possible to have more than one package lock and several conditions
3720- for each of them.
3721- """
3722- self.facade.set_package_lock("name1", "<", "version1")
3723- self.facade.set_package_lock("name1", ">=", "version3")
3724- self.facade.set_package_lock("name2")
3725- self.assertEqual(sorted(self.facade.get_package_locks()),
3726- sorted([("name1", "<", "version1"),
3727- ("name1", ">=", "version3"),
3728- ("name2", "", "")]))
3729-
3730- def test_set_package_lock(self):
3731- """
3732- It is possible to lock a package by simply specifying its name.
3733- """
3734- self.facade.set_package_lock("name1")
3735- self.facade.reload_channels()
3736- [package] = self.facade.get_locked_packages()
3737- self.assertEqual(package.name, "name1")
3738-
3739- def test_set_package_lock_with_matching_condition(self):
3740- """
3741- It is possible to set a package lock specifying both a
3742- package name and version condition. Any matching package
3743- will be locked.
3744- """
3745- self.facade.set_package_lock("name1", "<", "version2")
3746- self.facade.reload_channels()
3747- [package] = self.facade.get_locked_packages()
3748- self.assertEqual(package.name, "name1")
3749-
3750- def test_set_package_lock_with_non_matching_condition(self):
3751- """
3752- If the package lock conditions do not match any package,
3753- no package will be locked.
3754- """
3755- self.facade.set_package_lock("name1", "<", "version1")
3756- self.facade.reload_channels()
3757- self.assertEqual(self.facade.get_locked_packages(), [])
3758-
3759- def test_set_package_lock_with_missing_version(self):
3760- """
3761- When specifing a relation for a package lock condition, a version
3762- must be provided as well.
3763- """
3764- error = self.assertRaises(RuntimeError, self.facade.set_package_lock,
3765- "name1", "<", "")
3766- self.assertEqual(str(error), "Package lock version not provided")
3767-
3768- def test_set_package_lock_with_missing_relation(self):
3769- """
3770- When specifing a version for a package lock condition, a relation
3771- must be provided as well.
3772- """
3773- error = self.assertRaises(RuntimeError, self.facade.set_package_lock,
3774- "name1", "", "version1")
3775- self.assertEqual(str(error), "Package lock relation not provided")
3776-
3777- def test_remove_package_lock(self):
3778- """
3779- It is possibly to remove a package lock without any version condition.
3780- """
3781- self.facade.set_package_lock("name1")
3782- self.facade.remove_package_lock("name1")
3783- self.assertEqual(self.facade.get_locked_packages(), [])
3784-
3785- def test_remove_package_lock_with_condition(self):
3786- """
3787- It is possibly to remove a package lock with a version condition.
3788- """
3789- self.facade.set_package_lock("name1", "<", "version1")
3790- self.facade.remove_package_lock("name1", "<", "version1")
3791- self.assertEqual(self.facade.get_locked_packages(), [])
3792-
3793- def test_save_config(self):
3794- """
3795- It is possible to lock a package by simply specifying its name.
3796- """
3797- self.facade.set_package_lock("python", "=>", "2.5")
3798- self.facade.save_config()
3799- self.facade.deinit()
3800- self.assertEqual(self.facade.get_package_locks(),
3801- [("python", "=>", "2.5")])
3802
3803=== removed file 'landscape/package/tests/test_interface.py'
3804--- landscape/package/tests/test_interface.py 2011-07-18 15:16:18 +0000
3805+++ landscape/package/tests/test_interface.py 1970-01-01 00:00:00 +0000
3806@@ -1,34 +0,0 @@
3807-# -*- encoding: utf-8 -*-
3808-from landscape.package.interface import LandscapeInterface
3809-
3810-from landscape.tests.helpers import LandscapeTest
3811-from landscape.package.tests.helpers import SmartFacadeHelper
3812-
3813-
3814-class LandscapeInterfaceTest(LandscapeTest):
3815-
3816- helpers = [SmartFacadeHelper]
3817-
3818- def setUp(self):
3819- super(LandscapeInterfaceTest, self).setUp()
3820- self.facade.reload_channels()
3821- self.iface = LandscapeInterface(None)
3822-
3823- def test_message_with_unicode_and_utf8(self):
3824- self.iface.info(u"áéíóú")
3825- self.iface.info("áéíóú")
3826- self.assertEqual(self.iface.get_output_for_landscape(),
3827- u"INFO: áéíóú\nINFO: áéíóú\n")
3828-
3829- def test_message_with_unicode_and_unknown_encoding(self):
3830- self.iface.info(u"áéíóú")
3831- self.iface.info("aeíou\xc3") # UTF-8 expects a byte after \xc3
3832- c = u"\N{REPLACEMENT CHARACTER}"
3833- self.assertEqual(self.iface.get_output_for_landscape(),
3834- u"INFO: áéíóú\nINFO: ae%s%sou%s\n" % (c, c, c))
3835-
3836- def test_output_with_unicode_and_utf8(self):
3837- self.iface.showOutput(u"áéíóú")
3838- self.iface.showOutput("áéíóú")
3839- self.assertEqual(self.iface.get_output_for_landscape(),
3840- u"áéíóúáéíóú")
3841
3842=== modified file 'landscape/package/tests/test_releaseupgrader.py'
3843--- landscape/package/tests/test_releaseupgrader.py 2012-03-19 09:33:34 +0000
3844+++ landscape/package/tests/test_releaseupgrader.py 2012-06-04 14:08:28 +0000
3845@@ -655,7 +655,7 @@
3846
3847 def check_result((out, err, code)):
3848 self.assertFalse(os.path.exists(upgrade_tool_directory))
3849- self.assertEqual(out, "--force-smart-update\n%s\n"
3850+ self.assertEqual(out, "--force-apt-update\n%s\n"
3851 % os.getcwd())
3852 self.assertEqual(err, "")
3853 self.assertEqual(code, 0)
3854@@ -738,7 +738,7 @@
3855 result = self.upgrader.finish()
3856
3857 def check_result((out, err, code)):
3858- self.assertEqual(out, "--force-smart-update "
3859+ self.assertEqual(out, "--force-apt-update "
3860 "--config=/some/config\n")
3861 self.assertEqual(err, "")
3862 self.assertEqual(code, 0)
3863
3864=== modified file 'landscape/package/tests/test_reporter.py'
3865--- landscape/package/tests/test_reporter.py 2012-03-19 09:33:34 +0000
3866+++ landscape/package/tests/test_reporter.py 2012-06-04 14:08:28 +0000
3867@@ -1,4 +1,3 @@
3868-import glob
3869 import sys
3870 import os
3871 import unittest
3872@@ -17,9 +16,9 @@
3873 PackageReporter, HASH_ID_REQUEST_TIMEOUT, main, find_reporter_command,
3874 PackageReporterConfiguration, FakeGlobalReporter, FakeReporter)
3875 from landscape.package import reporter
3876-from landscape.package.facade import AptFacade, has_new_enough_apt
3877+from landscape.package.facade import AptFacade
3878 from landscape.package.tests.helpers import (
3879- SmartFacadeHelper, AptFacadeHelper, SimpleRepositoryHelper,
3880+ AptFacadeHelper, SimpleRepositoryHelper,
3881 HASH1, HASH2, HASH3, PKGNAME1)
3882 from landscape.tests.helpers import (
3883 LandscapeTest, BrokerServiceHelper, EnvironSaverHelper)
3884@@ -30,18 +29,63 @@
3885
3886 class PackageReporterConfigurationTest(unittest.TestCase):
3887
3888- def test_force_smart_update_option(self):
3889+ def test_force_apt_update_option(self):
3890 """
3891- The L{PackageReporterConfiguration} supports a '--force-smart-update'
3892+ The L{PackageReporterConfiguration} supports a '--force-apt-update'
3893 command line option.
3894 """
3895 config = PackageReporterConfiguration()
3896- self.assertFalse(config.force_smart_update)
3897- config.load(["--force-smart-update"])
3898- self.assertTrue(config.force_smart_update)
3899-
3900-
3901-class PackageReporterTestMixin(object):
3902+ self.assertFalse(config.force_apt_update)
3903+ config.load(["--force-apt-update"])
3904+ self.assertTrue(config.force_apt_update)
3905+
3906+
3907+class PackageReporterAptTest(LandscapeTest):
3908+
3909+ helpers = [AptFacadeHelper, SimpleRepositoryHelper, BrokerServiceHelper]
3910+
3911+ Facade = AptFacade
3912+
3913+ def setUp(self):
3914+
3915+ def set_up(ignored):
3916+ self.store = PackageStore(self.makeFile())
3917+ self.config = PackageReporterConfiguration()
3918+ self.reporter = PackageReporter(
3919+ self.store, self.facade, self.remote, self.config)
3920+ self.config.data_path = self.makeDir()
3921+ os.mkdir(self.config.package_directory)
3922+
3923+ result = super(PackageReporterAptTest, self).setUp()
3924+ return result.addCallback(set_up)
3925+
3926+ def _clear_repository(self):
3927+ """Remove all packages from self.repository."""
3928+ create_file(self.repository_dir + "/Packages", "")
3929+
3930+ def set_pkg1_upgradable(self):
3931+ """Make it so that package "name1" is considered to be upgradable.
3932+
3933+ Return the hash of the package that upgrades "name1".
3934+ """
3935+ self._add_package_to_deb_dir(
3936+ self.repository_dir, "name1", version="version2")
3937+ self.facade.reload_channels()
3938+ name1_upgrade = sorted(self.facade.get_packages_by_name("name1"))[1]
3939+ return self.facade.get_package_hash(name1_upgrade)
3940+
3941+ def set_pkg1_installed(self):
3942+ """Make it so that package "name1" is considered installed."""
3943+ self._install_deb_file(os.path.join(self.repository_dir, PKGNAME1))
3944+
3945+ def _make_fake_apt_update(self, out="output", err="error", code=0):
3946+ """Create a fake apt-update executable"""
3947+ self.reporter.apt_update_filename = self.makeFile(
3948+ "#!/bin/sh\n"
3949+ "echo -n %s\n"
3950+ "echo -n %s >&2\n"
3951+ "exit %d" % (out, err, code))
3952+ os.chmod(self.reporter.apt_update_filename, 0755)
3953
3954 def test_set_package_ids_with_all_known(self):
3955 self.store.add_hash_id_request(["hash1", "hash2"])
3956@@ -497,64 +541,6 @@
3957
3958 return result
3959
3960- def test_run_smart_update(self):
3961- """
3962- The L{PackageReporter.run_smart_update} method should run smart-update
3963- with the proper arguments.
3964- """
3965- self.reporter.sources_list_filename = "/I/Dont/Exist"
3966- self.reporter.sources_list_directory = "/I/Dont/Exist"
3967- self.reporter.smart_update_filename = self.makeFile(
3968- "#!/bin/sh\necho -n $@")
3969- os.chmod(self.reporter.smart_update_filename, 0755)
3970- debug_mock = self.mocker.replace("logging.debug")
3971- debug_mock("'%s' exited with status 0 (out='--after %d', err=''" % (
3972- self.reporter.smart_update_filename,
3973- self.reporter.smart_update_interval))
3974- warning_mock = self.mocker.replace("logging.warning")
3975- self.expect(warning_mock(ANY)).count(0)
3976- self.mocker.replay()
3977- deferred = Deferred()
3978-
3979- def do_test():
3980-
3981- result = self.reporter.run_smart_update()
3982-
3983- def callback((out, err, code)):
3984- interval = self.reporter.smart_update_interval
3985- self.assertEqual(err, "")
3986- self.assertEqual(out, "--after %d" % interval)
3987- self.assertEqual(code, 0)
3988- result.addCallback(callback)
3989- result.chainDeferred(deferred)
3990-
3991- reactor.callWhenRunning(do_test)
3992- return deferred
3993-
3994- def test_run_smart_update_with_force_smart_update(self):
3995- """
3996- L{PackageReporter.run_smart_update} forces a smart-update run if
3997- the '--force-smart-update' command line option was passed.
3998-
3999- """
4000- self.config.load(["--force-smart-update"])
4001- self.reporter.smart_update_filename = self.makeFile(
4002- "#!/bin/sh\necho -n $@")
4003- os.chmod(self.reporter.smart_update_filename, 0755)
4004-
4005- deferred = Deferred()
4006-
4007- def do_test():
4008- result = self.reporter.run_smart_update()
4009-
4010- def callback((out, err, code)):
4011- self.assertEqual(out, "")
4012- result.addCallback(callback)
4013- result.chainDeferred(deferred)
4014-
4015- reactor.callWhenRunning(do_test)
4016- return deferred
4017-
4018 def test_wb_apt_sources_have_changed(self):
4019 """
4020 The L{PackageReporter._apt_sources_have_changed} method returns a bool
4021@@ -581,244 +567,6 @@
4022 content="deb http://foo ./")
4023 self.assertTrue(self.reporter._apt_sources_have_changed())
4024
4025- def test_run_smart_update_with_force_smart_update_if_sources_changed(self):
4026- """
4027- L{PackageReporter.run_smart_update} forces a smart-update run if
4028- the APT sources.list file has changed.
4029-
4030- """
4031- self.assertEqual(self.reporter.sources_list_filename,
4032- "/etc/apt/sources.list")
4033- self.reporter.sources_list_filename = self.makeFile("deb ftp://url ./")
4034- self.reporter.smart_update_filename = self.makeFile(
4035- "#!/bin/sh\necho -n $@")
4036- os.chmod(self.reporter.smart_update_filename, 0755)
4037-
4038- deferred = Deferred()
4039-
4040- def do_test():
4041- result = self.reporter.run_smart_update()
4042-
4043- def callback((out, err, code)):
4044- # Smart update was called without the --after parameter
4045- self.assertEqual(out, "")
4046- result.addCallback(callback)
4047- result.chainDeferred(deferred)
4048-
4049- reactor.callWhenRunning(do_test)
4050- return deferred
4051-
4052- def test_run_smart_update_warns_about_failures(self):
4053- """
4054- The L{PackageReporter.run_smart_update} method should log a warning
4055- in case smart-update terminates with a non-zero exit code other than 1.
4056- """
4057- self.reporter.smart_update_filename = self.makeFile(
4058- "#!/bin/sh\necho -n error >&2\necho -n output\nexit 2")
4059- os.chmod(self.reporter.smart_update_filename, 0755)
4060- logging_mock = self.mocker.replace("logging.warning")
4061- logging_mock("'%s' exited with status 2"
4062- " (error)" % self.reporter.smart_update_filename)
4063- self.mocker.replay()
4064- deferred = Deferred()
4065-
4066- def do_test():
4067- result = self.reporter.run_smart_update()
4068-
4069- def callback((out, err, code)):
4070- self.assertEqual(out, "output")
4071- self.assertEqual(err, "error")
4072- self.assertEqual(code, 2)
4073- result.addCallback(callback)
4074- result.chainDeferred(deferred)
4075-
4076- reactor.callWhenRunning(do_test)
4077- return deferred
4078-
4079- def test_run_smart_update_report_smart_failure(self):
4080- """
4081- If L{PackageReporter.run_smart_update} fails, a message is sent to the
4082- server reporting the error, to be able to fix the problem centrally.
4083- """
4084- message_store = self.broker_service.message_store
4085- message_store.set_accepted_types(["package-reporter-result"])
4086- self.reporter.smart_update_filename = self.makeFile(
4087- "#!/bin/sh\necho -n error >&2\necho -n output\nexit 2")
4088- os.chmod(self.reporter.smart_update_filename, 0755)
4089- deferred = Deferred()
4090-
4091- def do_test():
4092- result = self.reporter.run_smart_update()
4093-
4094- def callback(ignore):
4095- self.assertMessages(message_store.get_pending_messages(),
4096- [{"type": "package-reporter-result",
4097- "code": 2, "err": u"error"}])
4098- result.addCallback(callback)
4099- result.chainDeferred(deferred)
4100-
4101- reactor.callWhenRunning(do_test)
4102- return deferred
4103-
4104- def test_run_smart_update_report_no_sources(self):
4105- """
4106- L{PackageReporter.run_smart_update} reports a failure if smart
4107- succeeds but there are no APT sources defined. Smart doesn't
4108- fail if there are no sources, but we fake a failure in order to
4109- re-use the PackageReporterAlert on the server.
4110- """
4111- self.facade.reset_channels()
4112- message_store = self.broker_service.message_store
4113- message_store.set_accepted_types(["package-reporter-result"])
4114- self.reporter.smart_update_filename = self.makeFile(
4115- "#!/bin/sh\necho -n error >&2\necho -n output\nexit 0")
4116- os.chmod(self.reporter.smart_update_filename, 0755)
4117- deferred = Deferred()
4118-
4119- def do_test():
4120- result = self.reporter.run_smart_update()
4121-
4122- def callback(ignore):
4123- error = "There are no APT sources configured in %s or %s." % (
4124- self.reporter.sources_list_filename,
4125- self.reporter.sources_list_directory)
4126- self.assertMessages(message_store.get_pending_messages(),
4127- [{"type": "package-reporter-result",
4128- "code": 1, "err": error}])
4129- result.addCallback(callback)
4130- result.chainDeferred(deferred)
4131-
4132- reactor.callWhenRunning(do_test)
4133- return deferred
4134-
4135- def test_run_smart_update_report_smart_failure_no_sources(self):
4136- """
4137- If L{PackageReporter.run_smart_update} fails and there are no
4138- APT sources configured, the Smart error takes precedence.
4139- """
4140- self.facade.reset_channels()
4141- message_store = self.broker_service.message_store
4142- message_store.set_accepted_types(["package-reporter-result"])
4143- self.reporter.smart_update_filename = self.makeFile(
4144- "#!/bin/sh\necho -n error >&2\necho -n output\nexit 2")
4145- os.chmod(self.reporter.smart_update_filename, 0755)
4146- deferred = Deferred()
4147-
4148- def do_test():
4149- result = self.reporter.run_smart_update()
4150-
4151- def callback(ignore):
4152- self.assertMessages(message_store.get_pending_messages(),
4153- [{"type": "package-reporter-result",
4154- "code": 2, "err": u"error"}])
4155- result.addCallback(callback)
4156- result.chainDeferred(deferred)
4157-
4158- reactor.callWhenRunning(do_test)
4159- return deferred
4160-
4161- def test_run_smart_update_report_success(self):
4162- """
4163- L{PackageReporter.run_smart_update} also reports success to be able to
4164- know the proper state of the client.
4165- """
4166- message_store = self.broker_service.message_store
4167- message_store.set_accepted_types(["package-reporter-result"])
4168- self.reporter.smart_update_filename = self.makeFile(
4169- "#!/bin/sh\necho -n error >&2\necho -n output\nexit 0")
4170- os.chmod(self.reporter.smart_update_filename, 0755)
4171- deferred = Deferred()
4172-
4173- def do_test():
4174- result = self.reporter.run_smart_update()
4175-
4176- def callback(ignore):
4177- self.assertMessages(message_store.get_pending_messages(),
4178- [{"type": "package-reporter-result",
4179- "code": 0, "err": u"error"}])
4180- result.addCallback(callback)
4181- result.chainDeferred(deferred)
4182-
4183- reactor.callWhenRunning(do_test)
4184- return deferred
4185-
4186- def test_run_smart_update_warns_exit_code_1_and_non_empty_stderr(self):
4187- """
4188- The L{PackageReporter.run_smart_update} method should log a warning
4189- in case smart-update terminates with exit code 1 and non empty stderr.
4190- """
4191- self.reporter.smart_update_filename = self.makeFile(
4192- "#!/bin/sh\necho -n \"error \" >&2\nexit 1")
4193- os.chmod(self.reporter.smart_update_filename, 0755)
4194- logging_mock = self.mocker.replace("logging.warning")
4195- logging_mock("'%s' exited with status 1"
4196- " (error )" % self.reporter.smart_update_filename)
4197- self.mocker.replay()
4198- deferred = Deferred()
4199-
4200- def do_test():
4201- result = self.reporter.run_smart_update()
4202-
4203- def callback((out, err, code)):
4204- self.assertEqual(out, "")
4205- self.assertEqual(err, "error ")
4206- self.assertEqual(code, 1)
4207- result.addCallback(callback)
4208- result.chainDeferred(deferred)
4209-
4210- reactor.callWhenRunning(do_test)
4211- return deferred
4212-
4213- def test_run_smart_update_ignores_exit_code_1_and_empty_output(self):
4214- """
4215- The L{PackageReporter.run_smart_update} method should not log anything
4216- in case smart-update terminates with exit code 1 and output containing
4217- only a newline character.
4218- """
4219- self.reporter.smart_update_filename = self.makeFile(
4220- "#!/bin/sh\necho\nexit 1")
4221- os.chmod(self.reporter.smart_update_filename, 0755)
4222- logging_mock = self.mocker.replace("logging.warning")
4223- self.expect(logging_mock(ANY)).count(0)
4224- self.mocker.replay()
4225- deferred = Deferred()
4226-
4227- def do_test():
4228-
4229- result = self.reporter.run_smart_update()
4230-
4231- def callback((out, err, code)):
4232- self.assertEqual(out, "\n")
4233- self.assertEqual(err, "")
4234- self.assertEqual(code, 1)
4235- result.addCallback(callback)
4236- result.chainDeferred(deferred)
4237-
4238- reactor.callWhenRunning(do_test)
4239- return deferred
4240-
4241- def test_run_smart_update_touches_stamp_file(self):
4242- """
4243- The L{PackageReporter.run_smart_update} method touches a stamp file
4244- after running the smart-update wrapper.
4245- """
4246- self.reporter.sources_list_filename = "/I/Dont/Exist"
4247- self.reporter.smart_update_filename = "/bin/true"
4248- deferred = Deferred()
4249-
4250- def do_test():
4251-
4252- result = self.reporter.run_smart_update()
4253-
4254- def callback(ignored):
4255- self.assertTrue(
4256- os.path.exists(self.config.update_stamp_filename))
4257- result.addCallback(callback)
4258- result.chainDeferred(deferred)
4259-
4260- reactor.callWhenRunning(do_test)
4261- return deferred
4262-
4263 def test_remove_expired_hash_id_request(self):
4264 request = self.store.add_hash_id_request(["hash1"])
4265 request.message_id = 9999
4266@@ -1133,11 +881,7 @@
4267
4268 upgrade_hash = self.set_pkg1_upgradable()
4269 self.set_pkg1_installed()
4270- # Don't reload for SmartFacade, since the hash of pkg2 will be
4271- # changed, resulting in that name2 will be considered not
4272- # available..
4273- if isinstance(self.facade, AptFacade):
4274- self.facade.reload_channels()
4275+ self.facade.reload_channels()
4276
4277 self.store.set_hash_ids(
4278 {HASH1: 1, upgrade_hash: 2, HASH3: 3})
4279@@ -1193,20 +937,13 @@
4280 result = self.reporter.detect_packages_changes()
4281 return result.addCallback(got_result)
4282
4283- def test_detect_changes_considers_packages_and_locks_changes(self):
4284+ def test_detect_changes_considers_packages_changes(self):
4285 """
4286- The L{PackageReporter.detect_changes} method considers both package and
4287- package locks changes. It also releases smart locks by calling the
4288- L{SmartFacade.deinit} method.
4289+ The L{PackageReporter.detect_changes} method package changes.
4290 """
4291 reporter_mock = self.mocker.patch(self.reporter)
4292 reporter_mock.detect_packages_changes()
4293 self.mocker.result(succeed(True))
4294- reporter_mock.detect_package_locks_changes()
4295- self.mocker.result(succeed(True))
4296-
4297- facade_mock = self.mocker.patch(self.facade)
4298- facade_mock.deinit()
4299
4300 self.mocker.replay()
4301 return self.reporter.detect_changes()
4302@@ -1219,8 +956,6 @@
4303 """
4304 reporter_mock = self.mocker.patch(self.reporter)
4305 reporter_mock.detect_packages_changes()
4306- self.mocker.result(succeed(False))
4307- reporter_mock.detect_package_locks_changes()
4308 self.mocker.result(succeed(True))
4309 callback = self.mocker.mock()
4310 callback()
4311@@ -1236,11 +971,7 @@
4312
4313 results = [Deferred() for i in range(7)]
4314
4315- # Either the Apt or Smart cache will be updated, not both.
4316- if isinstance(self.facade, AptFacade):
4317- reporter_mock.run_apt_update()
4318- else:
4319- reporter_mock.run_smart_update()
4320+ reporter_mock.run_apt_update()
4321 self.mocker.result(results[0])
4322
4323 reporter_mock.fetch_hash_id_db()
4324@@ -1306,16 +1037,19 @@
4325 This is done in the reporter so that we know it happens when
4326 no other reporter is possibly running at the same time.
4327 """
4328+ self._add_system_package("foo")
4329+ self.facade.reload_channels()
4330+ [foo] = self.facade.get_packages_by_name("foo")
4331+ foo_hash = self.facade.get_package_hash(foo)
4332+ self.facade.set_package_hold(foo)
4333+ self.facade.reload_channels()
4334 message_store = self.broker_service.message_store
4335 message_store.set_accepted_types(["package-locks"])
4336- self.store.set_hash_ids({HASH1: 3, HASH2: 4})
4337+ self.store.set_hash_ids({foo_hash: 3, HASH2: 4})
4338 self.store.add_available([1])
4339 self.store.add_available_upgrades([2])
4340 self.store.add_installed([2])
4341 self.store.add_locked([3])
4342- self.store.add_package_locks([("name1", None, None)])
4343- if self.facade.supports_package_locks:
4344- self.facade.set_package_lock("name1")
4345 request1 = self.store.add_hash_id_request(["hash3"])
4346 request2 = self.store.add_hash_id_request(["hash4"])
4347
4348@@ -1328,12 +1062,6 @@
4349 self.assertEqual(self.store.get_available_upgrades(), [2])
4350 self.assertEqual(self.store.get_available(), [1])
4351 self.assertEqual(self.store.get_installed(), [2])
4352- # XXX: Don't check get_locked() and get_package_locks() until
4353- # package locks are implemented in AptFacade.
4354- if not isinstance(self.facade, AptFacade):
4355- self.assertEqual(self.store.get_locked(), [3])
4356- self.assertEqual(
4357- self.store.get_package_locks(), [("name1", "", "")])
4358 self.assertEqual(self.store.get_hash_id_request(request1.id).id,
4359 request1.id)
4360
4361@@ -1344,7 +1072,7 @@
4362 def check_result(result):
4363
4364 # The hashes should not go away.
4365- hash1 = self.store.get_hash_id(HASH1)
4366+ hash1 = self.store.get_hash_id(foo_hash)
4367 hash2 = self.store.get_hash_id(HASH2)
4368 self.assertEqual([hash1, hash2], [3, 4])
4369
4370@@ -1353,12 +1081,9 @@
4371
4372 # After running the resychronize task, detect_packages_changes is
4373 # called, and the existing known hashes are made available.
4374- self.assertEqual(self.store.get_available(), [3, 4])
4375- self.assertEqual(self.store.get_installed(), [])
4376- # XXX: Don't check get_locked() until package locks are
4377- # implemented in AptFacade.
4378- if not isinstance(self.facade, AptFacade):
4379- self.assertEqual(self.store.get_locked(), [3])
4380+ self.assertEqual(self.store.get_available(), [4])
4381+ self.assertEqual(self.store.get_installed(), [3])
4382+ self.assertEqual(self.store.get_locked(), [3])
4383
4384 # The two original hash id requests should be still there, and
4385 # a new hash id request should also be detected for HASH3.
4386@@ -1371,314 +1096,14 @@
4387 elif request.id == request2.id:
4388 self.assertEqual(request.hashes, ["hash4"])
4389 elif not new_request_found:
4390- self.assertEqual(request.hashes, [HASH3])
4391+ self.assertEqual(request.hashes, [HASH3, HASH1])
4392 else:
4393 self.fail("Unexpected hash-id request!")
4394 self.assertEqual(requests_count, 3)
4395
4396- # XXX: Don't check for package-locks messages until package
4397- # locks are implemented in AptFacade.
4398- if not isinstance(self.facade, AptFacade):
4399- self.assertMessages(message_store.get_pending_messages(),
4400- [{"type": "package-locks",
4401- "created": [("name1", "", "")]}])
4402-
4403 deferred.addCallback(check_result)
4404 return deferred
4405
4406-
4407-class PackageReporterSmartTest(LandscapeTest, PackageReporterTestMixin):
4408-
4409- helpers = [SmartFacadeHelper, BrokerServiceHelper]
4410-
4411- def setUp(self):
4412-
4413- def set_up(ignored):
4414- self.store = PackageStore(self.makeFile())
4415- self.config = PackageReporterConfiguration()
4416- self.reporter = PackageReporter(
4417- self.store, self.facade, self.remote, self.config)
4418- self.config.data_path = self.makeDir()
4419- os.mkdir(self.config.package_directory)
4420-
4421- result = super(PackageReporterSmartTest, self).setUp()
4422- return result.addCallback(set_up)
4423-
4424- def _clear_repository(self):
4425- """Remove all packages from self.repository."""
4426- for filename in glob.glob(self.repository_dir + "/*"):
4427- os.unlink(filename)
4428-
4429- def set_pkg1_upgradable(self):
4430- """Make it so that package "name1" is considered to be upgradable.
4431-
4432- Return the hash of the package that upgrades "name1".
4433- """
4434- previous = self.Facade.channels_reloaded
4435-
4436- def callback(self):
4437- from smart.backends.deb.base import DebUpgrades
4438- previous(self)
4439- pkg2 = self.get_packages_by_name("name2")[0]
4440- pkg2.upgrades += (DebUpgrades("name1", "=", "version1-release1"),)
4441- self.reload_cache() # Relink relations.
4442- self.Facade.channels_reloaded = callback
4443- return HASH2
4444-
4445- def set_pkg1_installed(self):
4446- """Make it so that package "name1" is considered installed."""
4447- previous = self.Facade.channels_reloaded
4448-
4449- def callback(self):
4450- previous(self)
4451- self.get_packages_by_name("name1")[0].installed = True
4452- self.Facade.channels_reloaded = callback
4453-
4454- def test_detect_packages_changes_with_locked(self):
4455- """
4456- If Smart indicates locked packages we didn't know about, report
4457- them to the server.
4458- """
4459- message_store = self.broker_service.message_store
4460- message_store.set_accepted_types(["packages"])
4461-
4462- self.facade.set_package_lock("name1")
4463- self.facade.set_package_lock("name2", ">=", "version2")
4464-
4465- self.store.set_hash_ids({HASH1: 1, HASH2: 2})
4466- self.store.add_available([1, 2])
4467-
4468- def got_result(result):
4469- self.assertMessages(message_store.get_pending_messages(),
4470- [{"type": "packages", "locked": [1, 2]}])
4471- self.assertEqual(sorted(self.store.get_locked()), [1, 2])
4472-
4473- result = self.reporter.detect_packages_changes()
4474- return result.addCallback(got_result)
4475-
4476- def test_detect_packages_changes_with_locked_and_ranges(self):
4477- """
4478- Ranges are used when reporting changes to 3 or more locked packages
4479- having consecutive ids.
4480- """
4481- message_store = self.broker_service.message_store
4482- message_store.set_accepted_types(["packages"])
4483-
4484- self.facade.set_package_lock("name1")
4485- self.facade.set_package_lock("name2", ">=", "version2")
4486- self.facade.set_package_lock("name3", "<", "version4")
4487-
4488- self.store.set_hash_ids({HASH1: 1, HASH2: 2, HASH3: 3})
4489- self.store.add_available([1, 2, 3])
4490-
4491- def got_result(result):
4492- self.assertMessages(message_store.get_pending_messages(),
4493- [{"type": "packages", "locked": [(1, 3)]}])
4494- self.assertEqual(sorted(self.store.get_locked()), [1, 2, 3])
4495-
4496- result = self.reporter.detect_packages_changes()
4497- return result.addCallback(got_result)
4498-
4499- def test_detect_packages_changes_with_locked_with_unknown_hash(self):
4500- """
4501- Locked packages whose hashes are unknown don't get reported.
4502- """
4503- self.facade.set_package_lock("name1")
4504-
4505- def got_result(result):
4506- self.assertEqual(self.store.get_locked(), [])
4507-
4508- result = self.reporter.detect_packages_changes()
4509- return result.addCallback(got_result)
4510-
4511- def test_detect_packages_changes_with_locked_and_previously_known(self):
4512- """
4513- We don't report locked packages we already know about.
4514- """
4515- message_store = self.broker_service.message_store
4516- message_store.set_accepted_types(["packages"])
4517-
4518- self.facade.set_package_lock("name1")
4519- self.facade.set_package_lock("name2", ">=", "version2")
4520-
4521- self.store.set_hash_ids({HASH1: 1, HASH2: 2})
4522- self.store.add_available([1, 2])
4523- self.store.add_locked([1])
4524-
4525- def got_result(result):
4526- self.assertMessages(message_store.get_pending_messages(),
4527- [{"type": "packages", "locked": [2]}])
4528-
4529- self.assertEqual(sorted(self.store.get_locked()), [1, 2])
4530-
4531- result = self.reporter.detect_packages_changes()
4532- return result.addCallback(got_result)
4533-
4534- def test_detect_packages_changes_with_not_locked(self):
4535- """
4536- We report when a package was previously locked and isn't anymore.
4537- """
4538- message_store = self.broker_service.message_store
4539- message_store.set_accepted_types(["packages"])
4540-
4541- self.store.set_hash_ids({HASH1: 1})
4542- self.store.add_available([1])
4543- self.store.add_locked([1])
4544-
4545- def got_result(result):
4546- self.assertMessages(message_store.get_pending_messages(),
4547- [{"type": "packages", "not-locked": [1]}])
4548- self.assertEqual(self.store.get_locked(), [])
4549-
4550- result = self.reporter.detect_packages_changes()
4551- return result.addCallback(got_result)
4552-
4553- def test_detect_package_locks_changes_with_create_locks(self):
4554- """
4555- If Smart indicates package locks we didn't know about, report
4556- them to the server.
4557- """
4558- message_store = self.broker_service.message_store
4559- message_store.set_accepted_types(["package-locks"])
4560-
4561- self.facade.set_package_lock("name")
4562-
4563- logging_mock = self.mocker.replace("logging.info")
4564- logging_mock("Queuing message with changes in known package locks:"
4565- " 1 created, 0 deleted.")
4566- self.mocker.replay()
4567-
4568- def got_result(result):
4569- self.assertMessages(message_store.get_pending_messages(),
4570- [{"type": "package-locks",
4571- "created": [("name", "", "")]}])
4572- self.assertEqual(self.store.get_package_locks(),
4573- [("name", "", "")])
4574-
4575- result = self.reporter.detect_package_locks_changes()
4576- return result.addCallback(got_result)
4577-
4578- def test_detect_package_locks_changes_with_already_known_locks(self):
4579- """
4580- We don't report changes about locks we already know about.
4581- """
4582- message_store = self.broker_service.message_store
4583- message_store.set_accepted_types(["package-locks"])
4584-
4585- self.facade.set_package_lock("name1")
4586- self.facade.set_package_lock("name2", "<", "1.2")
4587-
4588- self.store.add_package_locks([("name1", "", "")])
4589-
4590- logging_mock = self.mocker.replace("logging.info")
4591- logging_mock("Queuing message with changes in known package locks:"
4592- " 1 created, 0 deleted.")
4593- self.mocker.replay()
4594-
4595- def got_result(result):
4596- self.assertMessages(message_store.get_pending_messages(),
4597- [{"type": "package-locks",
4598- "created": [("name2", "<", "1.2")]}])
4599- self.assertEqual(sorted(self.store.get_package_locks()),
4600- [("name1", "", ""),
4601- ("name2", "<", "1.2")])
4602-
4603- result = self.reporter.detect_package_locks_changes()
4604- return result.addCallback(got_result)
4605-
4606- def test_detect_package_locks_changes_with_deleted_locks(self):
4607- """
4608- If Smart indicates newly unset package locks, report them to the
4609- server.
4610- """
4611- message_store = self.broker_service.message_store
4612- message_store.set_accepted_types(["package-locks"])
4613-
4614- self.store.add_package_locks([("name1", "", "")])
4615-
4616- logging_mock = self.mocker.replace("logging.info")
4617- logging_mock("Queuing message with changes in known package locks:"
4618- " 0 created, 1 deleted.")
4619- self.mocker.replay()
4620-
4621- def got_result(result):
4622- self.assertMessages(message_store.get_pending_messages(),
4623- [{"type": "package-locks",
4624- "deleted": [("name1", "", "")]}])
4625- self.assertEqual(self.store.get_package_locks(), [])
4626-
4627- result = self.reporter.detect_package_locks_changes()
4628- return result.addCallback(got_result)
4629-
4630- def test_detect_package_locks_changes_with_locked_already_known(self):
4631- """
4632- If we didn't detect any change in the package locks, we don't send any
4633- message, and we return a deferred resulting in C{False}.
4634- """
4635- message_store = self.broker_service.message_store
4636- message_store.set_accepted_types(["package-locks"])
4637-
4638- self.facade.set_package_lock("name1")
4639- self.store.add_package_locks([("name1", "", "")])
4640-
4641- def got_result(result):
4642- self.assertFalse(result)
4643- self.assertMessages(message_store.get_pending_messages(), [])
4644-
4645- result = self.reporter.detect_packages_changes()
4646- return result.addCallback(got_result)
4647-
4648-
4649-class PackageReporterAptTest(LandscapeTest, PackageReporterTestMixin):
4650-
4651- if not has_new_enough_apt:
4652- skip = "Can't use AptFacade on hardy"
4653-
4654- helpers = [AptFacadeHelper, SimpleRepositoryHelper, BrokerServiceHelper]
4655-
4656- Facade = AptFacade
4657-
4658- def setUp(self):
4659-
4660- def set_up(ignored):
4661- self.store = PackageStore(self.makeFile())
4662- self.config = PackageReporterConfiguration()
4663- self.reporter = PackageReporter(
4664- self.store, self.facade, self.remote, self.config)
4665- self.config.data_path = self.makeDir()
4666- os.mkdir(self.config.package_directory)
4667-
4668- result = super(PackageReporterAptTest, self).setUp()
4669- return result.addCallback(set_up)
4670-
4671- def _clear_repository(self):
4672- """Remove all packages from self.repository."""
4673- create_file(self.repository_dir + "/Packages", "")
4674-
4675- def set_pkg1_upgradable(self):
4676- """Make it so that package "name1" is considered to be upgradable.
4677-
4678- Return the hash of the package that upgrades "name1".
4679- """
4680- self._add_package_to_deb_dir(
4681- self.repository_dir, "name1", version="version2")
4682- self.facade.reload_channels()
4683- name1_upgrade = sorted(self.facade.get_packages_by_name("name1"))[1]
4684- return self.facade.get_package_hash(name1_upgrade)
4685-
4686- def set_pkg1_installed(self):
4687- """Make it so that package "name1" is considered installed."""
4688- self._install_deb_file(os.path.join(self.repository_dir, PKGNAME1))
4689-
4690- def _make_fake_apt_update(self, out="output", err="error", code=0):
4691- """Create a fake apt-update executable"""
4692- self.reporter.apt_update_filename = self.makeFile(
4693- "#!/bin/sh\n"
4694- "echo -n %s\n"
4695- "echo -n %s >&2\n"
4696- "exit %d" % (out, err, code))
4697- os.chmod(self.reporter.apt_update_filename, 0755)
4698-
4699 def test_run_apt_update(self):
4700 """
4701 The L{PackageReporter.run_apt_update} method should run apt-update.
4702@@ -1708,13 +1133,13 @@
4703 reactor.callWhenRunning(do_test)
4704 return deferred
4705
4706- def test_run_apt_update_with_force_smart_update(self):
4707+ def test_run_apt_update_with_force_apt_update(self):
4708 """
4709 L{PackageReporter.run_apt_update} forces an apt-update run if the
4710- '--force-smart-update' command line option was passed.
4711+ '--force-apt-update' command line option was passed.
4712 """
4713 self.makeFile("", path=self.config.update_stamp_filename)
4714- self.config.load(["--force-smart-update"])
4715+ self.config.load(["--force-apt-update"])
4716 self._make_fake_apt_update()
4717
4718 deferred = Deferred()
4719@@ -1730,7 +1155,7 @@
4720 reactor.callWhenRunning(do_test)
4721 return deferred
4722
4723- def test_run_apt_update_with_force_smart_update_if_sources_changed(self):
4724+ def test_run_apt_update_with_force_apt_update_if_sources_changed(self):
4725 """
4726 L{PackageReporter.run_apt_update} forces an apt-update run if the APT
4727 sources.list file has changed.
4728@@ -1929,7 +1354,22 @@
4729 return deferred
4730
4731
4732-class GlobalPackageReporterTestMixin(object):
4733+class GlobalPackageReporterAptTest(LandscapeTest):
4734+
4735+ helpers = [AptFacadeHelper, SimpleRepositoryHelper, BrokerServiceHelper]
4736+
4737+ def setUp(self):
4738+
4739+ def set_up(ignored):
4740+ self.store = FakePackageStore(self.makeFile())
4741+ self.config = PackageReporterConfiguration()
4742+ self.reporter = FakeGlobalReporter(
4743+ self.store, self.facade, self.remote, self.config)
4744+ self.config.data_path = self.makeDir()
4745+ os.mkdir(self.config.package_directory)
4746+
4747+ result = super(GlobalPackageReporterAptTest, self).setUp()
4748+ return result.addCallback(set_up)
4749
4750 def test_store_messages(self):
4751 """
4752@@ -1937,13 +1377,13 @@
4753 """
4754 message_store = self.broker_service.message_store
4755 message_store.set_accepted_types(["package-reporter-result"])
4756- self.reporter.smart_update_filename = self.makeFile(
4757+ self.reporter.apt_update_filename = self.makeFile(
4758 "#!/bin/sh\necho -n error >&2\necho -n output\nexit 0")
4759- os.chmod(self.reporter.smart_update_filename, 0755)
4760+ os.chmod(self.reporter.apt_update_filename, 0755)
4761 deferred = Deferred()
4762
4763 def do_test():
4764- result = self.reporter.run_smart_update()
4765+ result = self.reporter.run_apt_update()
4766
4767 def callback(ignore):
4768 message = {"type": "package-reporter-result",
4769@@ -1962,47 +1402,6 @@
4770 return deferred
4771
4772
4773-class GlobalPackageReporterAptTest(LandscapeTest,
4774- GlobalPackageReporterTestMixin):
4775-
4776- if not has_new_enough_apt:
4777- skip = "Can't use AptFacade on hardy"
4778-
4779- helpers = [AptFacadeHelper, SimpleRepositoryHelper, BrokerServiceHelper]
4780-
4781- def setUp(self):
4782-
4783- def set_up(ignored):
4784- self.store = FakePackageStore(self.makeFile())
4785- self.config = PackageReporterConfiguration()
4786- self.reporter = FakeGlobalReporter(
4787- self.store, self.facade, self.remote, self.config)
4788- self.config.data_path = self.makeDir()
4789- os.mkdir(self.config.package_directory)
4790-
4791- result = super(GlobalPackageReporterAptTest, self).setUp()
4792- return result.addCallback(set_up)
4793-
4794-
4795-class GlobalPackageReporterSmartTest(LandscapeTest,
4796- GlobalPackageReporterTestMixin):
4797-
4798- helpers = [SmartFacadeHelper, BrokerServiceHelper]
4799-
4800- def setUp(self):
4801-
4802- def set_up(ignored):
4803- self.store = FakePackageStore(self.makeFile())
4804- self.config = PackageReporterConfiguration()
4805- self.reporter = FakeGlobalReporter(
4806- self.store, self.facade, self.remote, self.config)
4807- self.config.data_path = self.makeDir()
4808- os.mkdir(self.config.package_directory)
4809-
4810- result = super(GlobalPackageReporterSmartTest, self).setUp()
4811- return result.addCallback(set_up)
4812-
4813-
4814 class FakePackageReporterTest(LandscapeTest):
4815
4816 helpers = [EnvironSaverHelper, BrokerServiceHelper]
4817
4818=== modified file 'landscape/package/tests/test_skeleton.py'
4819--- landscape/package/tests/test_skeleton.py 2012-03-19 09:33:34 +0000
4820+++ landscape/package/tests/test_skeleton.py 2012-06-04 14:08:28 +0000
4821@@ -1,21 +1,10 @@
4822-try:
4823- import smart
4824- from smart.cache import Package
4825-except ImportError:
4826- # Smart is optional if AptFacade is being used.
4827- pass
4828-
4829-from landscape.package.interface import (
4830- install_landscape_interface, uninstall_landscape_interface)
4831-
4832-from landscape.package.facade import has_new_enough_apt
4833 from landscape.package.skeleton import (
4834- build_skeleton, PackageTypeError, build_skeleton_apt, DEB_PROVIDES,
4835+ build_skeleton_apt, DEB_PROVIDES,
4836 DEB_NAME_PROVIDES, DEB_REQUIRES, DEB_OR_REQUIRES, DEB_UPGRADES,
4837 DEB_CONFLICTS)
4838
4839 from landscape.package.tests.helpers import (
4840- AptFacadeHelper, SmartHelper, HASH1, create_simple_repository, create_deb,
4841+ AptFacadeHelper, HASH1, create_simple_repository, create_deb,
4842 PKGNAME_MINIMAL, PKGDEB_MINIMAL, HASH_MINIMAL, PKGNAME_SIMPLE_RELATIONS,
4843 PKGDEB_SIMPLE_RELATIONS, HASH_SIMPLE_RELATIONS, PKGNAME_VERSION_RELATIONS,
4844 PKGDEB_VERSION_RELATIONS, HASH_VERSION_RELATIONS,
4845@@ -47,16 +36,32 @@
4846 PKGDEB_OR_RELATIONS)
4847
4848
4849-class SkeletonTestMixin(object):
4850- """Tests for building a skeleton from a package.
4851-
4852- This class should be mixed in to test different backends, like smart
4853- and apt.
4854-
4855- The main test case classes need to implement C{get_package(name)} to
4856- get a package by name, and C{build_skeleton(package, with_info,
4857- with_unicode}, which builds the skeleton.
4858- """
4859+class SkeletonAptTest(LandscapeTest):
4860+ """C{PackageSkeleton} tests for apt packages."""
4861+
4862+ helpers = [AptFacadeHelper, SkeletonTestHelper]
4863+
4864+ def setUp(self):
4865+ super(SkeletonAptTest, self).setUp()
4866+ self.facade.add_channel_deb_dir(self.skeleton_repository_dir)
4867+ # Don't use reload_channels(), since that causes the test setup
4868+ # depending on build_skeleton_apt working correctly, which makes
4869+ # it harder to do TDD for these tests.
4870+ self.facade._cache.open(None)
4871+ self.facade._cache.update(None)
4872+ self.facade._cache.open(None)
4873+
4874+ def get_package(self, name):
4875+ """Return the package with the specified name."""
4876+ # Don't use get_packages(), since that causes the test setup
4877+ # depending on build_skeleton_apt working correctly, which makes
4878+ # it harder to to TDD for these tests.
4879+ package = self.facade._cache[name]
4880+ return package.candidate
4881+
4882+ def build_skeleton(self, *args, **kwargs):
4883+ """Build the skeleton to be tested."""
4884+ return build_skeleton_apt(*args, **kwargs)
4885
4886 def test_build_skeleton(self):
4887 """
4888@@ -253,67 +258,3 @@
4889 (DEB_UPGRADES, "or-relations < 1.0")]
4890 self.assertEqual(relations, skeleton.relations)
4891 self.assertEqual(HASH_OR_RELATIONS, skeleton.get_hash())
4892-
4893-
4894-class SmartSkeletonTest(LandscapeTest, SkeletonTestMixin):
4895- """C{PackageSkeleton} tests for smart packages."""
4896-
4897- helpers = [SmartHelper, SkeletonTestHelper]
4898-
4899- def setUp(self):
4900- super(SmartSkeletonTest, self).setUp()
4901- install_landscape_interface()
4902- self.ctrl = smart.init(interface="landscape", datadir=self.smart_dir)
4903- smart.sysconf.set(
4904- "channels", {"alias": {"type": "deb-dir",
4905- "path": self.skeleton_repository_dir}})
4906- self.ctrl.reloadChannels()
4907- self.cache = self.ctrl.getCache()
4908-
4909- def tearDown(self):
4910- uninstall_landscape_interface()
4911- super(SmartSkeletonTest, self).tearDown()
4912-
4913- def get_package(self, name):
4914- """Return the package with the specified name."""
4915- [package] = self.cache.getPackages(name)
4916- return package
4917-
4918- def build_skeleton(self, *args, **kwargs):
4919- """Build the skeleton to be tested."""
4920- return build_skeleton(*args, **kwargs)
4921-
4922- def test_refuse_to_build_non_debian_packages(self):
4923- self.assertRaises(PackageTypeError, build_skeleton,
4924- Package("name", "version"))
4925-
4926-
4927-class SkeletonAptTest(LandscapeTest, SkeletonTestMixin):
4928- """C{PackageSkeleton} tests for apt packages."""
4929-
4930- if not has_new_enough_apt:
4931- skip = "Can't use AptFacade on hardy"
4932-
4933- helpers = [AptFacadeHelper, SkeletonTestHelper]
4934-
4935- def setUp(self):
4936- super(SkeletonAptTest, self).setUp()
4937- self.facade.add_channel_deb_dir(self.skeleton_repository_dir)
4938- # Don't use reload_channels(), since that causes the test setup
4939- # depending on build_skeleton_apt working correctly, which makes
4940- # it harder to to TDD for these tests.
4941- self.facade._cache.open(None)
4942- self.facade._cache.update(None)
4943- self.facade._cache.open(None)
4944-
4945- def get_package(self, name):
4946- """Return the package with the specified name."""
4947- # Don't use get_packages(), since that causes the test setup
4948- # depending on build_skeleton_apt working correctly, which makes
4949- # it harder to to TDD for these tests.
4950- package = self.facade._cache[name]
4951- return package.candidate
4952-
4953- def build_skeleton(self, *args, **kwargs):
4954- """Build the skeleton to be tested."""
4955- return build_skeleton_apt(*args, **kwargs)
4956
4957=== modified file 'landscape/package/tests/test_store.py'
4958--- landscape/package/tests/test_store.py 2011-07-18 15:16:18 +0000
4959+++ landscape/package/tests/test_store.py 2012-06-04 14:08:28 +0000
4960@@ -1,6 +1,5 @@
4961 import threading
4962 import time
4963-import sys
4964
4965 import sqlite3
4966 from landscape.tests.helpers import LandscapeTest
4967@@ -356,11 +355,9 @@
4968
4969 database = sqlite3.connect(filename)
4970 cursor = database.cursor()
4971- for table in ["package_locks", "locked"]:
4972- query = "pragma table_info(%s)" % table
4973- cursor.execute(query)
4974- result = cursor.fetchall()
4975- self.assertTrue(len(result) > 0)
4976+ cursor.execute("pragma table_info(locked)")
4977+ result = cursor.fetchall()
4978+ self.assertTrue(len(result) > 0)
4979
4980 def test_add_and_get_locked(self):
4981 """
4982@@ -401,103 +398,6 @@
4983 self.store1.clear_locked()
4984 self.assertEqual(self.store2.get_locked(), [])
4985
4986- def test_get_package_locks_with_no_lock(self):
4987- """
4988- L{PackageStore.get_package_locks} returns an empty list if no package
4989- locks are stored.
4990- """
4991- self.assertEqual(self.store1.get_package_locks(), [])
4992-
4993- def test_add_package_locks(self):
4994- """
4995- L{PackageStore.add_package_locks} adds a package lock to the store.
4996- """
4997- self.store1.add_package_locks([("name", "", "")])
4998- self.assertEqual(self.store2.get_package_locks(),
4999- [("name", "", "")])
5000-
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches