diff options
Diffstat (limited to 'tests')
65 files changed, 4008 insertions, 0 deletions
diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/_test_py2_string_handling.py b/tests/_test_py2_string_handling.py new file mode 100644 index 0000000..86709fb --- /dev/null +++ b/tests/_test_py2_string_handling.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2011 Michael Vogt <mvo@ubuntu.com> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +"""Regression test for a unicode decoding error in the status_details, +progress_download or error_properties attributes of the transaction, +see LP #724735. +""" + +__author__ = "Michael Vogt <mvo@glatzor.de>" + +import os +import sys +import unittest + +import dbus +from dbus.lowlevel import ErrorMessage, Message + +from aptdaemon.core import Transaction +from aptdaemon.errors import TransactionFailed +from aptdaemon.test import AptDaemonTestCase, Chroot + + +class TestUnicodeDecoding(AptDaemonTestCase): + + """Test the workaround.""" + + def setUp(self): + self.chroot = Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.start_dbus_daemon() + self.dbus = dbus.bus.BusConnection(self.dbus_address) + self.trans = Transaction(None, "role-test", None, + os.getpid(), os.getuid(), os.getgid(), + sys.argv[0], + "org.debian.apt.test", bus=self.dbus) + + def test(self): + # ensure we don't crash regardless if str or unicode is passed here + self.trans.status_details = "äää" + self.trans.status_details = u"äää" + + self.trans.progress_download = ("äö", "ß", "üöä", 1L, 2L, "ö") + self.trans.progress_download = (u"äö", u"ß", u"üöä", 1L, 2L, u"ö") + + self.trans.error = TransactionFailed("ERROR_TEST", "Mixed ä %s", u"öä") + self.trans.error = TransactionFailed("ERROR_TEST", u"Mixed ü %s", "öä") + self.trans.error = TransactionFailed("ERROR_TEST", "Str ä %s", "öä") + self.trans.error = TransactionFailed("ERROR_TEST", u"Uni ä %s", u"öä") + + def test_dbus_exception(self): + """This tests simulates the steps taken by the DBus bindings to + send an error reply, see LP# 761386""" + # The original error message that we get from python-apt + orig = "E:Die Paketliste oder die Statusdatei konnte nicht " \ + "eingelesen oder ge\xc3\xb6ffnet werden." + for msg in [u"E:Die Paketliste oder die Statusdatei konnte nicht " + u"eingelesen oder geöffnet werden.", + "E:Die Paketliste oder die Statusdatei konnte nicht " + "eingelesen oder geöffnet werden.", orig]: + # Create a simple DBus exception + error = TransactionFailed("ERROR_TEST", msg) + + # Taken from dbus.service._method_reply_error() + name = error.get_dbus_name() + content = error.get_dbus_message() + self.assertEqual(orig, content[12:]) + # The constructor of the ErrorMessage fails since we only use + # a fake Message + self.assertRaises(MemoryError, ErrorMessage, Message(), name, + content) + + def test_dbus_exception_lp846044(self): + e = TransactionFailed("foo", "bar") + e.details = u"ä" + foo = unicode(e) + self.assertEqual(foo, u"Transaction failed: None\nä") + foo = str(e) + self.assertEqual(foo, u"Transaction failed: None\nä".encode("utf-8")) + + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/_test_py3_string_handling.py b/tests/_test_py3_string_handling.py new file mode 100644 index 0000000..9773412 --- /dev/null +++ b/tests/_test_py3_string_handling.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2011 Michael Vogt <mvo@ubuntu.com> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +"""Regression test for a unicode decoding error in the status_details, +progress_download or error_properties attributes of the transaction, +see LP #724735. +""" + +__author__ = "Michael Vogt <mvo@glatzor.de>" + +import unittest + +from aptdaemon.errors import TransactionFailed +from aptdaemon.test import AptDaemonTestCase + + +class TestUnicodeDecodingPy3(AptDaemonTestCase): + + def test_dbus_exception_lp846044(self): + e = TransactionFailed("foo", "bar") + e.details = "ä" + self.assertEqual(str(e), "Transaction failed: None\nä") + + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/aptdaemon b/tests/aptdaemon new file mode 120000 index 0000000..d2811fd --- /dev/null +++ b/tests/aptdaemon @@ -0,0 +1 @@ +../aptdaemon
\ No newline at end of file diff --git a/tests/data/high-trust-repository-whitelist-broken.cfg b/tests/data/high-trust-repository-whitelist-broken.cfg new file mode 100644 index 0000000..513e99c --- /dev/null +++ b/tests/data/high-trust-repository-whitelist-broken.cfg @@ -0,0 +1,13 @@ + +This line makes this no longer a valid file and that is used in the tests + +[repo name1] +origin = Ubuntu +component = main +pkgnames = foo.* + +[repo name2] +origin = Debian-Security +component = non-free +pkgnames = ^bar$ + diff --git a/tests/data/high-trust-repository-whitelist.cfg b/tests/data/high-trust-repository-whitelist.cfg new file mode 100644 index 0000000..68113ac --- /dev/null +++ b/tests/data/high-trust-repository-whitelist.cfg @@ -0,0 +1,10 @@ + +[repo name1] +origin = Ubuntu +component = main +pkgnames = foo.* + +[repo whitelist2] +origin = Debian-Security +component = non-free +pkgnames = ^bar$
\ No newline at end of file diff --git a/tests/data/high-trust-repository-whitelist.d/high-trust-repository-whitelist-broken.cfg b/tests/data/high-trust-repository-whitelist.d/high-trust-repository-whitelist-broken.cfg new file mode 120000 index 0000000..3dea1a9 --- /dev/null +++ b/tests/data/high-trust-repository-whitelist.d/high-trust-repository-whitelist-broken.cfg @@ -0,0 +1 @@ +../high-trust-repository-whitelist-broken.cfg
\ No newline at end of file diff --git a/tests/data/high-trust-repository-whitelist.d/high-trust-repository-whitelist.cfg b/tests/data/high-trust-repository-whitelist.d/high-trust-repository-whitelist.cfg new file mode 120000 index 0000000..b5972cc --- /dev/null +++ b/tests/data/high-trust-repository-whitelist.d/high-trust-repository-whitelist.cfg @@ -0,0 +1 @@ +../high-trust-repository-whitelist.cfg
\ No newline at end of file diff --git a/tests/dbus.conf b/tests/dbus.conf new file mode 100644 index 0000000..6d7c2bc --- /dev/null +++ b/tests/dbus.conf @@ -0,0 +1,21 @@ +<!-- This configuration file controls the per-user-login-session message bus. + Add a session-local.conf and edit that rather than changing this + file directly. --> + +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> +<busconfig> + <type>system</type> + + <listen>unix:tmpdir=/tmp</listen> + + <policy context="default"> + <!-- Allow everything to be sent --> + <allow send_destination="*" eavesdrop="true"/> + <!-- Allow everything to be received --> + <allow eavesdrop="true"/> + <!-- Allow anyone to own anything --> + <allow own="*"/> + </policy> + +</busconfig> diff --git a/tests/debconf/aptdaemon.config b/tests/debconf/aptdaemon.config new file mode 100755 index 0000000..c7a8d43 --- /dev/null +++ b/tests/debconf/aptdaemon.config @@ -0,0 +1,10 @@ +#!/bin/sh + +set -e + +. /usr/share/debconf/confmodule + +db_input high aptdaemon/test || true +db_go || true + +exit 0 diff --git a/tests/debconf/aptdaemon.templates b/tests/debconf/aptdaemon.templates new file mode 100644 index 0000000..e226272 --- /dev/null +++ b/tests/debconf/aptdaemon.templates @@ -0,0 +1,5 @@ +Template: aptdaemon/test +Type: string +Default: bli bla blub +Description: This is a test + Huhu diff --git a/tests/dpkg-wrapper.sh b/tests/dpkg-wrapper.sh new file mode 100755 index 0000000..3880036 --- /dev/null +++ b/tests/dpkg-wrapper.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/fakeroot /usr/bin/dpkg $* diff --git a/tests/fake-polkitd.py b/tests/fake-polkitd.py new file mode 100755 index 0000000..e8dfa70 --- /dev/null +++ b/tests/fake-polkitd.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +"""Fake a PolicyKit daemon.""" + +from optparse import OptionParser +import sys + +import dbus +import dbus.mainloop.glib +import dbus.service +from gi.repository import GLib + +# Setup the DBus main loop +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + +class FakePolicyKitDaemon(dbus.service.Object): + + def __init__(self, allowed_actions): + self.allowed_actions = allowed_actions + bus_name = dbus.service.BusName("org.freedesktop.PolicyKit1", + dbus.SystemBus(), + do_not_queue=True) + dbus.service.Object.__init__(self, bus_name, + "/org/freedesktop/PolicyKit1/Authority") + self.loop = GLib.MainLoop() + + def run(self): + self.loop.run() + + @dbus.service.method("org.freedesktop.PolicyKit1.Authority", + in_signature='(sa{sv})sa{ss}us', + out_signature='(bba{ss})') + def CheckAuthorization(self, subject, action_id, details, flags, + cancellation_id): + if "all" in self.allowed_actions: + allowed = True + else: + allowed = action_id in self.allowed_actions + challenged = False + details = {"test": "test"} + return (allowed, challenged, details) + + @dbus.service.method("org.freedesktop.PolicyKit1.Authority", + in_signature='', out_signature='') + def Quit(self): + GLib.idle_add(self._quit) + + def _quit(self): + self.loop.quit() + sys.exit() + + +def main(): + parser = OptionParser() + parser.add_option("-a", "--allowed-actions", + default="", action="store", type="string", + dest="allowed_actions", + help="Comma separated list of allowed action ids") + options, args = parser.parse_args() + polkitd = FakePolicyKitDaemon(options.allowed_actions.split(",")) + polkitd.run() + +if __name__ == "__main__": + main() diff --git a/tests/fakeroot-apt-key b/tests/fakeroot-apt-key new file mode 100755 index 0000000..7be9971 --- /dev/null +++ b/tests/fakeroot-apt-key @@ -0,0 +1,2 @@ +#!/bin/sh +fakeroot /usr/bin/apt-key $* diff --git a/tests/regressions/aptdaemon b/tests/regressions/aptdaemon new file mode 120000 index 0000000..9b3d444 --- /dev/null +++ b/tests/regressions/aptdaemon @@ -0,0 +1 @@ +../../aptdaemon
\ No newline at end of file diff --git a/tests/regressions/test_lp722228.py b/tests/regressions/test_lp722228.py new file mode 100644 index 0000000..1f84376 --- /dev/null +++ b/tests/regressions/test_lp722228.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010 Michael Vogt <mvo@ubuntu.com> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +"""Regression test for the security issue CVE-2011-0725 tracked +in LP #722228. + +Thanks to Sergey Nizovtsev for spotting this issue. + +The UpdateCache method allows to specify an alternative sources.list +snippet to only update the repositories specified in the corresponding +configuration file. + +Aptdaemon did not restrict the path to the sources.list.d directory and +allowed to inject packages from malicious sources specified in a custom +sources.list and even to read every file on the system. +""" + +__author__ = "Michael Vogt <mvo@glatzor.de>" + +import os +import tempfile +import time +import unittest2 + +import apt_pkg +import dbus +import mock + +import aptdaemon.client +import aptdaemon.test +from aptdaemon.worker import AptWorker +from aptdaemon.errors import AptDaemonError + + +class TestFix(unittest2.TestCase): + + """Test the fix.""" + + def test_closed(self): + worker = AptWorker() + # We don't want to perform any cache changes + worker._cache = mock.Mock() + trans = mock.Mock() + # ensure normal operation keeps working + worker.update_cache(trans, None) + self.assertTrue(worker._cache.update.called) + worker._cache.reset_mock() + worker.update_cache(trans, "foobar.list") + self.assertTrue(worker._cache.update.called) + worker._cache.reset_mock() + worker.update_cache(trans, "/etc/apt/sources.list.d/foobar.list") + self.assertTrue(worker._cache.update.called) + worker._cache.reset_mock() + worker.update_cache(trans, "/etc/apt/sources.list") + self.assertTrue(worker._cache.update.called) + + # ensure absolute path is no longer working + worker._cache.reset_mock() + self.assertRaises(AptDaemonError, worker.update_cache, trans, + "/etc/fstab") + self.assertFalse(worker._cache.update.called) + worker._cache.reset_mock() + self.assertRaises(AptDaemonError, worker.update_cache, trans, + "/tmp/etc/apt/sources.list.d") + self.assertFalse(worker._cache.update.called) + worker._cache.reset_mock() + self.assertRaises(AptDaemonError, worker.update_cache, trans, + "/etc/apt/sources.list.d/../../tmp/evil.list") + self.assertFalse(worker._cache.update.called) + worker._cache.reset_mock() + self.assertRaises(AptDaemonError, worker.update_cache, trans, + "../../../../../../../../../tmp/evil.list") + self.assertFalse(worker._cache.update.called) + + +class TestExploit(aptdaemon.test.AptDaemonTestCase): + + """Test if the a possible exploit still exists.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon + self.start_fake_polkitd() + time.sleep(1) + # Create a file which containts a virtual secret + self.secrets_file = tempfile.NamedTemporaryFile(dir=self.chroot.path, + delete=False) + self.secrets_file.write("Oh oh!") + self.secrets_file.close() + + @unittest2.expectedFailure + def test(self): + """A possible exploit of the security issue. + Originally provided by Sergey Nizovtsev. + """ + repo_path = os.path.join(self.chroot.path, "repo") + lst_path = os.path.join(self.chroot.path, "malicious.list") + + arch = apt_pkg.config["APT::Architecture"] + + # Setup a pseudo repository and link the file which should be extracted + # to the Packages file + dir = os.path.join(repo_path, "dists/a/a/binary-%s" % arch) + os.makedirs(dir) + os.symlink(self.secrets_file.name, "%s/Packages" % dir) + # Create a malicious list file which injects the repo + with open(lst_path, "w") as lst_file: + lst_file.write("deb file://%s a a" % repo_path) + + client = aptdaemon.client.AptClient(self.bus) + exit = client.update_cache(sources_list=lst_path, wait=True) + self.assertEqual(exit, aptdaemon.enums.EXIT_SUCCESS) + + # Check if succeeded to leak the file content! + repo_path_encoded = apt_pkg.uri_to_filename("file://%s" % repo_path) + leaked_path = os.path.join(self.chroot.path, "var/lib/apt/lists/", + "%s_dists_a_a_binary-%s_" + "Packages" % (repo_path_encoded, arch)) + with open(leaked_path, "r") as leaked_file: + self.assertEqual(leaked_file.read(), "Oh oh!") + + +if __name__ == "__main__": + unittest2.main() + +# vim: ts=4 et sts=4 diff --git a/tests/regressions/test_lp768691.py b/tests/regressions/test_lp768691.py new file mode 100644 index 0000000..14e5fe9 --- /dev/null +++ b/tests/regressions/test_lp768691.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests if we can handle different encodings well.""" + +import locale +import logging +import os +import sys +import unittest + +from aptdaemon import core, enums, test, errors, utils + +DEBUG = True + +if sys.version >= '3': + unicode = str + + +class GettextTest(test.AptDaemonTestCase): + + """Regression test for LP: #768691 and LP: #926340 + + The gettext.translation.gettext() method returns a string in Python 2. + If we try to perform a string format operation, Python wants to convert + string to unicode. If the daemon is running with a different + default encoding as the translated message this results in an error. + By defaulf aptdaemon runs as C if activated by D-Bus. + """ + + def setUp(self): + # Use the mo files from the build + local_mo_files = os.path.join(test.get_tests_dir(), + "../build/mo") + if not os.path.isdir(local_mo_files): + self.skipTest("Please run setup.py build before since local mo " + "files are required. Run python setup.py build_i18n") + core.gettext._default_localedir = local_mo_files + + self.trans = core.Transaction(None, enums.ROLE_FIX_BROKEN_DEPENDS, + None, os.getpid(), os.getuid(), + sys.argv[0], "org.debian.apt.test", + connect=False) + self.codes = utils.IsoCodes("iso_639", tag="iso_639_1_code", + fallback_tag="iso_639_2T_code") + + def test(self): + """Test if the installation of an unauthenticated packages fails + if simulate hasn't been called explicitly before. + """ + self.trans._set_locale("de_DE.UTF-8") + ret = self.trans.gettext("CD/DVD '%s' is required") + self.assertTrue(isinstance(ret, unicode)) + error = errors.TransactionFailed(enums.ERROR_NO_PACKAGE, + "CD/DVD '%s' is required", "lala") + self.trans.error = error + + utils.gettext._default_localedir = "/usr/share/locale" + lang = self.codes.get_localised_name("en", "ru.UTF-8") + self.assertTrue(isinstance(lang, unicode)) + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/repo/Packages b/tests/repo/Packages new file mode 100644 index 0000000..68b585f --- /dev/null +++ b/tests/repo/Packages @@ -0,0 +1,217 @@ +Package: silly-important +Priority: important +Section: admin +Installed-Size: 32 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Filename: ./silly-important_0.1-0_all.deb +Size: 1792 +MD5sum: ef9a1eefd088a375ef58773831256205 +SHA1: 4075517d20fdd81d8642ab0febe7ad8c5fcde4f0 +SHA256: 3003723f0f2686a6ed700f364b0c13c966026c5e5f3b383969d87b5dba411d5e +Description: an essential package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package is an essential one. + +Package: silly-fail +Priority: extra +Section: admin +Installed-Size: 36 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Filename: ./silly-fail_0.1-0_all.deb +Size: 1874 +MD5sum: 623a67e49bb7a1351a9bf1ae72fc6cfb +SHA1: 76417770f2b788b680ef18be66b5a6c4ec51bc62 +SHA256: 45fea3eb64a427a288a90b12f42cc3a6abea8e8387efd4879b319db736890ebd +Description: installation fails + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This installation of this package will always fail. + +Package: silly-broken +Priority: extra +Section: admin +Installed-Size: 32 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Depends: silly-unavailable +Filename: ./silly-broken_0.1-0_all.deb +Size: 1840 +MD5sum: 78bbe306af637c18f5df9dc47bfbf41f +SHA1: bb63cdbde699fe2100349b0418af095e6d9f80fe +SHA256: a816e61369de433e261b5ad041e913ee3c140637825ce6613a5c99efbfd4c21b +Description: package with broken dependencies + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package cannot be installed because of a missing dependency. + +Package: silly-depend-base-lintian-broken +Priority: extra +Section: admin +Installed-Size: 32 +Architecture: all +Source: silly-packages +Version: 0.1-0 +Depends: silly-base +Filename: ./silly-depend-base-lintian-broken_0.1-0_all.deb +Size: 1758 +MD5sum: ba9e0b746b08fae8f8a8fbb4cf9ba41e +SHA1: 8bcaf6034b09383e461f0e366762e6b6683e69e2 +SHA256: ff1302170d232c21ab66f332e38c51b2af9b6d06d8f377ae5944465be9467c22 +Description: package depending on silly-base (but lintian broken) + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package depends on silly-base and has no "Maintainer" set + and the file owner is totally wrong so lintian complains about it. + +Package: silly-essential +Essential: yes +Priority: extra +Section: admin +Installed-Size: 32 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Filename: ./silly-essential_0.1-0_all.deb +Size: 1800 +MD5sum: 492c977ce9b2f1b6a51d7c475aad058b +SHA1: 06fb9a5efb07f72edbd297d2a21cffd1787a2388 +SHA256: e516159e99bd40d860515e4c9af251ab056eaabae58ea3f5ee11eecc4f3bee50 +Description: an essential package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package is an essential one. + +Package: silly-postinst-input +Priority: extra +Section: admin +Installed-Size: 36 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Filename: ./silly-postinst-input_0.1-0_all.deb +Size: 1906 +MD5sum: 99eecdacbcdf95b9e7b3b0c50f812a8d +SHA1: c066b13414faa9931ff688c29f6dbcf4809861a9 +SHA256: ce6e4f7f59c3d1da45ff0b3e8e54ebdcf9a5b44edeccf9fc04c96daec5cfa020 +Description: breaks your non-interactive package manager + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package will wait for user input in the postinst script. + +Package: silly-config +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Filename: ./silly-config_0.1-0_all.deb +Size: 1928 +MD5sum: 565698b052640ed3d514f6b38ad457c7 +SHA1: e7169cc58f10e8ff9481cf31b2ffb947bc99f617 +SHA256: 255f025bae5b24a91158e7daa986f9bf59146ab1895f39452104eb97c412d190 +Description: wants to update a locally changed config file + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package will install a configuration file. + +Package: gstreamer0.10-silly +Priority: extra +Section: admin +Installed-Size: 168 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Depends: libc6 (>= 2.7-1), libglib2.0-0 (>= 2.16.0), libgstreamer-plugins-base0.10-0 (>= 0.10.0), libgstreamer0.10-0 (>= 0.10.14), libogg0 (>= 1.0rc3) +Filename: ./gstreamer0.10-silly_0.1-0_all.deb +Size: 52016 +MD5sum: bbaf259e0dfcb39050061181d2a13755 +SHA1: be59be2d82b7f57097f387a22f5f295d202d9c1d +SHA256: 6b91b67de10ae547cd4c648ef343c8acd35e626e4a1ac20df1aaae51d6ec6328 +Description: gstreamer plugin test package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package is a GStreamer test plugin package. +Gstreamer-Version: 0.10 +Gstreamer-Decoders: audio/ac3; audio/mpeg, mpegversion=(int){ 1, 2, 4 }; +Gstreamer-Elements: ac3parse + +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 32 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Filename: ./silly-base_0.1-0_all.deb +Size: 1824 +MD5sum: 81ba1cf86142c466f35a36a11b5b7b52 +SHA1: f949c8e5962a43fbcd4f7d67df0ebe741052c497 +SHA256: a7c2a30abdb6488d5c3d2894db398f5dfafbc6be098da1135822be4e3ac94b32 +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + +Package: silly-depend-base +Priority: extra +Section: admin +Installed-Size: 32 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages +Version: 0.1-0 +Depends: silly-base +Filename: ./silly-depend-base_0.1-0_all.deb +Size: 1812 +MD5sum: 3ee7181283e4926558d2afdf7b2657f1 +SHA1: 8294794b1727e22b123866f9124431a2c7b79380 +SHA256: 5fa74f7bdc0d207188790419130330becb0cf7484a972762ed512090885016f9 +Description: package depending on silly-base + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package depends on silly-base. + +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + diff --git a/tests/repo/Release b/tests/repo/Release new file mode 100644 index 0000000..1a116a9 --- /dev/null +++ b/tests/repo/Release @@ -0,0 +1,22 @@ +Date: Wed, 09 May 2012 01:24:59 UTC +MD5Sum: + da80d4a76b8c6119b697558524cdaf71 7325 Packages + d41d8cd98f00b204e9800998ecf8427e 0 Release + 0bd018b62f0031d1ee4993896f50ddd5 782 backports/Packages + cec65a680d0777c2f8f06bbaa503d345 899 backports/Release + 0bd018b62f0031d1ee4993896f50ddd5 782 security/Packages + 4fa3f7d1e32aa2bc06b63bf7519d9e64 895 security/Release +SHA1: + c911274d83557d97f04bbab8d681efd11450b695 7325 Packages + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 Release + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 backports/Packages + 71e98c6dbe072ebbf7c959c4ebc496743fc4d3ae 899 backports/Release + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 security/Packages + 8e14bd91f977a2e12d3e30b3649c3f772e84126e 895 security/Release +SHA256: + 9ee3b2e2d7cd1d6f567a7914d4a78e201b80b65d01d21a0865f1d5a9f5cceab2 7325 Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 Release + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 backports/Packages + 6e85dc9fc5506e5564bd9914abc165f0c50ac15d34ede44c31b363468ef641b5 899 backports/Release + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 security/Packages + cfdf15ef290d6ab0c9e3afff718dec679d78a07b4364cbfc46be9d9ad4296ca1 895 security/Release diff --git a/tests/repo/Release.gpg b/tests/repo/Release.gpg new file mode 100644 index 0000000..868d5ef --- /dev/null +++ b/tests/repo/Release.gpg @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.12 (GNU/Linux) + +iQEcBAABCAAGBQJPqculAAoJEB8w/lhZqRjZCeEH/jpt4El5MNKUR3Eu0nUR9CYn +MNo0ZuFGQ+y11yL+FZ7nkwKIFdbFDwcR/5GFPZBPvltTmuBkbSa7sWNU9jyPwJHC +7IcKVw40C87lMUDN/rRFdGMhYZzpu5n2F74P7frwlgu16yRq5towprwNdRt+6k9F +LmVvo/os8/p/WwFCPX10ARdm+JTZa/G8OTfSSu6iWmoClOQ/JvYGnmzxyqVICFiF +lR2YGLAW+RXOo/B9jhJWpz6f5/0MPVd8SpHaONV8RxZeOEkJVTeWYXg9HCIBCjUc +azCiflzQpTC/cVFvjfEaEP23KHaSV2dTMp0fq91yMCiPq/wDqyB0M64Q8xAMN00= +=FgqZ +-----END PGP SIGNATURE----- diff --git a/tests/repo/backports/Packages b/tests/repo/backports/Packages new file mode 100644 index 0000000..b8492c6 --- /dev/null +++ b/tests/repo/backports/Packages @@ -0,0 +1,20 @@ +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + diff --git a/tests/repo/backports/Packages.gpg b/tests/repo/backports/Packages.gpg new file mode 100644 index 0000000..3b72d67 --- /dev/null +++ b/tests/repo/backports/Packages.gpg @@ -0,0 +1,34 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (GNU/Linux) + +iQEcBAEBCAAGBQJO3ZylAAoJEGg8U8fPmC0YooQH/inTQPInDCiN3pTDvzWfV16F +Ea+UpwBN0vzuyS6f3xmhLRxLQpuz/yk8buc1H+f/XKn6eygydJRFwIEgtdWAN/Tk +eG9I4c5zYiHzZnNWe4XNBhRdPVkIHPkbmbRs/RvDiM5Cq0LvXIe0X0RV+empJyrC +EgKbt3PJxh8qpMfrf/OIF+GkSqAug4tq0i0n6QxLOi0raeb9PjfDwErmBpbLDSFg +XyDnNvPET5BtWxjgupOwoFqs2QRkrLv10JBdGRz+7qG6WhH1BCAOfzYxxCtn++Ip +kmwo8c/pmtOr1BzZyyNMWP8nvVtB728eb/M84WGYynIEyCObUQ+Q2HVsXcsPQLc= +=j3Nx +-----END PGP SIGNATURE----- diff --git a/tests/repo/backports/Release b/tests/repo/backports/Release new file mode 100644 index 0000000..0ed3dca --- /dev/null +++ b/tests/repo/backports/Release @@ -0,0 +1,16 @@ +Origin: Debian +Suite: sid-backports +Codename: lalelu +Date: Tue, 06 Dec 2011 04:40:53 UTC +MD5Sum: + 0bd018b62f0031d1ee4993896f50ddd5 782 Packages + d41d8cd98f00b204e9800998ecf8427e 0 Release +SHA1: + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 Packages + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 Release +SHA256: + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 Release +SHA512: + 984c9203b8e534b9b9cc486b21da94cf807428dc1d2daa56427a870f4d53111c58ce749c35509a5fcf7112433d7a403830378a0f482354fb382c0aa7a25bdbc2 782 Packages + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e 0 Release diff --git a/tests/repo/backports/Release.gpg b/tests/repo/backports/Release.gpg new file mode 100644 index 0000000..38f5901 --- /dev/null +++ b/tests/repo/backports/Release.gpg @@ -0,0 +1,30 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Origin: Debian +Suite: sid-backports +Codename: lalelu +Date: Tue, 06 Dec 2011 04:40:53 UTC +MD5Sum: + 0bd018b62f0031d1ee4993896f50ddd5 782 Packages + d41d8cd98f00b204e9800998ecf8427e 0 Release +SHA1: + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 Packages + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 Release +SHA256: + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 Release +SHA512: + 984c9203b8e534b9b9cc486b21da94cf807428dc1d2daa56427a870f4d53111c58ce749c35509a5fcf7112433d7a403830378a0f482354fb382c0aa7a25bdbc2 782 Packages + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e 0 Release +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (GNU/Linux) + +iQEcBAEBCAAGBQJO3aBFAAoJEGg8U8fPmC0Y+esIAMigdsJQneBznIwfTsA6EMSB +wKegB/IAl7VJDPMXoUAdu9kVxaJbScrrhHJ6lFdIobgIA+5zWfJjMnvujsM5PDAv +t8xzh/sU3m3HzR8iBDi10BO+SleKps/fKHnnQZOP8msf03rzydYUTbQI2KVhy+C1 +MSx/KTAD4a/0NPKMw09kKNqfU0uoFLnJFZEO3kVYt3hIZyGjtvw2QoEPMphNMixk +Qq7YVhKiXw/QB318dPb065bXQePvc1EWxQuR9RgtCCM+9FMyOyF1NwAzOc8XzjEY +qHib6JzkbH+tBLqq5AmVLOTR07rndGQQuNtu70BkIGkuZC8KpDRMRTq5mi1cipg= +=CUOV +-----END PGP SIGNATURE----- diff --git a/tests/repo/glatzor.gpg b/tests/repo/glatzor.gpg new file mode 100644 index 0000000..8bb45d3 --- /dev/null +++ b/tests/repo/glatzor.gpg @@ -0,0 +1,115 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.12 (GNU/Linux) + +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 +8fwzmD4MW2kyoYtEl1VGBL9PjLSZ8Ns= +=BAJh +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/repo/gstreamer0.10-silly_0.1-0_all.deb b/tests/repo/gstreamer0.10-silly_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..7eee4ea --- /dev/null +++ b/tests/repo/gstreamer0.10-silly_0.1-0_all.deb diff --git a/tests/repo/security/Packages b/tests/repo/security/Packages new file mode 100644 index 0000000..b8492c6 --- /dev/null +++ b/tests/repo/security/Packages @@ -0,0 +1,20 @@ +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + diff --git a/tests/repo/security/Packages.gpg b/tests/repo/security/Packages.gpg new file mode 100644 index 0000000..3b72d67 --- /dev/null +++ b/tests/repo/security/Packages.gpg @@ -0,0 +1,34 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (GNU/Linux) + +iQEcBAEBCAAGBQJO3ZylAAoJEGg8U8fPmC0YooQH/inTQPInDCiN3pTDvzWfV16F +Ea+UpwBN0vzuyS6f3xmhLRxLQpuz/yk8buc1H+f/XKn6eygydJRFwIEgtdWAN/Tk +eG9I4c5zYiHzZnNWe4XNBhRdPVkIHPkbmbRs/RvDiM5Cq0LvXIe0X0RV+empJyrC +EgKbt3PJxh8qpMfrf/OIF+GkSqAug4tq0i0n6QxLOi0raeb9PjfDwErmBpbLDSFg +XyDnNvPET5BtWxjgupOwoFqs2QRkrLv10JBdGRz+7qG6WhH1BCAOfzYxxCtn++Ip +kmwo8c/pmtOr1BzZyyNMWP8nvVtB728eb/M84WGYynIEyCObUQ+Q2HVsXcsPQLc= +=j3Nx +-----END PGP SIGNATURE----- diff --git a/tests/repo/security/Release b/tests/repo/security/Release new file mode 100644 index 0000000..e8ebce5 --- /dev/null +++ b/tests/repo/security/Release @@ -0,0 +1,16 @@ +Origin: Debian +Label: Debian-Security +Suite: sid +Date: Tue, 06 Dec 2011 04:40:53 UTC +MD5Sum: + 0bd018b62f0031d1ee4993896f50ddd5 782 Packages + d41d8cd98f00b204e9800998ecf8427e 0 Release +SHA1: + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 Packages + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 Release +SHA256: + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 Release +SHA512: + 984c9203b8e534b9b9cc486b21da94cf807428dc1d2daa56427a870f4d53111c58ce749c35509a5fcf7112433d7a403830378a0f482354fb382c0aa7a25bdbc2 782 Packages + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e 0 Release diff --git a/tests/repo/security/Release.gpg b/tests/repo/security/Release.gpg new file mode 100644 index 0000000..d012876 --- /dev/null +++ b/tests/repo/security/Release.gpg @@ -0,0 +1,30 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Origin: Debian +Label: Debian-Security +Suite: sid +Date: Tue, 06 Dec 2011 04:40:53 UTC +MD5Sum: + 0bd018b62f0031d1ee4993896f50ddd5 782 Packages + d41d8cd98f00b204e9800998ecf8427e 0 Release +SHA1: + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 Packages + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 Release +SHA256: + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 Release +SHA512: + 984c9203b8e534b9b9cc486b21da94cf807428dc1d2daa56427a870f4d53111c58ce749c35509a5fcf7112433d7a403830378a0f482354fb382c0aa7a25bdbc2 782 Packages + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e 0 Release +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (GNU/Linux) + +iQEcBAEBCAAGBQJO3aA1AAoJEGg8U8fPmC0YigkIAK9CXZukop9g2byChtM8TRsN +t5K3epgmAoxws7yFF0gZJdFk7p6EMVp+13o5R4WYZhTfVQO8AFcYrEFvb17CGY9g +Y7JYAl79lkewZJuG5LYFaxUlyczft0p8yqRShpEMp+kKHUuHbpvABfVsLVh8dRWD +ydm4xIxHD558QSctn0Do+yEuzEJvKuYfp2h5LedXcpylhXjgMchfDhZyvNhPhCEB +uEb8/o458SILq4XWMSlkyOof/Rn/X7afbtJlG/oq0tSZ8SNYYkVj49TUPPGjD+zw +cU7LY3G+oEsDMl9XvUTEjX8zfeqcvpfBDa/d5KyXV2ZRg0EJB7mgLVIdBNdhxqA= +=8bi0 +-----END PGP SIGNATURE----- diff --git a/tests/repo/silly-base_0.1-0_all.deb b/tests/repo/silly-base_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..cb10c10 --- /dev/null +++ b/tests/repo/silly-base_0.1-0_all.deb diff --git a/tests/repo/silly-base_0.1-0update1_all.deb b/tests/repo/silly-base_0.1-0update1_all.deb Binary files differnew file mode 100644 index 0000000..858514f --- /dev/null +++ b/tests/repo/silly-base_0.1-0update1_all.deb diff --git a/tests/repo/silly-broken_0.1-0_all.deb b/tests/repo/silly-broken_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..ced1e29 --- /dev/null +++ b/tests/repo/silly-broken_0.1-0_all.deb diff --git a/tests/repo/silly-bully_0.1-0_all.deb b/tests/repo/silly-bully_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..54c3b5d --- /dev/null +++ b/tests/repo/silly-bully_0.1-0_all.deb diff --git a/tests/repo/silly-config_0.1-0_all.deb b/tests/repo/silly-config_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..c75ec3a --- /dev/null +++ b/tests/repo/silly-config_0.1-0_all.deb diff --git a/tests/repo/silly-depend-base-lintian-broken_0.1-0_all.deb b/tests/repo/silly-depend-base-lintian-broken_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..34c09b8 --- /dev/null +++ b/tests/repo/silly-depend-base-lintian-broken_0.1-0_all.deb diff --git a/tests/repo/silly-depend-base_0.1-0_all.deb b/tests/repo/silly-depend-base_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..56cdc36 --- /dev/null +++ b/tests/repo/silly-depend-base_0.1-0_all.deb diff --git a/tests/repo/silly-essential_0.1-0_all.deb b/tests/repo/silly-essential_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..43c3079 --- /dev/null +++ b/tests/repo/silly-essential_0.1-0_all.deb diff --git a/tests/repo/silly-fail_0.1-0_all.deb b/tests/repo/silly-fail_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..f08cfc0 --- /dev/null +++ b/tests/repo/silly-fail_0.1-0_all.deb diff --git a/tests/repo/silly-important_0.1-0_all.deb b/tests/repo/silly-important_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..5d9ab51 --- /dev/null +++ b/tests/repo/silly-important_0.1-0_all.deb diff --git a/tests/repo/silly-postinst-input_0.1-0_all.deb b/tests/repo/silly-postinst-input_0.1-0_all.deb Binary files differnew file mode 100644 index 0000000..89e0c3d --- /dev/null +++ b/tests/repo/silly-postinst-input_0.1-0_all.deb diff --git a/tests/repo/whitelisted/Packages b/tests/repo/whitelisted/Packages new file mode 100644 index 0000000..af8eaef --- /dev/null +++ b/tests/repo/whitelisted/Packages @@ -0,0 +1,34 @@ +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + +Package: other-pkg +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Version: 2.0 +Filename: ./other-pkg_2.0_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: another working package diff --git a/tests/repo/whitelisted/Packages.gpg b/tests/repo/whitelisted/Packages.gpg new file mode 100644 index 0000000..3b72d67 --- /dev/null +++ b/tests/repo/whitelisted/Packages.gpg @@ -0,0 +1,34 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +Package: silly-base +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-packages (0.1-0) +Version: 0.1-0update1 +Filename: ./silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +SHA512: e9eded74e2449a98b02828539c55a83de85a762d2361cd8c929292eb9c5a6e5a9b8eb9b64c26c45d7b73280e12a280cd799a9b831126e484bcf55b56456d559f +Description: working package + Silly packages is a set of packages which will break your package + management tool. They are created only for debugging purposes. + . + This package doesn't contain any files and should always be installable. + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (GNU/Linux) + +iQEcBAEBCAAGBQJO3ZylAAoJEGg8U8fPmC0YooQH/inTQPInDCiN3pTDvzWfV16F +Ea+UpwBN0vzuyS6f3xmhLRxLQpuz/yk8buc1H+f/XKn6eygydJRFwIEgtdWAN/Tk +eG9I4c5zYiHzZnNWe4XNBhRdPVkIHPkbmbRs/RvDiM5Cq0LvXIe0X0RV+empJyrC +EgKbt3PJxh8qpMfrf/OIF+GkSqAug4tq0i0n6QxLOi0raeb9PjfDwErmBpbLDSFg +XyDnNvPET5BtWxjgupOwoFqs2QRkrLv10JBdGRz+7qG6WhH1BCAOfzYxxCtn++Ip +kmwo8c/pmtOr1BzZyyNMWP8nvVtB728eb/M84WGYynIEyCObUQ+Q2HVsXcsPQLc= +=j3Nx +-----END PGP SIGNATURE----- diff --git a/tests/repo/whitelisted/Release b/tests/repo/whitelisted/Release new file mode 100644 index 0000000..859c02c --- /dev/null +++ b/tests/repo/whitelisted/Release @@ -0,0 +1,17 @@ +Origin: Ubuntu +Label: Ubuntu-Whitelisted +Components: main +Suite: sid +Date: Tue, 06 Dec 2011 04:40:53 UTC +MD5Sum: + 0bd018b62f0031d1ee4993896f50ddd5 782 Packages + d41d8cd98f00b204e9800998ecf8427e 0 Release +SHA1: + 42201c0ab580cb2d557ca22a7ed04717a68b2e6e 782 Packages + da39a3ee5e6b4b0d3255bfef95601890afd80709 0 Release +SHA256: + 950233659ae7e86ac11ae886298963e57f4414691881af1357456c6a4038ef91 782 Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 Release +SHA512: + 984c9203b8e534b9b9cc486b21da94cf807428dc1d2daa56427a870f4d53111c58ce749c35509a5fcf7112433d7a403830378a0f482354fb382c0aa7a25bdbc2 782 Packages + cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e 0 Release diff --git a/tests/repo/whitelisted/Release.gpg b/tests/repo/whitelisted/Release.gpg new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/repo/whitelisted/Release.gpg diff --git a/tests/repo/whitelisted/silly-base_0.1-0update1_all.deb b/tests/repo/whitelisted/silly-base_0.1-0update1_all.deb new file mode 120000 index 0000000..a960865 --- /dev/null +++ b/tests/repo/whitelisted/silly-base_0.1-0update1_all.deb @@ -0,0 +1 @@ +../silly-base_0.1-0update1_all.deb
\ No newline at end of file diff --git a/tests/test_cdrom.py b/tests/test_cdrom.py new file mode 100644 index 0000000..352bbbe --- /dev/null +++ b/tests/test_cdrom.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the client module.""" + +import logging +import time +import unittest + +import defer +import dbus + +import aptdaemon.client +import aptdaemon.loop +import aptdaemon.enums + +import aptdaemon.test + +DEBUG = True + + +class CDROMTestCase(aptdaemon.test.AptDaemonTestCase): + + """Test the installation from removable media, e.g. CDROMs.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.chroot.add_trusted_key() + self.chroot.add_cdrom_repository() + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon + self.start_fake_polkitd() + time.sleep(1) + self.called = False + + @defer.inline_callbacks + def _on_medium_required_cancel(self, trans, medium, mount_point): + yield trans.cancel() + + @defer.inline_callbacks + def _on_medium_required(self, trans, medium, mount_point): + if self.called: + # Abort if we get asked twice for the cdrom + yield trans.cancel() + self.chroot.mount_cdrom() + self.called = True + yield trans.provide_medium(medium) + + def _on_finished(self, trans, exit): + """Callback to stop the mainloop after a transaction is done.""" + aptdaemon.loop.mainloop.quit() + + def test(self): + """Test changing media.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-depend-base"]) + trans.connect("finished", self._on_finished) + trans.connect("medium-required", self._on_medium_required) + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_SUCCESS) + + def test_cancel(self): + """Test cancelling a required medium request.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-depend-base"]) + trans.connect("finished", self._on_finished) + trans.connect("medium-required", self._on_medium_required_cancel) + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_CANCELLED) + + self.chroot.mount_cdrom() + + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_SUCCESS) + + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..c7370c6 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the client module.""" + +import logging +import time +import unittest + +import dbus +import defer + +from gi.repository import GObject + +import aptdaemon.client +import aptdaemon.loop +import aptdaemon.enums +import aptdaemon.errors + +import aptdaemon.test + +DEBUG = True + + +class ClientTestNotAuthorized(aptdaemon.test.AptDaemonTestCase): + + """Test the python client.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.chroot.add_test_repository() + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon and disallow all actions + self.start_fake_polkitd("none") + time.sleep(1) + + def _on_finished(self, trans, exit): + """Callback to stop the mainloop after a transaction is done.""" + aptdaemon.loop.mainloop.quit() + + def test_auth_failed(self): + """Test the failing of an unauthorized transaction""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.update_cache() + trans.connect("finished", self._on_finished) + try: + yield trans.run() + except aptdaemon.errors.NotAuthorizedError as error: + print(error) + except Exception as error: + self.fail("Wrong exception: %s" % error) + else: + self.fail("Authorization passed (sic!)") + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.error.code, + aptdaemon.enums.ERROR_NOT_AUTHORIZED) + + +class ClientTest(aptdaemon.test.AptDaemonTestCase): + + """Test the python client.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.chroot.add_test_repository() + self.chroot.add_trusted_key() + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon + self.start_fake_polkitd() + time.sleep(1) + + def _on_finished(self, trans, exit): + """Callback to stop the mainloop after a transaction is done.""" + aptdaemon.loop.mainloop.quit() + + def test_sync(self): + """Test synchronous calls to the client.""" + self.client = aptdaemon.client.AptClient(self.bus) + trans = self.client.update_cache() + trans.connect("finished", self._on_finished) + trans.run() + aptdaemon.loop.mainloop.run() + self.assertEqual(trans.exit, aptdaemon.enums.EXIT_SUCCESS) + + def test_deferred(self): + """Test deferred calls to the client.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.update_cache() + trans.connect("finished", self._on_finished) + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_SUCCESS) + + def test_client_methods_sync(self): + """ Test most client methods (syncronous) """ + test_methods = [ + ("enable_distro_component", ("universe",)), + ("add_repository", ("deb", "http://archive.ubuntu.com/ubuntu", + "lucid", "restricted"))] + client = aptdaemon.client.AptClient(self.bus) + for (method, args) in test_methods: + f = getattr(client, method) + exit = f(*args, wait=True) + self.assertEqual(exit, aptdaemon.enums.EXIT_SUCCESS) + + def test_simulation_error(self): + """Test if a simulation fails in a correct way.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-broken"]) + trans.connect("finished", self._on_finished) + yield trans.simulate() + self.fail("We should never have been here") + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.value.code, + aptdaemon.enums.ERROR_DEP_RESOLUTION_FAILED) + + def test_run_error(self): + """Test if a simulation during run fails in a correct way.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-broken"]) + trans.connect("finished", self._on_finished) + yield trans.run() + self.fail("We should never have been here") + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.value.code, + aptdaemon.enums.ERROR_DEP_RESOLUTION_FAILED) + + def test_tid_caching(self): + """Test if calling Client with identical TIDs uses caching.""" + + tid = "/meep" + trans = aptdaemon.client.AptTransaction(tid, bus=self.bus) + trans2 = aptdaemon.client.AptTransaction(tid, bus=self.bus) + trans3 = aptdaemon.client.AptTransaction("/meep2", bus=self.bus) + self.assertEqual(trans, trans2) + self.assertNotEqual(trans, trans3) + + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_configfileprompt.py b/tests/test_configfileprompt.py new file mode 100644 index 0000000..2f1ede4 --- /dev/null +++ b/tests/test_configfileprompt.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the config file handling.""" + +import logging +import os +import time +import unittest + +import defer +import dbus + +import aptdaemon.client +import aptdaemon.loop +import aptdaemon.enums + +import aptdaemon.test + +DEBUG = True +REPO_PATH = os.path.join(aptdaemon.test.get_tests_dir(), "repo") + + +class ConfigFilePromptTestCase(aptdaemon.test.AptDaemonTestCase): + + """Test the replacement of config files.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.chroot.add_test_repository() + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon + self.start_fake_polkitd() + time.sleep(1) + self.called = False + # Create a fake config file which gets overwritten by silly-config + self.config_path = os.path.join(self.chroot.path, + "etc/silly-packages.cfg") + with open(self.config_path, "w") as config: + config.write("BliBlaBlub") + + @defer.inline_callbacks + def _on_config_file_conflict(self, trans, config_old, config_new, answer): + self.assertEqual(trans.config_file_conflict, (config_old, config_new)) + if answer == "urgs": + # Check if cancelling is forbidden + try: + yield trans.cancel() + except aptdaemon.errors.AptDaemonError as error: + self.assertTrue(str(error), + "org.debian.apt: Could not cancel transaction") + # Check if we fail correctly on wrong answers + try: + yield trans.resolve_config_file_conflict(config_old, + "a&&dasmk") + except aptdaemon.errors.AptDaemonError as error: + self.assertTrue(str(error).index("Invalid value")) + yield trans.resolve_config_file_conflict(config_old, "replace") + else: + self.fail("Failed to detect invalid answer") + else: + yield trans.resolve_config_file_conflict(config_old, answer) + + def _on_finished(self, trans, exit): + """Callback to stop the mainloop after a transaction is done.""" + aptdaemon.loop.mainloop.quit() + + def test_keep(self): + """Test keeping the current configuration file.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-config"]) + trans.connect("finished", self._on_finished) + trans.connect("config-file-conflict", + self._on_config_file_conflict, + "keep") + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_SUCCESS) + with open(self.config_path) as config: + self.assertEqual(config.read(), + "BliBlaBlub") + with open("%s.dpkg-dist" % self.config_path) as config_dist: + self.assertEqual(config_dist.read(), + "#Just another config file.\n") + + def test_replace(self): + """Test replacing the current configuration file.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-config"]) + trans.connect("finished", self._on_finished) + trans.connect("config-file-conflict", + self._on_config_file_conflict, + "replace") + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_SUCCESS) + with open(self.config_path) as config: + self.assertEqual(config.read(), + "#Just another config file.\n") + with open("%s.dpkg-old" % self.config_path) as config_old: + self.assertEqual(config_old.read(), + "BliBlaBlub") + + def test_fail(self): + """Test failing correctly.""" + @defer.inline_callbacks + def run(): + self.client = aptdaemon.client.AptClient(self.bus) + trans = yield self.client.install_packages(["silly-config"]) + yield trans.set_locale("C") + trans.connect("finished", self._on_finished) + trans.connect("config-file-conflict", + self._on_config_file_conflict, + "urgs") + yield trans.run() + defer.return_value(trans) + deferred = run() + aptdaemon.loop.mainloop.run() + self.assertEqual(deferred.result.exit, aptdaemon.enums.EXIT_SUCCESS) + with open(self.config_path) as config: + self.assertEqual(config.read(), + "#Just another config file.\n") + with open("%s.dpkg-old" % self.config_path) as config_old: + self.assertEqual(config_old.read(), + "BliBlaBlub") + + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_configparser.py b/tests/test_configparser.py new file mode 100644 index 0000000..006404b --- /dev/null +++ b/tests/test_configparser.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Provides unit tests for the APT configuration file parser""" +# Copyright (C) 2010 Sebastian Heinlein <devel@glatzor.de> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +__author__ = "Sebastian Heinlein <devel@glatzor.de>" + +import os +import sys +import unittest + +import apt_pkg + +from aptdaemon.config import ConfigWriter + + +class ConfigurationParserTestCase(unittest.TestCase): + + """Test suite for the configuration parser.""" + + def setUp(self): + self.parser = ConfigWriter() + + def test_comment_in_value(self): + """ ensure that comment strings in values are parsed correctly """ + s = """// Server information for apt-changelog + APT { + Changelogs { # bar + Server "http://changelogs.ubuntu.com/changelogs"; // foo + } + } + """ + cf = self.parser.parse(s.split("\n")) + self.assertEqual(cf["apt::changelogs::server"].string, + "http://changelogs.ubuntu.com/changelogs") + + def test_multi_line_comments(self): + s = """/* + * APT configuration file for Zope Debian packages. + */ + +DPkg { + Post-Invoke {"which dzhandle";}; +} + """ + cf = self.parser.parse(s.split("\n")) + self.assertEqual(cf["dpkg::post-invoke"][0].string, "which dzhandle") + + def test_(self): + config = {} + config_check = {} + + for filename in os.listdir("/etc/apt/apt.conf.d"): + path = "/etc/apt/apt.conf.d/%s" % filename + config_apt = apt_pkg.Configuration() + with open(path, "r") as fd: + apt_pkg.read_config_file(config_apt, path) + config = self.parser.parse(fd.readlines()) + for key in config_apt.keys(): + if key.endswith("::"): + key = key[:-2] + value_list_apt = config_apt.value_list(key) + if value_list_apt: + value_list = [val.string for val in + config[key.lower()]] + self.assertTrue(value_list_apt == value_list, + "%s: %s != %s" % (key, value_list_apt, + value_list)) + else: + value_apt = config_apt[key] + if value_apt: + self.assertTrue( + value_apt == config[key.lower()].string) + + +@unittest.skipIf(sys.version_info.major < 3, "Only Python3") +def setUp(): + pass + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_dbus_type.py b/tests/test_dbus_type.py new file mode 100644 index 0000000..b7ffcac --- /dev/null +++ b/tests/test_dbus_type.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Test index handling.""" + +from collections import namedtuple +import os +import re +import sys +import unittest + +import dbus +from gi.repository import GLib + +from aptdaemon.worker import aptworker +from aptdaemon import core +from aptdaemon import enums +from aptdaemon import test + +REGEX_SIG = "([ibxsdt])|(a{[ibxsdt]+?})|(a[ixbsdt]+?)|(\([ibxsdt]+?\))" +REGEX_IFACE = r"\n(org\.debian\.apt[a-z\.]*) --- " +REGEX_ATTRIB = (r"\n\.\.\s+attribute::\s+(?P<name>[a-zA-Z]+)\s+:\s+" + "(?P<sig>[a-z\(\)\{\}]+)") + +# Setup the DBus main loop +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + +DOC_PATH = os.path.join(test.get_tests_dir(), "../doc") + + +class DBusTypeTest(test.AptDaemonTestCase): + + """Make sure that the specified types are returned over D-Bus.""" + + def setUp(self): + # Extract the property type specification from the documentation + self.ifaces = {} + with open(os.path.join(DOC_PATH, "source/dbus.rst")) as rst_file: + docu = rst_file.read() + doc = "" + iface = "" + for match in re.split(REGEX_IFACE, docu, re.MULTILINE): + if match.startswith("org.debian.apt"): + iface = match + self.ifaces[iface] = {} + doc = "" + else: + doc = match + if doc and iface: + for match_attrib in re.finditer(REGEX_ATTRIB, doc): + name = match_attrib.group("name") + sig = match_attrib.group("sig") + self.ifaces[iface][name] = sig + self.start_dbus_daemon() + self.dbus = dbus.bus.BusConnection(self.dbus_address) + self.loop = GLib.MainLoop() + self.error = None + + def _on_property_changed(self, name, value, iface): + if name == "Progress" and value == 100: + self.loop.quit() + try: + self._check_property_type(iface, name, value) + except: + self.loop.quit() + raise + + def _check_property_type(self, iface, name, value, signature=None): + if signature is None: + signature = self.ifaces[iface][name] + if isinstance(value, dbus.String): + self.assertEqual(signature, "s", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.String): + self.assertEqual(signature, "s", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.Int32): + self.assertEqual(signature, "i", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.Int64): + self.assertEqual(signature, "x", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.UInt64): + self.assertEqual(signature, "t", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.Double): + self.assertEqual(signature, "d", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.Boolean): + self.assertEqual(signature, "b", + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.Dictionary): + self.assertEqual(signature, "a{%s}" % value.signature, + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + elif isinstance(value, dbus.Struct): + if value.signature: + self.assertEqual(signature, "s(%s)" % value.signature, + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + else: + # The dbus proxy doesn't set the signature property + for val, sig in map(lambda x, y: (x, y), value, + ["".join(matches) for matches in + re.findall(REGEX_SIG, signature[1:-1])]): + self._check_property_type(iface, name, val, sig) + elif isinstance(value, dbus.Array): + self.assertEqual(signature, "a%s" % value.signature, + "Property %s on %s doesnt' comply with the " + "spec: %s" % (name, iface, value)) + else: + raise Exception("Unkown type %s for property %s of %s" % + (type(value), name, iface)) + + def _error_cb(self, error): + """Errback of the GetAll call.""" + self.loop.quit() + raise error + + def _get_all_cb(self, iface, props): + """Callback of the GetAll call.""" + try: + for name, value in props.items(): + self._check_property_type(iface, name, value) + except Exception as error: + self.error = error + raise + finally: + self.loop.quit() + + @unittest.skip("Requires to be convert to a C based test client") + def test_transaction_properties(self): + """Test object properties.""" + trans = core.Transaction(None, enums.ROLE_REMOVE_PACKAGES, None, + os.getpid(), os.getuid(), sys.argv[0], + "org.debian.apt.test", bus=self.dbus) + proxy = self.dbus.get_object(core.APTDAEMON_DBUS_INTERFACE, + trans.tid) + iface = core.APTDAEMON_TRANSACTION_DBUS_INTERFACE + proxy.GetAll(iface, + reply_handler=lambda x: self._get_all_cb(iface, x), + error_handler=self._error_cb, + dbus_interface=dbus.PROPERTIES_IFACE) + self.loop.run() + self.assertEqual(self.error, None, self.error) + + @unittest.skip("Requires to be convert to a C based test client") + def test_transaction_signals(self): + """Test signal emittion.""" + trans = core.Transaction(None, enums.ROLE_COMMIT_PACKAGES, None, + os.getpid(), os.getuid(), sys.argv[0], + "org.debian.apt.test", bus=self.dbus, + packages=[["silly-base"], [], [], [], [], []]) + proxy = self.dbus.get_object("org.debian.apt", trans.tid) + proxy.connect_to_signal("PropertyChanged", + self._on_property_changed, + dbus_interface="org.debian.apt.transaction", + interface_keyword="iface") + chroot = test.Chroot() + self.addCleanup(chroot.remove) + chroot.setup() + chroot.add_test_repository() + apt_worker = aptworker.AptWorker(load_plugins=False, + chroot=chroot.path) + apt_worker.run(trans) + self.loop.run() + self.assertEqual(self.error, None) + + @unittest.skip("Requires to be convert to a C based test client") + def test_aptdaemon_properties(self): + """Test aptdaemon properties.""" + Options = namedtuple("Options", "dummy") + opt = Options(True) + self.daemon = core.AptDaemon(opt, bus=self.dbus) + + proxy = self.dbus.get_object(core.APTDAEMON_DBUS_SERVICE, + core.APTDAEMON_DBUS_PATH) + iface = core.APTDAEMON_DBUS_INTERFACE + proxy.GetAll(iface, + reply_handler=lambda x: self._get_all_cb(iface, x), + error_handler=self._error_cb, + dbus_interface=dbus.PROPERTIES_IFACE) + self.loop.run() + self.assertEqual(self.error, None) + + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_debconf.py b/tests/test_debconf.py new file mode 100644 index 0000000..eca31cd --- /dev/null +++ b/tests/test_debconf.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the debconf forwarding""" + +import logging +import os +import subprocess +import sys +import tempfile +import unittest + +import apt_pkg +from gi.repository import GLib + +from aptdaemon import test +from aptdaemon.debconf import DebconfProxy + +DEBUG = False + + +class DebconfTestBasic(unittest.TestCase): + + def _stop(self): + self.proxy.stop() + self.loop.quit() + + def setUp(self): + self.loop = GLib.MainLoop() + self.debconf_socket_path = tempfile.mktemp(prefix="debconf-socket-") + self._set_input_value() + self.proxy = DebconfProxy("editor", self.debconf_socket_path) + self.proxy.start() + + def _set_input_value(self, template="aptdaemon/test", value="lalelu"): + os.environ["DEBIAN_PRIORITY"] = "high" + os.environ["EDITOR"] = "sed -ie 's/\\(%s=\\).*/\\1\\\"%s\\\"/i'" % \ + (template.replace("/", "\\/"), value) + + def _spawn_config_script(self, config_db_path, command=None): + if command is None: + command = [os.path.join(test.get_tests_dir(), + "debconf/aptdaemon.config")] + env = {} + env["DEBCONF_DB_REPLACE"] = "File{%s}" % config_db_path + env["DEBIAN_FRONTEND"] = "passthrough" + env["DEBCONF_PIPE"] = self.debconf_socket_path + if DEBUG: + env["DEBCONF_DEBUG"] = ".*" + env_str = ["%s=%s" % (key, val) for key, val in env.items()] + + proc = subprocess.Popen(command, env=env) + return proc + + def testBasic(self): + def config_done(pid, cond): + self.assertEqual(cond, 0, + "Config script failed: %s" % os.WEXITSTATUS(cond)) + self._stop() + debconf_db_path = tempfile.mktemp(suffix=".dat", + prefix="config-basic-") + proc = self._spawn_config_script(debconf_db_path) + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, proc.pid, config_done) + self.loop.run() + # Check the results + self._check_value(debconf_db_path) + + @unittest.skipIf(sys.version_info.major < 3 and "nose" in sys.modules, + "For unknown reasons lets other tests fail " + "(test_simulate) if performed under Python2 and nose") + def testSerial(self): + """Run several config scripts in a row.""" + def config_done(pid, cond): + self.assertEqual(cond, 0, + "Config script failed: %s" % os.WEXITSTATUS(cond)) + self.config_scripts -= 1 + if self.config_scripts <= 0: + self._stop() + else: + proc = self._spawn_config_script(debconf_db_path) + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, + proc.pid, config_done) + debconf_db_path = tempfile.mktemp(suffix=".dat", prefix="config-row-") + self.config_scripts = 10 + proc = self._spawn_config_script(debconf_db_path) + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, proc.pid, config_done) + self.loop.run() + # Check the results + self._check_value(debconf_db_path) + + def testRace(self): + def config_done(pid, cond): + self.assertEqual(cond, 0, + "Config script failed: %s" % os.WEXITSTATUS(cond)) + self.workers -= 1 + if self.workers <= 0: + self._stop() + debconf_dbs = [] + self.workers = 0 + for i in range(10): + debconf_db_path = tempfile.mktemp(suffix=".dat", + prefix="config-race-") + proc = self._spawn_config_script(debconf_db_path) + GLib.child_watch_add(GLib.PRIORITY_DEFAULT, proc.pid, config_done) + debconf_dbs.append(debconf_db_path) + self.workers += 1 + self.loop.run() + # Check the results + for db_path in debconf_dbs: + self._check_value(db_path) + + def _check_value(self, db_path, template=None, value="lalelu"): + with open(db_path) as db_file: + for section in apt_pkg.TagFile(db_file): + if template == section["Template"] or template is None: + self.assertEqual(section["Value"], value) + return + os.remove(db_path) + self.fail("Database doesn't contain any matching value or template") + + def tearDown(self): + os.remove(self.debconf_socket_path) + self.proxy = None + self.loop.quit() + self.loop = None + + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_gtk3widgets.py b/tests/test_gtk3widgets.py new file mode 100644 index 0000000..ca3d73f --- /dev/null +++ b/tests/test_gtk3widgets.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +"""Test gtk3widgets.py.""" + +import os +import codecs +import shutil +import tempfile +import unittest + +from aptdaemon.gtk3widgets import DiffView + + +class TestLP1120322(unittest.TestCase): + + def setUp(self): + tempdir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, tempdir) + self.a = os.path.join(tempdir, 'a.txt') + self.b = os.path.join(tempdir, 'b.txt') + with codecs.open(self.a, 'w', encoding='utf-8') as f: + f.write('one\n') + with codecs.open(self.b, 'w', encoding='utf-8') as f: + f.write('onee\n') + + def test_lp_1120322(self): + # UnboundLocalError when the diff is one line long. + dv = DiffView() + # This simply should not traceback. + dv.show_diff(self.a, self.b) + + +class TestGoodPath(unittest.TestCase): + + def setUp(self): + tempdir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, tempdir) + self.a = os.path.join(tempdir, 'a.txt') + self.b = os.path.join(tempdir, 'b.txt') + with codecs.open(self.a, 'w', encoding='utf-8') as f: + f.write('one\ntwo\n') + with codecs.open(self.b, 'w', encoding='utf-8') as f: + f.write('one\ntoo\n') + + def test_lp_1120322(self): + # UnboundLocalError when the diff is multiple lines long. + dv = DiffView() + # This simply should not traceback. + dv.show_diff(self.a, self.b) diff --git a/tests/test_high_trust_repository_whitelist.py b/tests/test_high_trust_repository_whitelist.py new file mode 100644 index 0000000..38da3c5 --- /dev/null +++ b/tests/test_high_trust_repository_whitelist.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Provides unit tests for the APTDAEMON high-trust-repo feature.""" +# Copyright (C) 2011 Sebastian Heinlein <devel@glatzor.de> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +__author__ = "Michael Vogt <michael.vogt@ubuntu.com>" + +import os +import sys +import time +import unittest + +import dbus +from gi.repository import GLib +from mock import ( + patch) + +import aptdaemon.client +from aptdaemon.policykit1 import ( + PK_ACTION_INSTALL_PACKAGES_FROM_HIGH_TRUST_REPO as PK_ACTION) +import aptdaemon.test + +from aptdaemon.worker.aptworker import ( + _read_high_trust_repository_whitelist_file, + read_high_trust_repository_dir, + trans_only_installs_pkgs_from_high_trust_repos, + AptWorker) +from aptdaemon.core import Transaction +from aptdaemon import enums + + +REPO_PATH = os.path.join(aptdaemon.test.get_tests_dir(), "repo") + +PY3K = sys.version_info.major > 2 + + +class BaseHighTrustTestCase(aptdaemon.test.AptDaemonTestCase): + + def setUp(self): + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.loop = GLib.MainLoop() + + +class HighTrustRepositoryTestCase(BaseHighTrustTestCase): + + """ Test the worker low-level bits of the high-trust repo implementation""" + + def setUp(self): + super(HighTrustRepositoryTestCase, self).setUp() + self.queue = aptdaemon.test.MockQueue() + self.worker = AptWorker(chroot=self.chroot.path, load_plugins=False) + self.worker.connect("transaction-done", lambda w, t: self.loop.quit()) + self.worker.connect("transaction-simulated", + lambda w, t: self.loop.quit()) + + def test_read_high_trust_repository_whitelist_dir(self): + whitelist = read_high_trust_repository_dir( + os.path.join(aptdaemon.test.get_tests_dir(), + "data/high-trust-repository-whitelist.d")) + self.assertEqual( + whitelist, set([("Ubuntu", "main", "foo.*"), + ("Debian-Security", "non-free", "^bar$")])) + + def test_read_high_trust_repository_whitelist(self): + whitelist = _read_high_trust_repository_whitelist_file( + os.path.join(aptdaemon.test.get_tests_dir(), + "data/high-trust-repository-whitelist.cfg")) + self.assertEqual( + whitelist, set([("Ubuntu", "main", "foo.*"), + ("Debian-Security", "non-free", "^bar$")])) + + @patch("aptdaemon.worker.log") + def test_read_high_trust_repository_whitelist_broken(self, mock_log): + """ test that a broken repo file results in a empty whitelist """ + whitelist = _read_high_trust_repository_whitelist_file( + os.path.join(aptdaemon.test.get_tests_dir(), + "data/high-trust-repository-whitelist-broken.cfg")) + self.assertEqual(whitelist, set()) + # ensure we log a error if the config file is broken + # Skip due to LP: #1487087 + #mock_log.error.assert_called() + + @patch("aptdaemon.worker.log") + def test_read_high_trust_repository_whitelist_not_there(self, mock_log): + whitelist = _read_high_trust_repository_whitelist_file( + "lalalala-not-there-really.cfg") + self.assertEqual(whitelist, set()) + # ensure we log no error if there is no config file + self.assertFalse(mock_log.called) + + def test_high_trust_repository(self): + """Test if using a high_trust repo is working """ + self.chroot.add_repository(os.path.join(aptdaemon.test.get_tests_dir(), + "repo/whitelisted")) + # setup a whitelist + self.worker._high_trust_repositories.add( + ("Ubuntu", "", "silly.*")) + # a high-trust whitelisted pkg and a non-whitelisted one + trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[["silly-base", "other-pkg"], [], [], [], + [], []]) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.high_trust_packages, ["silly-base"]) + self.assertFalse( + trans_only_installs_pkgs_from_high_trust_repos( + trans, self.worker._high_trust_repositories)) + # whitelisted only + trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[["silly-base"], [], [], [], [], []]) + self.worker.simulate(trans) + self.loop.run() + self.assertTrue( + trans_only_installs_pkgs_from_high_trust_repos( + trans, self.worker._high_trust_repositories)) + + +class HighTrustRepositoryIntegrationTestCase(BaseHighTrustTestCase): + """ Test the whitelist feature inside the chroot """ + + def setUp(self): + super(HighTrustRepositoryIntegrationTestCase, self).setUp() + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + # setup the environment first including the high-trust whitelist + self.chroot.add_repository(os.path.join(aptdaemon.test.get_tests_dir(), + "repo/whitelisted")) + whitelist_file = os.path.join( + self.chroot.path, "etc", "aptdaemon", + "high-trust-repository-whitelist.d", "test.cfg") + os.makedirs(os.path.dirname(whitelist_file)) + + with open(whitelist_file, "w") as f: + f.write(""" +[test repo"] +origin = Ubuntu +component = +pkgnames = silly.* +""") + # *after* that start the aptdaemon + self.start_session_aptd(self.chroot.path) + time.sleep(1) + # start policykit and *only* allow from-whitelisted repo pk action + self.start_fake_polkitd(PK_ACTION) + time.sleep(1) + + def test_high_trust_polkit_ok(self): + self.client = aptdaemon.client.AptClient(self.bus) + # test that the high trust whitelist works + trans = self.client.install_packages(["silly-base"]) + trans.simulate() + trans.connect("finished", lambda a, b: self.loop.quit()) + trans.run() + self.loop.run() + self.assertEqual(trans.exit, aptdaemon.enums.EXIT_SUCCESS) + # plus ensure removal will not work + trans = self.client.remove_packages(["silly-base"]) + with self.assertRaises(aptdaemon.errors.NotAuthorizedError): + trans.run() + + def test_high_trust_polkit_not_ok(self): + self.client = aptdaemon.client.AptClient(self.bus) + # ensure that non-whitelisted packages can not be installed + trans = self.client.install_packages(["other-pkg"]) + trans.simulate() + trans.connect("finished", lambda a, b: self.loop.quit()) + with self.assertRaises(aptdaemon.errors.NotAuthorizedError): + trans.run() + + +if __name__ == "__main__": + # import logging + # logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_index.py b/tests/test_index.py new file mode 100644 index 0000000..52c2717 --- /dev/null +++ b/tests/test_index.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Test index handling.""" + +import os.path + +import apt +import apt_pkg +import unittest + +import aptdaemon.test + + +class IndexRaceTest(unittest.TestCase): + + """If the indexes are deleted or manipulated at the time + apt.Cache.required_download was called we get the following error: + SystemError: I wasn't able to locate file for the XXX package. + This might mean you need to manually fix this package. + + See lp:#659438 + """ + + def setUp(self): + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.chroot.add_test_repository() + # Check if installing an uninstalled package works + self.cache = apt.Cache(rootdir=self.chroot.path) + self.cache["silly-base"].mark_install() + self.assertEqual(self.cache.required_download, 0) + self.cache.clear() + + def test(self): + lists_path = apt_pkg.config.find_dir("Dir::State::Lists") + for file_name in os.listdir(lists_path): + if file_name.endswith("Packages"): + os.remove(os.path.join(lists_path, file_name)) + self.cache["silly-base"].mark_install() + self.assertRaises(SystemError, + lambda: self.cache.required_download) +# self.cache.required_download + + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_lock.py b/tests/test_lock.py new file mode 100644 index 0000000..d7aa000 --- /dev/null +++ b/tests/test_lock.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests locking.""" + +import logging +import os +import socket +import subprocess +import sys +import unittest + +import aptdaemon.test + +import aptdaemon.worker.aptworker + +DEBUG = False + +import apt_pkg +apt_pkg.init() + + +class LockTest(unittest.TestCase): + + REMOTE_REPO = "deb copy://%s/repo ./" % aptdaemon.test.get_tests_dir() + + def setUp(self): + self.chroot = aptdaemon.test.Chroot("-lock-test") + self.chroot.setup() + self.addCleanup(self.chroot.remove) + # Required to change the lock pathes to the chroot + self.worker = aptdaemon.worker.aptworker.AptWorker( + chroot=self.chroot.path, + load_plugins=False) + pkg_path = os.path.join(aptdaemon.test.get_tests_dir(), + "repo/silly-base_0.1-0_all.deb") + self.dpkg_cmd = ["fakeroot", "dpkg", "--root", self.chroot.path, + "--log=%s/var/log/dpkg.log" % self.chroot.path, + "--install", pkg_path] + self.inst_cmd = ('apt-get install silly-base ' + '-o "Dir"="%s" ' + '-o "Dir::state::status"="%s/var/lib/dpkg/status" ' + '-o "Dir::Bin::Dpkg"="%s/dpkg-wrapper.sh" ' + '-o "DPkg::Options::"="--root=%s" -y --force-yes' % + (self.chroot.path, self.chroot.path, + aptdaemon.test.get_tests_dir(), self.chroot.path)) + self.apt_cmd = ('apt-get update -o "Dir"="%s" -o "Dir::state::status="' + '"%s/var/lib/dpkg/status"' % + (self.chroot.path, self.chroot.path)) + # ensure to kill /etc/apt/apt.conf.d, otherwise stuff like + # the (root only) Dpkg::Post-Invoke actions are run + with open("%s/etc/apt/apt.conf" % self.chroot.path, "w") as conf: + conf.write('Dir::Etc::parts "/directory-does-not-exist";') + self.env = { + # override the default apt conf to kill off apt.conf.d includes + "APT_CONFIG": "%s/etc/apt/apt.conf" % self.chroot.path, + # provide a path for dpkg + "PATH": "/sbin:/bin:/usr/bin:/usr/sbin"} + + def test_global_lock(self): + """Check if the lock blocks dpkg and apt-get.""" + # Lock! + aptdaemon.worker.aptworker.lock.acquire() + self.assertEqual(2, subprocess.call(self.dpkg_cmd, env=self.env)) + self.assertEqual(100, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + # Relase and all should work again! + aptdaemon.worker.aptworker.lock.release() + self.assertEqual(0, subprocess.call(self.dpkg_cmd, env=self.env)) + self.assertEqual(0, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + + def test_status_lock(self): + """Test the lock on the status lock.""" + # Lock! + aptdaemon.worker.aptworker.lock.status_lock.acquire() + self.assertEqual(2, subprocess.call(self.dpkg_cmd, env=self.env)) + self.assertEqual(0, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + # Relase and all should work again! + aptdaemon.worker.aptworker.lock.status_lock.release() + self.assertEqual(0, subprocess.call(self.dpkg_cmd, env=self.env)) + self.assertEqual(0, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + + def test_lists_lock(self): + """Test the lock on the repository packages lists.""" + # Lock! + aptdaemon.worker.aptworker.lock.lists_lock.acquire() + # Dpkg doesn't care about the lock + self.assertEqual(0, subprocess.call(self.dpkg_cmd, env=self.env)) + self.assertEqual(100, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + # Relase and all should work again! + aptdaemon.worker.aptworker.lock.lists_lock.release() + self.assertEqual(0, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + + def test_archives_lock(self): + """Test the lock on the download archives.""" + # Skip the test if we don't have networking + aptdaemon.worker.aptworker.lock.archive_lock.acquire() + lst_path = os.path.join(self.chroot.path, "etc/apt/sources.list") + with open(lst_path, "w") as lst_file: + lst_file.write(self.REMOTE_REPO) + # Dpkg and apt-get doen't care about the lock as long as there aren't + # any downloads required + self.assertEqual(0, subprocess.call(self.dpkg_cmd, env=self.env)) + self.assertEqual(100, subprocess.call(self.apt_cmd, env=self.env, + shell=True)) + self.assertEqual(100, subprocess.call(self.inst_cmd, env=self.env, + shell=True)) + # Relase and all should work again! + aptdaemon.worker.aptworker.lock.archive_lock.release() + self.assertEqual(0, subprocess.call(self.inst_cmd, env=self.env, + shell=True)) + + +@unittest.skipIf(sys.version_info.major < 3, "Python 3 only") +def setUp(): + pass + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_lock_location.py b/tests/test_lock_location.py new file mode 100644 index 0000000..7f11b8a --- /dev/null +++ b/tests/test_lock_location.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests locking.""" + +import imp +import logging +import os +import subprocess +import sys +import unittest + +DEBUG = False + + +class LockFileLocationTest(unittest.TestCase): + + def test_lock_file_location(self): + """Make sure that the correct lock files are used.""" + # Make sure that the lock module is reloaded if called from + # within a test suite (to ensure no stale apt_pkg.config values + # hanging around) + import aptdaemon.lock + imp.reload(aptdaemon.lock) + # the actual test + self.assertEqual(aptdaemon.lock.status_lock.path, + os.path.join(os.path.dirname(self.STATUS_PATH), + "lock")) + self.assertEqual(aptdaemon.lock.lists_lock.path, + os.path.join(self.LISTS_PATH, "lock")) + self.assertEqual(aptdaemon.lock.archive_lock.path, + os.path.join(self.ARCHIVES_PATH, "lock")) + + def setUp(self): + """Extract the currently used pathes.""" + for var, lock in [("self.STATUS_PATH", "'dir::state::status'/f"), + ("self.LISTS_PATH", "'dir::state::lists'/d"), + ("self.ARCHIVES_PATH", "'dir::cache::archives'/d")]: + cmd = subprocess.Popen("/usr/bin/apt-config shell %s %s" % (var, + lock), + shell=True, stdout=subprocess.PIPE) + exec(cmd.communicate()[0]) + + +@unittest.skipIf(sys.version_info.major < 3, "Only Python 3") +def setUp(): + pass + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_pep8.py b/tests/test_pep8.py new file mode 100644 index 0000000..42faaaa --- /dev/null +++ b/tests/test_pep8.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Make sure that the code conforms the PEP8 conventions.""" +# Copyright (C) 2012 Sebastian Heinlein <devel@glatzor.de> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +__author__ = "Sebastian Heinlein <devel@glatzor.de>" + +import subprocess +import unittest + + +@unittest.skip("Does not work") +class AptDaemonPep8TestCase(unittest.TestCase): + + def test(self): + """Check if the source code matches the PEP8 style conventions.""" + subprocess.check_call([ + "pep8", "--statistics", "--show-source", + "--show-pep8", "--exclude", + "pkenums.py,aptdaemon,tests,debian,doc,.pc,gtk3-demo.py,setup.py", + "--ignore=E402"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_pk.py b/tests/test_pk.py new file mode 100644 index 0000000..1c73632 --- /dev/null +++ b/tests/test_pk.py @@ -0,0 +1,601 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the PackageKit compatibility layer. + +Since the PackageKit client doesn't support changing system D-Bus sockets, +run the tests only by using nose (e.g. nosetests3 tests.test_pk.PackageKitTest) +or by running the main routine (python3 test_pk.py). + +If a test fails all subsequent ones will fail, too. You will get the following +error message: +gi._glib.GError: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: +The name :1.16 was not provided by any .service files +""" + +import atexit +import logging +import os +import os.path +import shutil +import subprocess +import tempfile +import time +import sys +import unittest + +import apt_pkg +import apt.auth +from gi.repository import GLib +from gi.repository import PackageKitGlib as pk + +import aptdaemon.test + +REPO_PATH = os.path.join(aptdaemon.test.get_tests_dir(), "repo") +DEBUG = True + + +@unittest.skip("Removed PackageKit compat") +class PackageKitTest(aptdaemon.test.AptDaemonTestCase): + + """Test the PackageKit compatibility layer.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.chroot.add_test_repository() + # set up scratch dir + self.workdir = tempfile.mkdtemp() + # allow tests to add plugins, etc. + self.orig_pythonpath = os.environ.get("PYTHONPATH") + os.environ["PYTHONPATH"] = "%s:%s" % (self.workdir, + os.environ.get("PYTHONPATH", "")) + # write apt config for calling apt-key + apt_conf = os.path.join(self.chroot.path, 'aptconfig') + with open(apt_conf, 'w') as f: + f.write('Dir "%s";\n' % self.chroot.path) + os.environ['APT_CONFIG'] = apt_conf + + # if tests install keys, have aptd query a local fake server + os.environ['APTDAEMON_KEYSERVER'] = 'hkp://localhost:19191' + + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon + self.start_fake_polkitd() + time.sleep(2.0) + + def tearDown(self): + shutil.rmtree(self.workdir) + if self.orig_pythonpath: + os.environ["PYTHONPATH"] = self.orig_pythonpath + + def test_install(self): + """Test installing a package.""" + pkg_name = "silly-depend-base" + + client = pk.Client() + + # Resolve the id of the package + res = client.resolve(pk.FilterEnum.NONE, [pkg_name], None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + ids = [] + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_name(), pkg_name) + ids.append(pkg.get_id()) + break + else: + self.fail("Failed to resolve %s" % pkg_name) + + # Simulate + res = client.install_packages(2 ** pk.TransactionFlagEnum.SIMULATE, + ids, None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_name(), "silly-base") + self.assertEqual(pkg.get_info(), + pk.info_enum_from_string("installing")) + break + else: + self.fail("Failed to get dependencies of %s" % pkg_name) + + # Install + res = client.install_packages(pk.TransactionFlagEnum.NONE, ids, None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + # verify list of files + res = client.get_files(ids, None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + files = res.get_files_array()[0].get_property('files') + # ships two files, plus directories + self.assertGreaterEqual(len(files), 2, + 'expect two files in ' + str(files)) + self.assertTrue('/usr/share/doc/silly-depend-base/copyright' in files, + files) + + def test_install_files(self): + """Test installing local package files.""" + + path_pkg_config = os.path.join( + REPO_PATH, + "silly-config_.1-0_all.deb") + path_pkg = os.path.join( + REPO_PATH, + "silly-depend-base_0.1-0_all.deb") + + client = pk.Client() + + # Fail if more than package should be installed + try: + client.install_files(pk.TransactionFlagEnum.NONE, + [path_pkg_config, path_pkg], None, + lambda p, t, d: True, None) + except GLib.GError as error: + self.assertTrue("Only one package" in error.message) + else: + self.fail("Installing multiple package files didn't fail") + + # Check simulating + res = client.install_files(2 ** pk.TransactionFlagEnum.SIMULATE, + [path_pkg], None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = res.get_package_array() + if len(pkgs) != 1: + self.fail("Failed to get dependencies") + self.assertEqual(pkgs[0].get_name(), "silly-base") + self.assertEqual(pkgs[0].get_version(), "0.1-0update1") + + # Check the actual installtion + res = client.install_files(pk.TransactionFlagEnum.NONE, + [path_pkg], None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + # verify list of files + res = client.get_files(["silly-depend-base;0.1-0;all;"], + None, lambda p, t, d: True, None) + files = res.get_files_array()[0].get_property('files') + # ships two files, plus directories + self.assertGreaterEqual(len(files), 2, + 'expect two files in ' + str(files)) + self.assertTrue('/usr/share/doc/silly-depend-base/copyright' in files, + files) + + def test_download(self): + """Test downloading packages.""" + pkg_filename = "silly-base_0.1-0update1_all.deb" + pkg_id = "silly-base;0.1-0update1;all;" + temp_dir = tempfile.mkdtemp(prefix="aptd-download-test-") + + client = pk.Client() + res = client.download_packages([pkg_id], temp_dir, + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + if not os.path.exists(os.path.join(temp_dir, pkg_filename)): + self.fail("Failed to download the package") + + shutil.rmtree(temp_dir) + + def test_filters(self): + """Test filters.""" + pkg = "silly-base_0.1-0_all.deb" + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg), True) + + client = pk.Client() + + # All version + res = client.resolve(pk.FilterEnum.NONE, ["silly-base"], None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = res.get_package_array() + if len(pkgs) != 2: + self.fail("Failed to get versions") + versions = ["0.1-0", "0.1-0update1"] + for pkg in pkgs: + self.assertEqual(pkg.get_name(), "silly-base") + versions.remove(pkg.get_version()) + + # Newest version + res = client.resolve(2 ** pk.FilterEnum.NEWEST, ["silly-base"], None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = res.get_package_array() + if len(pkgs) != 1: + self.fail("Failed to get version") + self.assertEqual(pkgs[0].get_name(), "silly-base") + self.assertEqual(pkgs[0].get_version(), "0.1-0update1") + + # Installed version + res = client.resolve(2 ** pk.FilterEnum.INSTALLED, ["silly-base"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = res.get_package_array() + if len(pkgs) != 1: + self.fail("Failed to get version") + self.assertEqual(pkgs[0].get_name(), "silly-base") + self.assertEqual(pkgs[0].get_version(), "0.1-0") + + # Available version + res = client.resolve(2 ** pk.FilterEnum.NOT_INSTALLED, ["silly-base"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = res.get_package_array() + if len(pkgs) != 1: + self.fail("Failed to get version") + self.assertEqual(pkgs[0].get_name(), "silly-base") + self.assertEqual(pkgs[0].get_version(), "0.1-0update1") + + def test_get_updates(self): + """Test getting updates.""" + pkg = "silly-base_0.1-0_all.deb" + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg), True) + + client = pk.Client() + + res = client.get_updates(pk.FilterEnum.NONE, None, + lambda p, t, d: True, None) + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_name(), "silly-base") + self.assertEqual(pkg.get_version(), "0.1-0update1") + self.assertEqual(pkg.get_info(), + pk.info_enum_from_string("normal")) + break + else: + self.fail("Failed to detect upgrade") + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + def test_get_updates_security(self): + """Test if security updates are detected correctly.""" + self.chroot.add_repository(os.path.join(aptdaemon.test.get_tests_dir(), + "repo/security")) + pkg = "silly-base_0.1-0_all.deb" + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg), True) + + client = pk.Client() + + res = client.get_updates(pk.FilterEnum.NONE, None, + lambda p, t, d: True, None) + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_name(), "silly-base") + self.assertEqual(pkg.get_version(), "0.1-0update1") + self.assertEqual(pkg.get_info(), + pk.info_enum_from_string("security")) + break + else: + self.fail("Failed to detect upgrade") + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + def test_get_updates_backports(self): + """Test if backports are detected correctly.""" + self.chroot.add_repository(os.path.join(aptdaemon.test.get_tests_dir(), + "repo/backports")) + pkg = "silly-base_0.1-0_all.deb" + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg), True) + + client = pk.Client() + + res = client.get_updates(pk.FilterEnum.NONE, None, + lambda p, t, d: True, None) + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_name(), "silly-base") + self.assertEqual(pkg.get_version(), "0.1-0update1") + self.assertEqual(pkg.get_info(), + pk.info_enum_from_string("enhancement")) + break + else: + self.fail("Failed to detect upgrade") + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + def test_require_restart(self): + """Test if the restart-required signal gets emitted.""" + os.makedirs(os.path.join(self.chroot.path, "var/run")) + with open(os.path.join(self.chroot.path, "var/run/reboot-required"), + "w") as reboot_stamp: + reboot_stamp.write("") + client = pk.Client() + + res = client.get_updates(pk.FilterEnum.NONE, None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + self.assertEqual(res.get_require_restart_worst(), + pk.RestartEnum.SYSTEM) + + def test_dependencies(self): + """Test getting dependencies and dependants.""" + pkg_id_depend = "silly-depend-base;0.1-0;all;" + pkg_id = "silly-base;0.1-0update1;all;" + + client = pk.Client() + + # Get depends + res = client.get_depends(pk.FilterEnum.NONE, [pkg_id_depend], True, + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_id(), pkg_id) + break + else: + self.fail("Failed to get dependencies of %s" % pkg_id_depend) + + # Get requires + res = client.get_requires(pk.FilterEnum.NONE, [pkg_id], True, + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + for pkg in res.get_package_array(): + self.assertEqual(pkg.get_id(), pkg_id_depend) + break + else: + self.fail("Failed to get dependants of %s" % pkg_id) + + def test_what_provides_unsupported(self): + """Test querying for provides for unsupported type.""" + + client = pk.Client() + + try: + client.what_provides(pk.FilterEnum.NONE, pk.ProvidesEnum.CODEC, + ["gstreamer0.10(decoder-audio/ac3)"], + None, lambda p, t, d: True, None) + self.fail("expected GLib.Error failure") + except GLib.GError as e: + self.assertTrue("codec" in str(e), e) + self.assertTrue("not supported" in str(e), e) + + def test_what_provides_plugin(self): + """Test querying for provides with plugins.""" + + # add plugin for extra codecs + f = open(os.path.join(self.workdir, "extra_codecs.py"), "w") + f.write("""import aptdaemon.pkenums as enums + +def fake_what_provides(cache, type, search): + if type in (enums.PROVIDES_CODEC, enums.PROVIDES_ANY): + if search.startswith('gstreamer'): + return [cache["gstreamer0.10-silly"]] + raise NotImplementedError('cannot handle type ' + str(type)) +""") + f.close() + os.mkdir(os.path.join(self.workdir, "extra_codecs-0.egg-info")) + f = open(os.path.join(self.workdir, "extra_codecs-0.egg-info", + 'entry_points.txt'), "w") + f.write("[packagekit.apt.plugins]\n" + "what_provides=extra_codecs:fake_what_provides\n") + f.close() + + # invalid plugin, should not stop the valid ones + os.mkdir(os.path.join(self.workdir, "nonexisting-1.egg-info")) + f = open(os.path.join(self.workdir, "nonexisting-1.egg-info", + 'entry_points.txt'), "w") + f.write("[packagekit.apt.plugins]\n" + "what_provides=nonexisting:what_provides\n") + f.close() + + # another plugin to test chaining and a new type + f = open(os.path.join(self.workdir, "more_stuff.py"), "w") + f.write("""import aptdaemon.pkenums as enums + +def my_what_provides(cache, type, search): + if type in (enums.PROVIDES_CODEC, enums.PROVIDES_ANY): + if search.startswith('gstreamer'): + return [cache["silly-base"]] + if type in (enums.PROVIDES_LANGUAGE_SUPPORT, enums.PROVIDES_ANY): + if search.startswith('locale('): + return [cache["silly-important"]] + raise NotImplementedError('cannot handle type ' + str(type)) +""") + f.close() + os.mkdir(os.path.join(self.workdir, "more_stuff-0.egg-info")) + f = open(os.path.join(self.workdir, "more_stuff-0.egg-info", + 'entry_points.txt'), "w") + f.write("[packagekit.apt.plugins]\n" + "what_provides=more_stuff:my_what_provides\n") + f.close() + + client = pk.Client() + + # search for CODEC + res = client.what_provides(pk.FilterEnum.NONE, pk.ProvidesEnum.CODEC, + ["gstreamer0.10(decoder-audio/vorbis)"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = [p.get_id().split(";")[0] for p in res.get_package_array()] + self.assertEqual(pkgs, ["gstreamer0.10-silly", "silly-base"]) + + # search for LANGUAGE_SUPPORT + res = client.what_provides(pk.FilterEnum.NONE, + pk.ProvidesEnum.LANGUAGE_SUPPORT, + ["locale(de_DE)"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = [p.get_id().split(";")[0] for p in res.get_package_array()] + self.assertEqual(pkgs, ["silly-important"]) + + # search ANY + res = client.what_provides(pk.FilterEnum.NONE, pk.ProvidesEnum.ANY, + ["gstreamer0.10(decoder-audio/vorbis)"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = [p.get_id().split(";")[0] for p in res.get_package_array()] + self.assertEqual(pkgs, ["gstreamer0.10-silly", "silly-base"]) + + res = client.what_provides(pk.FilterEnum.NONE, pk.ProvidesEnum.ANY, + ["locale(de_DE)"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + pkgs = [p.get_id().split(";")[0] for p in res.get_package_array()] + self.assertEqual(pkgs, ["silly-important"]) + + res = client.what_provides(pk.FilterEnum.NONE, pk.ProvidesEnum.ANY, + ["modalias(pci:1)"], + None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + self.assertEqual(res.get_package_array(), []) + + # unsupported type with plugins + try: + client.what_provides(pk.FilterEnum.NONE, + pk.ProvidesEnum.PLASMA_SERVICE, + ["plasma4(dataengine-weather)"], + None, lambda p, t, d: True, None) + self.fail("expected GLib.Error failure") + except GLib.GError as e: + self.assertTrue("plasma" in str(e), e) + self.assertTrue("not supported" in str(e), e) + + def test_repo_enable(self): + """Test adding a repository.""" + client = pk.Client() + + # create test update repo + repo = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, repo) + with open(os.path.join(repo, 'Packages'), 'w') as f: + f.write('''Package: silly-new +Priority: extra +Section: admin +Installed-Size: 44 +Maintainer: Sebastian Heinlein <devel@glatzor.de> +Architecture: all +Source: silly-new (0.1-0) +Version: 1.2.3 +Filename: %s/silly-base_0.1-0update1_all.deb +Size: 1934 +MD5sum: 8e20af56a63a1e0cf40db3b0d07e7989 +SHA1: 7ce87423d9c7a734478c464021994944d07fbf1b +SHA256: d3693c0e3e7a9519b2833fdf1301c7e03e0620edf15b95b4c7329d9eb0bee553 +Description: new package from a third-party repo +''' % self.chroot.path) + + # without the new repo, we do not have it yet + self.assertRaises(GLib.GError, client.resolve, pk.FilterEnum.NONE, + ['silly-new'], None, lambda p, t, d: True, None) + + # now add the new repo + apt_source = 'deb file://%s /' % repo + res = client.repo_enable(apt_source, True, None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + with open(os.path.join(self.chroot.path, 'etc', 'apt', + 'sources.list')) as f: + for line in f: + if line.strip() == apt_source: + break + else: + self.fail('did not find newly added repository in ' + 'sources.list') + + # should not actually download the indexes yet + self.assertRaises(GLib.GError, client.resolve, pk.FilterEnum.NONE, + ['silly-new'], None, lambda p, t, d: True, None) + + res = client.refresh_cache(False, None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + # we should now see the new package + res = client.resolve(pk.FilterEnum.NONE, ['silly-new'], None, + lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + packages = res.get_package_array() + self.assertEqual(len(packages), 1) + self.assertEqual(packages[0].get_name(), "silly-new") + self.assertEqual(packages[0].get_version(), "1.2.3") + self.assertEqual(packages[0].get_info(), + pk.info_enum_from_string("available")) + + def test_repo_enable_errors(self): + """Test errors when adding a repository.""" + client = pk.Client() + client.set_locale("C") + + try: + client.repo_enable('bogus', True, None, lambda p, t, d: True, None) + except GLib.GError as e: + self.assertTrue('format' in str(e)) + self.assertTrue('bogus' in str(e)) + + try: + client.repo_enable('deb http://example.com', True, None, + lambda p, t, d: True, None) + except GLib.GError as e: + self.assertTrue('format' in str(e), e) + self.assertTrue('http://example.com' in str(e), e) + + def test_install_signature(self): + """Test installing a new GPG key""" + # we do not have any key initially + self.assertEqual(len(apt.auth.list_keys()), 0) + + # launch our keyserver + self.start_keyserver() + + # now add one + client = pk.Client() + res = client.install_signature( + pk.SigTypeEnum.GPG, + 'D0BF65B7DBE28DB62BEDBF1B683C53C7CF982D18', + '', None, lambda p, t, d: True, None) + self.assertEqual(res.get_exit_code(), pk.ExitEnum.SUCCESS) + + # key was imported correctly + key = apt.auth.list_keys()[0] + self.assertEqual('CF982D18', key.keyid) + + def test_install_signature_error(self): + """Test installing a new GPG key with failing server""" + + # do not start keyserver, so http://localhost.. will not exist + client = pk.Client() + client.set_locale("C") + try: + client.install_signature( + pk.SigTypeEnum.GPG, + '1111111111111111111111111111111111111111', + '', None, lambda p, t, d: True, None) + except GLib.GError as e: + self.assertTrue('Failed to download' in str(e), e) + self.assertTrue('11111111' in str(e), e) + + def test_unimplemented(self): + """Test proper error message on unimplemented method.""" + client = pk.Client() + client.set_locale("C") + try: + client.upgrade_system("sid", pk.UpgradeKindEnum.COMPLETE, None, + lambda p, t, d: True, None) + except GLib.GError as e: + self.assertTrue('implemented' in str(e)) + + +@unittest.skipIf(sys.version_info.major < 3, "Python3 only") +def setUp(): + """The PackageKit client cannot handle a changed system D-Bus address. + So we need to setup a static one for the whole test suite. + + This requires to run nosetests to launch this test suite. + """ + proc, address = aptdaemon.test.start_dbus_daemon() + os.environ["DBUS_SYSTEM_BUS_ADDRESS"] = address + # The pk.Client uses a DBus connection with exit-on-disconnect set to + # True which cannot be modified. Furthermore the registered signal + # handlers cannot be removed. Since GIO would kill the test suite if + # the daemon disappears we have to delay killing the daemon + atexit.register(os.kill, proc.pid, 9) + + +def tearDown(): + os.environ["DBUS_SYSTEM_BUS_ADDRESS"] = "" + + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + setUp() + unittest.main() + tearDown() + +# vim: ts=4 et sts=4 diff --git a/tests/test_progress.py b/tests/test_progress.py new file mode 100644 index 0000000..b691212 --- /dev/null +++ b/tests/test_progress.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the debconf forwarding""" + +import apt +import logging +import mock +import sys +import unittest + +import aptdaemon.test +from aptdaemon.progress import DaemonOpenProgress + + +class TestProgress(unittest.TestCase): + + def setUp(self): + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + + def test_open_progress(self): + transaction = mock.Mock() + begin = 0 + end = 5 + d = DaemonOpenProgress(transaction, begin=begin, end=end) + # simulate cache open (c = apt.Cache(d))) + for j in range(4): + for i in range(0, 100, 10): + d.update(i) + self.assertTrue(d.progress >= begin) + self.assertTrue(d.progress <= end) + d.done() + # ensure we use the full range + self.assertEqual(d.progress, end) + + def test_open_progress_real_cache(self): + transaction = mock.Mock() + begin = 0 + end = 5 + d = DaemonOpenProgress(transaction, begin=begin, end=end) + c = apt.Cache(d) + # ensure we use the full range + self.assertEqual(d.progress, end) + + +@unittest.skipIf(sys.version_info.major < 3, "Python 3 only") +def setUp(): + pass + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_py2_string_handling.py b/tests/test_py2_string_handling.py new file mode 100644 index 0000000..ab921f6 --- /dev/null +++ b/tests/test_py2_string_handling.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2011 Michael Vogt <mvo@ubuntu.com> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +"""Regression test for a unicode decoding error in the status_details, +progress_download or error_properties attributes of the transaction, +see LP #724735. +""" + +__author__ = "Michael Vogt <mvo@glatzor.de>" + +import sys +import unittest + +if sys.version_info.major == 2: + from _test_py2_string_handling import * +else: + try: + from _test_py3_string_handling import * + except ImportError: + from ._test_py3_string_handling import * + + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_simulate.py b/tests/test_simulate.py new file mode 100644 index 0000000..15da129 --- /dev/null +++ b/tests/test_simulate.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests if the daemon forces a simualte during run.""" + +import logging +import time +import unittest + +from gi.repository import GObject +import dbus + +import aptdaemon.client +import aptdaemon.loop +import aptdaemon.enums + +import aptdaemon.test + +DEBUG = True + + +class DaemonTest(aptdaemon.test.AptDaemonTestCase): + + """Test the python client.""" + + def setUp(self): + """Setup a chroot, run the aptdaemon and a fake PolicyKit daemon.""" + # Setup chroot + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + # Start aptdaemon with the chroot on the session bus + self.start_dbus_daemon() + self.bus = dbus.bus.BusConnection(self.dbus_address) + self.start_session_aptd(self.chroot.path) + # Start the fake PolikcyKit daemon + self.start_fake_polkitd() + time.sleep(1) + + def _on_finished(self, trans, exit): + """Callback to stop the mainloop after a transaction is done.""" + aptdaemon.loop.mainloop.quit() + + def test_detect_unauthenticated(self): + """Test if the installation of an unauthenticated packages fails + if simulate hasn't been called explicitly before. + """ + self.chroot.add_test_repository(copy_sig=False) + self.client = aptdaemon.client.AptClient(self.bus) + trans = self.client.install_packages(["silly-base"]) + trans.connect("finished", self._on_finished) + trans.run() + aptdaemon.loop.mainloop.run() + self.assertEqual(trans.exit, aptdaemon.enums.EXIT_FAILED) + self.assertEqual(trans.error.code, + aptdaemon.enums.ERROR_PACKAGE_UNAUTHENTICATED) + self.assertEqual(trans.unauthenticated, ["silly-base"]) + + def test_environment(self): + """Ensure that the test environment works.""" + self.chroot.add_test_repository() + self.client = aptdaemon.client.AptClient(self.bus) + trans = self.client.install_packages(["silly-base"]) + trans.connect("finished", self._on_finished) + trans.run() + aptdaemon.loop.mainloop.run() + self.assertEqual(trans.exit, aptdaemon.enums.EXIT_SUCCESS) + + +if __name__ == "__main__": + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_trans_chain.py b/tests/test_trans_chain.py new file mode 100644 index 0000000..209d7d7 --- /dev/null +++ b/tests/test_trans_chain.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Tests the debconf forwarding""" +import unittest +from gi.repository import GLib + +from aptdaemon import enums, client + +DEBUG = False + + +class TransChainTest(unittest.TestCase): + + """These tests require an aptdaemon running with the dummy worker: + # sudo aptd -td --dummy + """ + + def setUp(self): + self.loop = GLib.MainLoop() + self.client = client.AptClient() + + def _test_working(self): + def on_finished(trans, exit): + self.loop.quit() + trans1 = self.client.upgrade_packages(["huhu"]) + trans2 = self.client.upgrade_packages(["lala"]) + trans3 = self.client.upgrade_packages(["huhu"]) + trans2.run_after(trans1) + trans3.run_after(trans2) + trans1.run() + trans3.connect("finished", on_finished) + self.loop.run() + self.assertTrue(trans1.exit == enums.EXIT_SUCCESS) + self.assertTrue(trans2.exit == enums.EXIT_SUCCESS) + self.assertTrue(trans3.exit == enums.EXIT_SUCCESS) + + def _test_fail_after(self): + def on_finished(trans, exit): + self.loop.quit() + trans1 = self.client.update_cache() + trans2 = self.client.upgrade_packages(["huhululu"]) + trans3 = self.client.upgrade_packages(["huhululu"]) + trans2.run_after(trans1) + trans3.run_after(trans2) + trans1.run() + trans3.connect("finished", on_finished) + self.loop.run() + self.assertTrue(trans1.exit == enums.EXIT_FAILED) + self.assertTrue(trans2.exit == enums.EXIT_PREVIOUS_FAILED) + self.assertTrue(trans3.exit == enums.EXIT_PREVIOUS_FAILED) + + +if __name__ == "__main__": + import logging + if DEBUG: + logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_valid_package_names.py b/tests/test_valid_package_names.py new file mode 100644 index 0000000..0e81ab9 --- /dev/null +++ b/tests/test_valid_package_names.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Test index handling.""" + +import sys +import unittest + +import apt +import mock + +import aptdaemon.core +import aptdaemon.errors + + +class TestValidPacakgeNames(unittest.TestCase): + + """Test the code that verifies for valid package names + """ + + def setUp(self): + self.cache = apt.Cache() + opt = mock.Mock() + opt.dummy = True + self.daemon = aptdaemon.core.AptDaemon(opt, connect=False) + + def test_valid_package_names(self): + # ensure that the code raises on invalid ones, note that we + # test each item individually instead of the list because each + # needs to raise + for invalid in [ + "foo_bar", "äää", "i space", "a", "+invalidstart", "noUpper", + "foo=", "foo=", "foo=a", "foo=0 space" + "foo/", "foo/ space"]: + with self.assertRaises(aptdaemon.errors.AptDaemonError): + self.daemon._check_package_names([invalid]) + + # check some simple good cases + for pkgname in ["apt", "apt/unstable", "apt=0.3.2", "apt:i386", + "apt+:i386/unstable", "apt+:amd64=0.3.2"]: + self.daemon._check_package_names([pkgname]) + + # ensure the code does not wrongly label valid packages as + # invalid, _check_package_names will raise on error + for pkg in self.cache: + self.daemon._check_package_names([pkg.name]) + + # test again, this time with version number + for pkg in self.cache: + if not pkg.candidate: + continue + self.daemon._check_package_names( + ["%s=%s" % (pkg.name, pkg.candidate.version)]) + + # test again, this time with release origin + for pkg in self.cache: + if not pkg.candidate: + continue + archive = pkg.candidate.origins[0].archive + if archive: + self.daemon._check_package_names(["%s/%s" % (pkg.name, + archive)]) + + +@unittest.skipIf(sys.version_info.major < 3, "Python 3 only") +def setUp(): + pass + +if __name__ == "__main__": + unittest.main() + +# vim: ts=4 et sts=4 diff --git a/tests/test_worker.py b/tests/test_worker.py new file mode 100644 index 0000000..e82ace0 --- /dev/null +++ b/tests/test_worker.py @@ -0,0 +1,588 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Provides unit tests for the APT worker.""" +# Copyright (C) 2011 Sebastian Heinlein <devel@glatzor.de> +# +# Licensed under the GNU General Public License Version 2 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Licensed under the GNU General Public License Version 2 + +__author__ = "Sebastian Heinlein <devel@glatzor.de>" + +import glob +import netrc +import os +import shutil +import stat +import sys +import tempfile +import unittest + +import apt_pkg +from gi.repository import GLib +from mock import ( + Mock, + patch) + +import aptdaemon.test +from aptdaemon.worker.aptworker import ( + AptWorker) +from aptdaemon.core import Transaction +from aptdaemon import enums, errors + + +REPO_PATH = os.path.join(aptdaemon.test.get_tests_dir(), "repo") + +PY3K = sys.version_info.major > 2 + + +class WorkerTestCase(aptdaemon.test.AptDaemonTestCase): + + """Test suite for the worker which performs the actual package + installation and removal.""" + + def setUp(self): + self.chroot = aptdaemon.test.Chroot() + self.chroot.setup() + self.addCleanup(self.chroot.remove) + self.loop = GLib.MainLoop() + self.queue = aptdaemon.test.MockQueue() + self.worker = AptWorker(chroot=self.chroot.path, load_plugins=False) + self.worker.connect("transaction-done", lambda w, t: self.loop.quit()) + self.worker.connect("transaction-simulated", + lambda w, t: self.loop.quit()) + + @unittest.skipIf("nose" in sys.modules, "Fails under nosetests3") + def test_update_cache(self): + """Test updating the cache using a local repository.""" + # Add a working and a non-working repository + self.chroot.add_trusted_key() + path = os.path.join(self.chroot.path, + "etc/apt/sources.list.d/test.list") + with open(path, "w") as part_file: + part_file.write("deb file://%s ./" % REPO_PATH) + self.chroot.add_repository("/does/not/exist", copy_list=False) + # Only update the repository from the working snippet + trans = Transaction(None, enums.ROLE_UPDATE_CACHE, + self.queue, os.getpid(), os.getuid(), + os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + kwargs={"sources_list": "test.list"}) + self.worker.simulate(trans) + self.loop.run() + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertEqual(len(self.worker._cache), 10) + pkg = self.worker._cache["silly-base"] + self.assertTrue(pkg.candidate.origins[0].trusted) + + def test_upgrade_system(self): + """Test upgrading the system.""" + self.chroot.add_test_repository() + self.chroot.install_debfile(os.path.join(REPO_PATH, + "silly-base_0.1-0_all.deb")) + # Install the package + trans = Transaction(None, enums.ROLE_UPGRADE_SYSTEM, + self.queue, os.getpid(), os.getgid(), + os.getuid(), sys.argv[0], + "org.debian.apt.test", connect=False, + kwargs={"safe_mode": False}) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.depends[enums.PKGS_UPGRADE], + ["silly-base=0.1-0update1"]) + self.assertTrue(trans.space > 0) + self.assertTrue(trans.download == 0) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + # Test apt history log + with open(os.path.join(self.chroot.path, "var/log/apt/history.log")) \ + as history_file: + history = history_file.read() + self.assertTrue("Commandline: aptdaemon role='%s'" % trans.role in + history) + + self.assertEqual(self.worker._cache["silly-base"].installed.version, + "0.1-0update1") + + def test_check_unauth(self): + """Test if packages from an unauthenticated repo are detected.""" + self.chroot.add_test_repository(copy_sig=False) + # Install the package + trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[["silly-base"], [], [], [], [], []]) + self.worker.simulate(trans) + self.loop.run() + trans.allow_unauthenticated = False + self.assertEqual(trans.unauthenticated, ["silly-base"]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_FAILED) + self.assertEqual(trans.error.code, enums.ERROR_PACKAGE_UNAUTHENTICATED) + + # Allow installation of unauthenticated packages + trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[["silly-base"], [], [], [], [], []]) + trans.allow_unauthenticated = True + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.unauthenticated, ["silly-base"]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertTrue(self.worker._cache["silly-base"].is_installed) + + def test_install(self): + """Test installation of a package from a repository.""" + self.chroot.add_test_repository() + # Install the package + trans = Transaction(None, enums.ROLE_INSTALL_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[["silly-depend-base"], [], [], [], + [], []]) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.depends[enums.PKGS_INSTALL], + ["silly-base=0.1-0update1"]) + self.assertTrue(trans.space > 0) + self.assertTrue(trans.download == 0) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertTrue(self.worker._cache["silly-depend-base"].is_installed) + + def test_remove_obsolete(self): + """Test the removal of obsoleted packages.""" + for pkg in ["silly-base_0.1-0_all.deb", + "silly-depend-base_0.1-0_all.deb"]: + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg)) + ext_states = apt_pkg.config.find_file("Dir::State::extended_states") + with open(ext_states, "w") as ext_states_file: + ext_states_file.write("""Package: silly-base +Architecture: all +Auto-Installed: 1""") + trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[[], [], ["silly-depend-base"], [], + [], []]) + trans.remove_obsoleted_depends = True + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.depends[enums.PKGS_REMOVE], + ["silly-base=0.1-0"]) + self.assertTrue(trans.space < 0) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertFalse("silly-base" in self.worker._cache) + self.assertFalse("silly-depend-base" in self.worker._cache) + + def test_remove(self): + """Test the removal of packages.""" + for pkg in ["silly-base_0.1-0_all.deb", + "silly-essential_0.1-0_all.deb", + "silly-depend-base_0.1-0_all.deb"]: + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg)) + trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[[], [], ["silly-base"], [], [], []]) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.depends[enums.PKGS_REMOVE], + ["silly-depend-base=0.1-0"]) + self.assertTrue(trans.space < 0) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + try: + installed = self.worker._cache["silly-depend-base"].is_installed + self.assertFalse(installed) + except KeyError: + pass + # Don't allow to remove essential packages + trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[[], [], ["silly-essential"], [], [], []]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_FAILED, + "Allowed to remove an essential package") + self.assertEqual(trans.error.code, + enums.ERROR_NOT_REMOVE_ESSENTIAL_PACKAGE, + "Allowed to remove an essential package") + + def test_upgrade(self): + """Test upgrading of packages.""" + self.chroot.add_test_repository() + for pkg in ["silly-base_0.1-0_all.deb", + "silly-depend-base_0.1-0_all.deb"]: + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg)) + ext_states = apt_pkg.config.find_file("Dir::State::extended_states") + with open(ext_states, "w") as ext_states_file: + ext_states_file.write("""Package: silly-base +Architecture: all +Auto-Installed: 1""") + trans = Transaction(None, enums.ROLE_COMMIT_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[[], [], [], [], + ["silly-base=0.1-0update1"], []]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertEqual(self.worker._cache["silly-base"].installed.version, + "0.1-0update1", "Failed to upgrade.") + self.assertTrue(self.worker._cache["silly-base"].is_auto_installed) + + def test_downgrade(self): + """Test downgrading of packages.""" + self.chroot.add_test_repository() + pkg = os.path.join(REPO_PATH, "silly-base_0.1-0update1_all.deb") + self.chroot.install_debfile(pkg) + trans = Transaction(None, enums.ROLE_COMMIT_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[[], [], [], [], [], + ["silly-base=0.1-0"]]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertEqual(self.worker._cache["silly-base"].installed.version, + "0.1-0", "Failed to downgrade.") + + def test_purge(self): + """Test the purging of packages.""" + for pkg in ["silly-base_0.1-0_all.deb", "silly-config_0.1-0_all.deb"]: + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg)) + trans = Transaction(None, enums.ROLE_REMOVE_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + packages=[[], [], [], ["silly-config"], [], []]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.assertFalse( + os.path.exists(os.path.join(self.chroot.path, + "etc/silly-packages.cfg")), + "Configuration file wasn't removed.") + + def test_install_file(self): + """Test the installation of a local package file.""" + # test + self.chroot.add_test_repository() + pkg = os.path.join(REPO_PATH, + "silly-depend-base_0.1-0_all.deb") + trans = Transaction(None, enums.ROLE_INSTALL_FILE, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + kwargs={"path": os.path.join(REPO_PATH, pkg), + "force": False}) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.depends[enums.PKGS_INSTALL], + ["silly-base=0.1-0update1"]) + self.assertTrue(trans.space > 0) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + pkg = self.worker._cache["silly-depend-base"] + self.assertTrue(pkg.is_installed) + + def test_install_conflicting_file(self): + """Test installing of a local package file that conflicts with + installed packages. + + Regression test for LP: #750958 + """ + pkg_base = "silly-base_0.1-0_all.deb" + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg_base)) + pkg = os.path.join(REPO_PATH, "silly-bully_0.1-0_all.deb") + trans = Transaction(None, enums.ROLE_INSTALL_FILE, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + kwargs={"path": os.path.join(REPO_PATH, pkg), + "force": True}) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_FAILED, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.assertEqual(trans.error.code, enums.ERROR_DEP_RESOLUTION_FAILED) + self.worker._cache.open() + + def test_install_unknown_file(self): + """Test the installation of a local package file which is not known + to the cache. + + Regression test for LP #702217 + """ + pkg = os.path.join(REPO_PATH, "silly-base_0.1-0_all.deb") + trans = Transaction(None, enums.ROLE_INSTALL_FILE, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False, + kwargs={"path": os.path.join(REPO_PATH, pkg), + "force": True}) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.packages, (["silly-base"], [], [], [], [], [])) + self.assertTrue(trans.space > 0) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertTrue(self.worker._cache["silly-base"].is_installed) + + def test_fix_broken_depends(self): + """Test the fixing of broken dependencies.""" + for pkg in ["silly-base_0.1-0_all.deb", "silly-broken_0.1-0_all.deb"]: + self.chroot.install_debfile(os.path.join(REPO_PATH, pkg), True) + trans = Transaction(None, enums.ROLE_FIX_BROKEN_DEPENDS, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", connect=False) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.depends[enums.PKGS_REMOVE], + ["silly-broken=0.1-0"]) + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + self.worker._cache.open() + self.assertEqual(self.worker._cache.broken_count, 0) + + def test_install_broken_depends(self): + """Test the that installing a package with broken dependencies + fails in a correct way. + """ + self.chroot.add_test_repository() + trans = Transaction(None, enums.ROLE_COMMIT_PACKAGES, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", + packages=[["silly-broken"], [], [], [], [], []], + connect=False) + self.worker.simulate(trans) + self.loop.run() + self.assertEqual(trans.error.code, enums.ERROR_DEP_RESOLUTION_FAILED) + + def test_add_license_key_unsecure(self): + """Test if we refuse to install license key files to an unsecure + location or binaries.""" + self.chroot.add_test_repository(copy_sig=False) + # Should fail because of an untrusted source + license_key = "NASTY_BLOB" + license_key_path = "/opt/silly-license/NASTY.KEY" + pkg_name = "silly-license" + self.assertRaises(errors.TransactionFailed, + self.worker._add_license_key_to_system, + pkg_name, license_key, license_key_path) + # Check if we don't allow to install executables + with open("/bin/ls", "rb") as sample_exec: + license_key = sample_exec.read() + if PY3K: + license_key = license_key.decode("UTF-8", "ignore") + pkg_name = "silly-license" + self.assertRaises(errors.TransactionFailed, + self.worker._add_license_key_to_system, + pkg_name, license_key, license_key_path) + + def test_add_license_key(self): + """Test the installation of license key files.""" + license_key = "Bli bla blub, I am a nasty BLOB!" + license_path = "/opt/silly-license/NASTY.KEY" + + def get_license_key_mock(uid, pkg, oauth, server): + return license_key, license_path + + self.chroot.add_test_repository() + trans = Transaction(None, enums.ROLE_ADD_LICENSE_KEY, self.queue, + os.getpid(), os.getuid(), os.getgid(), sys.argv[0], + "org.debian.apt.test", + kwargs={"pkg_name": "silly-license", + "json_token": "lalelu", + "server_name": "mock"}, + connect=False) + os.makedirs(os.path.join( + aptdaemon.worker.aptworker.apt_pkg.config["Dir"], + "opt/silly-license/")) + self.worker.plugins["get_license_key"] = [get_license_key_mock] + self.worker.run(trans) + self.loop.run() + self.assertEqual(trans.exit, enums.EXIT_SUCCESS, + "%s: %s" % (trans._error_property[0], + trans._error_property[1])) + # Check the content of the installed key + verify_path = os.path.join( + aptdaemon.worker.aptworker.apt_pkg.config["Dir"], license_path[1:]) + with open(verify_path) as verify_file: + self.assertEqual(license_key, verify_file.read(), + "Content of license key doesn't match") + + def test_use_apt_auth_conf(self): + """Test if credentials of repositories are store securely in a + separate file. + """ + source_file_name = "private_source.list" + self.worker.add_repository(Mock(), "deb", + "https://user:pass@host.example.com/path", + "natty", ["main"], "comment", + source_file_name) + # check if password was stripped (source file) + source_parts = apt_pkg.config.find_dir("Dir::Etc::sourceparts") + source_file_path = os.path.join(source_parts, + source_file_name) + with open(source_file_path) as source_file: + source_file_content = source_file.read() + self.assertFalse("user:pass" in source_file_content) + # check if password was stored correctly (auth.conf) + auth_file_path = apt_pkg.config.find_file("Dir::Etc::netrc") + with open(auth_file_path) as auth_file: + auth_file_content = auth_file.read() + for token in ["login user", + "password pass", + "machine host.example.com/path"]: + self.assertTrue(token in auth_file_content) + buf = os.stat(auth_file_path) + self.assertEqual(stat.S_IMODE(buf.st_mode), 0o640) + # now add the repo again with updated auth credentials and ensure + # that the info is not duplicated + self.worker.add_repository(Mock(), "deb", + "https://xuser:xpass@host.example.com/path", + "natty", ["main"], "comment", + source_file_name) + # check if password was stored correctly (auth.conf) + auth_file_path = apt_pkg.config.find_file("Dir::Etc::netrc") + netrc_file = netrc.netrc(auth_file_path) + self.assertEqual(len(netrc_file.hosts), 1) + with open(auth_file_path) as auth_file: + auth_file_content = auth_file.read() + self.assertFalse("login user" in auth_file_content) + for token in ["login xuser", + "password xpass", + "machine host.example.com/path"]: + self.assertTrue(token in auth_file_content) + netrc_file = netrc.netrc(auth_file_path) + self.assertEqual(len(netrc_file.hosts), 1) + # add another one + self.worker.add_repository( + Mock(), "deb", "https://user2:pass2@host.example.com/path2", + "natty", ["main"], "comment", source_file_name) + netrc_file = netrc.netrc(auth_file_path) + self.assertEqual(len(netrc_file.hosts), 2) + # change mode and add another repo + os.chmod(auth_file_path, 0o740) + self.worker.add_repository(Mock(), "deb", + "https://user:pass@host.example.com/path3", + "natty", ["main"], "comment", + source_file_name) + # and ensure auth.conf mode is kept and *not* reset + buf = os.stat(auth_file_path) + self.assertEqual(stat.S_IMODE(buf.st_mode), 0o740) + self.assertEqual(len(netrc.netrc(auth_file_path).hosts), 3) + + def test_modify_apt_auth_fallback(self): + netrc_tempfile = tempfile.NamedTemporaryFile() + # note that the order of password/login is different than the + # standard order + netrc_tempfile.write(""" +machine private-ppa.launchpad.net/project-foo +password baz +login foo +""".encode("utf8")) + netrc_tempfile.flush() + # now pretend we have a different user/pass + uri = "http://foo2:baz2@private-ppa.launchpad.net/project-foo" + self.worker._store_and_strip_password_from_uri( + uri, netrc_tempfile.name) + # ensure that it used the fallback prepend + with open(netrc_tempfile.name) as f: + self.assertEqual(f.read(), """ +machine private-ppa.launchpad.net/project-foo login foo2 password baz2 + +machine private-ppa.launchpad.net/project-foo +password baz +login foo +""") + # and another one with a new entry that just goes to the end + # and special chars, note that the python netrc parser will fail + # for non-ascii (yes, it does) + uri = "http://m%20oo:bär@private-ppa.launchpad.net/project-moobar" + self.worker._store_and_strip_password_from_uri( + uri, netrc_tempfile.name) + with open(netrc_tempfile.name, 'rb') as f: + self.assertEqual(f.read().decode("utf-8"), """ +machine private-ppa.launchpad.net/project-foo login foo2 password baz2 + +machine private-ppa.launchpad.net/project-foo +password baz +login foo + +machine private-ppa.launchpad.net/project-moobar login m%20oo password bär +""") + + +@unittest.skipIf(not PY3K, "Only test the backend for Python3") +def setUp(): + pass + + +if __name__ == "__main__": + # import logging + # logging.basicConfig(level=logging.DEBUG) + unittest.main() + +# vim: ts=4 et sts=4 |