class TestCache(unittest.TestCase): def setUp(self): # Whenever a test will initialize apt_pkg, we must set the architecture # to amd64, because our various test files assume that. Even if this # test doesn't use those files, apt_pkg is only initialized once across # tests, so we must be consistent. real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) # We don't need anything special, but since we modify architecture # above, we ought to point to an aptroot that matches the arch self.aptroot = os.path.join(CURDIR, "aptroot-cache-test") self.cache = MyCache(None, rootdir=self.aptroot) self.cache.open() def test_https_and_creds_in_changelog_uri(self): # credentials in https locations are not supported as they can # be man-in-the-middled because of the lack of cert checking in # urllib2 pkgname = "package-one" uri = "https://*****:*****@ubuntu.com/foo/bar" mock_binary = mock.Mock() mock_binary.return_value = uri self.cache._guess_third_party_changelogs_uri_by_binary = mock_binary mock_source = mock.Mock() mock_source.return_value = uri self.cache._guess_third_party_changelogs_uri_by_source = mock_source self.cache.all_changes[pkgname] = "header\n" self.cache._fetch_changelog_for_third_party_package(pkgname) self.assertEqual( self.cache.all_changes[pkgname], "header\n" "This update does not come from a source that supports " "changelogs.") def test_conflicts_replaces_removal(self): # An incomplete set of Conflicts/Replaces does not allow removal. with mock.patch("logging.info") as mock_info: self.assertEqual(1, self.cache.saveDistUpgrade()) mock_info.assert_called_once_with( "package-two Conflicts/Replaces package-one; allowing removal") self.assertEqual([], [pkg for pkg in self.cache if pkg.marked_delete]) # Specifying Conflicts/Replaces allows packages to be removed. apt.apt_pkg.config.set( "Dir::State::Status", self.aptroot + "/var/lib/dpkg/status-minus-three") apt.apt_pkg.init_system() self.cache.open() self.cache._initDepCache() with mock.patch("logging.info") as mock_info: self.assertEqual(0, self.cache.saveDistUpgrade()) mock_info.assert_called_once_with( "package-two Conflicts/Replaces package-one; allowing removal") self.assertEqual([self.cache["package-one"]], [pkg for pkg in self.cache if pkg.marked_delete])
def setUp(self): self.aptroot = os.path.join(CURDIR, "aptroot-update-origin") self.dpkg_status = open("%s/var/lib/dpkg/status" % self.aptroot, "w") self.dpkg_status.flush() self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open()
def openCache(self): # open cache progress = apt.progress.text.OpProgress() if hasattr(self, "cache"): self.cache.open(progress) self.cache._initDepCache() else: self.cache = MyCache(progress) self.actiongroup = apt_pkg.ActionGroup(self.cache._depcache) # lock the cache self.cache.lock = True
def setUp(self): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-update-list-test") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache.open() self.updates_list = UpdateList.UpdateList(parent=None)
def setUp(self, mock_desktop, mock_installed): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-grouping-test") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache.open() mock_installed.__get__ = self.fake_installed_files mock_desktop.side_effect = self.fake_desktop self.updates_list = UpdateList.UpdateList(parent=None, dist='lucid') self.updates_list.update(self.cache)
def setUp(self): # Whenever a test will initialize apt_pkg, we must set the architecture # to amd64, because our various test files assume that. Even if this # test doesn't use those files, apt_pkg is only initialized once across # tests, so we must be consistent. real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) aptroot = os.path.join(CURDIR, "aptroot-changelog") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=aptroot) self.cache.open()
def setUp(self): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-update-origin") self.dpkg_status = open("%s/var/lib/dpkg/status" % self.aptroot, "w") self.dpkg_status.flush() self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open()
def setUp(self): # Whenever a test will initialize apt_pkg, we must set the architecture # to amd64, because our various test files assume that. Even if this # test doesn't use those files, apt_pkg is only initialized once across # tests, so we must be consistent. real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) # We don't need anything special, but since we modify architecture # above, we ought to point to an aptroot that matches the arch self.aptroot = os.path.join(CURDIR, "aptroot-cache-test") self.cache = MyCache(None, rootdir=self.aptroot) self.cache.open()
class TestChangelogs(unittest.TestCase): def setUp(self): # Whenever a test will initialize apt_pkg, we must set the architecture # to amd64, because our various test files assume that. Even if this # test doesn't use those files, apt_pkg is only initialized once across # tests, so we must be consistent. real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) aptroot = os.path.join(CURDIR, "aptroot-changelog") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=aptroot) self.cache.open() def test_get_changelogs_uri(self): pkgname = "gcc" # test binary changelogs uri = self.cache._guess_third_party_changelogs_uri_by_binary(pkgname) pkg = self.cache[pkgname] self.assertEqual(uri, pkg.candidate.uri.replace(".deb", ".changelog")) # test source changelogs uri = self.cache._guess_third_party_changelogs_uri_by_source(pkgname) self.assertTrue("gcc-defaults_" in uri) self.assertTrue(uri.endswith(".changelog")) # and one without a "Source" entry, we don't find something here uri = self.cache._guess_third_party_changelogs_uri_by_source("apt") self.assertEqual(uri, None) # one with srcver == binver pkgname = "libgtk2.0-dev" uri = self.cache._guess_third_party_changelogs_uri_by_source(pkgname) pkg = self.cache[pkgname] self.assertTrue(pkg.candidate.version in uri) self.assertTrue("gtk+2.0" in uri) def test_changelog_not_supported(self): def monkey_patched_get_changelogs(name, what, ver, uri): with open("/dev/zero") as zero: raise HTTPError("url", "code", "msg", "hdrs", zero) pkgname = "gcc" # patch origin real_origin = self.cache.CHANGELOG_ORIGIN self.cache.CHANGELOG_ORIGIN = "xxx" # monkey patch to raise the right error self.cache._get_changelog_or_news = monkey_patched_get_changelogs # get changelog self.cache.get_changelog(pkgname) error = "This update does not come from a source that " error += "supports changelogs." # verify that we don't have the lines twice self.assertEqual(self.cache.all_changes[pkgname].split("\n")[-1], error) self.assertEqual(len(self.cache.all_changes[pkgname].split("\n")), 5) self.assertEqual(self.cache.all_changes[pkgname].count(error), 1) self.cache.CHANGELOG_ORIGIN = real_origin
def openCache(self): # open cache progress = apt.progress.OpTextProgress() if hasattr(self, "cache"): self.cache.open(progress) self.cache._initDepCache() else: self.cache = MyCache(progress) self.actiongroup = apt_pkg.GetPkgActionGroup(self.cache._depcache) # lock the cache self.cache.lock = True
def setUp(self): # Whenever a test will initialize apt_pkg, we must set the architecture # to amd64, because our various test files assume that. Even if this # test doesn't use those files, apt_pkg is only initialized once across # tests, so we must be consistent. real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) aptroot = os.path.join(CURDIR, "aptroot-changelog") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=aptroot)
class TestChangelogs(unittest.TestCase): def setUp(self): # Whenever a test will initialize apt_pkg, we must set the architecture # to amd64, because our various test files assume that. Even if this # test doesn't use those files, apt_pkg is only initialized once across # tests, so we must be consistent. real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) aptroot = os.path.join(CURDIR, "aptroot-changelog") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=aptroot) def test_get_changelogs_uri(self): pkgname = "gcc" # test binary changelogs uri = self.cache._guess_third_party_changelogs_uri_by_binary(pkgname) pkg = self.cache[pkgname] self.assertEqual(uri, pkg.candidate.uri.replace(".deb", ".changelog")) # test source changelogs uri = self.cache._guess_third_party_changelogs_uri_by_source(pkgname) self.assertTrue("gcc-defaults_" in uri) self.assertTrue(uri.endswith(".changelog")) # and one without a "Source" entry, we don't find something here uri = self.cache._guess_third_party_changelogs_uri_by_source("apt") self.assertEqual(uri, None) # one with srcver == binver pkgname = "libgtk2.0-dev" uri = self.cache._guess_third_party_changelogs_uri_by_source(pkgname) pkg = self.cache[pkgname] self.assertTrue(pkg.candidate.version in uri) self.assertTrue("gtk+2.0" in uri) def test_changelog_not_supported(self): def monkey_patched_get_changelogs(name, what, ver, uri): with open("/dev/zero") as zero: raise HTTPError( "url", "code", "msg", "hdrs", zero) pkgname = "gcc" # patch origin real_origin = self.cache.CHANGELOG_ORIGIN self.cache.CHANGELOG_ORIGIN = "xxx" # monkey patch to raise the right error self.cache._get_changelog_or_news = monkey_patched_get_changelogs # get changelog self.cache.get_changelog(pkgname) error = "This update does not come from a source that " error += "supports changelogs." # verify that we don't have the lines twice self.assertEqual(self.cache.all_changes[pkgname].split("\n")[-1], error) self.assertEqual(len(self.cache.all_changes[pkgname].split("\n")), 5) self.assertEqual(self.cache.all_changes[pkgname].count(error), 1) self.cache.CHANGELOG_ORIGIN = real_origin
def setUp(self): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-update-list-test") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open() self.updates_list = UpdateList.UpdateList(parent=None)
class TestChangelogs(unittest.TestCase): def setUp(self): self.cache = MyCache(apt.progress.base.OpProgress()) def test_get_changelogs_uri(self): pkgname = "gcc" # test binary changelogs uri = self.cache._guess_third_party_changelogs_uri_by_binary(pkgname) pkg = self.cache[pkgname] self.assertEqual(uri, pkg.candidate.uri.replace(".deb", ".changelog")) # test source changelogs uri = self.cache._guess_third_party_changelogs_uri_by_source(pkgname) self.assertTrue("gcc-defaults_" in uri) self.assertTrue(uri.endswith(".changelog")) # and one without a "Source" entry, we don't find something here self.assertEqual(self.cache._guess_third_party_changelogs_uri_by_source("apt"), None) # one with srcver == binver pkgname = "libgtk2.0-dev" uri = self.cache._guess_third_party_changelogs_uri_by_source(pkgname) pkg = self.cache[pkgname] self.assertTrue(pkg.candidate.version in uri) self.assertTrue("gtk+2.0" in uri) def test_changelog_not_supported(self): def monkey_patched_get_changelogs(name, what, ver, uri): raise urllib2.HTTPError( "url", "code", "msg", "hdrs", open("/dev/zero")) pkgname = "update-manager" # patch origin real_origin = self.cache.CHANGELOG_ORIGIN self.cache.CHANGELOG_ORIGIN = "xxx" # monkey patch to raise the right error self.cache._get_changelog_or_news = monkey_patched_get_changelogs # get changelog self.cache.get_changelog(pkgname) error = "This update does not come from a source that supports changelogs." # verify that we don't have the lines twice self.assertEqual(self.cache.all_changes[pkgname].split("\n")[-1], error) self.assertEqual(len(self.cache.all_changes[pkgname].split("\n")), 5) self.assertEqual(self.cache.all_changes[pkgname].count(error), 1) self.cache.CHANGELOG_ORIGIN = real_origin
class PhasedTestCase(unittest.TestCase): def setUp(self): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-update-list-test") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open() self.updates_list = UpdateList.UpdateList(parent=None) def assertUpdatesListLen(self, nr): self.assertEqual(self.updates_list.num_updates, nr) def test_phased_percentage_not_included(self): """ Test that updates above the threshold are not included""" with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 100 self.updates_list.update(self.cache) self.assertUpdatesListLen(1) def test_phased_percentage_included(self): """ Test that updates below the threshold are included""" with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 1 self.updates_list.update(self.cache) self.assertUpdatesListLen(2) def test_phased_percentage_included_via_force(self): """ Test that the "always" override config works """ # set config to force override apt.apt_pkg.config.set( self.updates_list.ALWAYS_INCLUDE_PHASED_UPDATES, "1") self.addCleanup(lambda: apt.apt_pkg.config.set( self.updates_list.ALWAYS_INCLUDE_PHASED_UPDATES, "0")) # ensure it's included even if it's above the threshold with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 100 self.updates_list.update(self.cache) self.assertUpdatesListLen(2) def test_phased_percentage_excluded_via_force(self): """ Test that the "never" override config works """ # set config to force override apt.apt_pkg.config.set( self.updates_list.NEVER_INCLUDE_PHASED_UPDATES, "1") self.addCleanup(lambda: apt.apt_pkg.config.set( self.updates_list.NEVER_INCLUDE_PHASED_UPDATES, "0")) # ensure it's excluded even if it's below the threshold with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 0 self.updates_list.update(self.cache) self.assertUpdatesListLen(1) @patch('UpdateManager.Core.UpdateList.UpdateList._is_security_update') def test_phased_percentage_from_security(self, mock_security): """ Test that updates from the security node go in""" # pretend all updates come from security for the sake of this test mock_security.return_value = True with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 100 self.updates_list.update(self.cache) self.assertUpdatesListLen(2)
class UpdateManagerText(object): DEBUG = False def __init__(self, datadir): self.screen = SnackScreen() # FIXME: self.screen.finish() clears the screen (and all messages) # there too #atexit.register(self.restoreScreen) self.button_bar = ButtonBar(self.screen, ( (_("Cancel"), "cancel"), (_("Install"), "ok")), compact = True) self.textview_changes = Textbox(72, 8, "Changelog", True, True) self.checkbox_tree_updates = CheckboxTree(height=8, width=72, scroll=1) self.checkbox_tree_updates.setCallback(self.checkbox_changed) self.layout = GridForm(self.screen, "Updates", 1, 5) self.layout.add(self.checkbox_tree_updates, 0, 0) # empty line to make it look less crowded self.layout.add(Textbox(60, 1," ",False, False), 0, 1) self.layout.add(self.textview_changes, 0, 2) # empty line to make it look less crowded self.layout.add(Textbox(60, 1," ",False, False), 0, 3) self.layout.add(self.button_bar, 0, 4) # FIXME: better progress than the current suspend/resume screen thing self.screen.suspend() if not self.DEBUG: apt_pkg.PkgSystemLock() self.openCache() print _("Building Updates List") self.fillstore() if self.list.distUpgradeWouldDelete > 0: print _(""" A normal upgrade can not be calculated, please run: sudo apt-get dist-upgrade This can be caused by: * A previous upgrade which didn't complete * Problems with some of the installed software * Unofficial software packages not provided by Ubuntu * Normal changes of a pre-release version of Ubuntu""") sys.exit(1) self.screen.resume() # def restoreScreen(self): # self.screen.finish() def openCache(self): # open cache progress = apt.progress.OpTextProgress() if hasattr(self, "cache"): self.cache.open(progress) self.cache._initDepCache() else: self.cache = MyCache(progress) self.actiongroup = apt_pkg.GetPkgActionGroup(self.cache._depcache) # lock the cache self.cache.lock = True def fillstore(self): # populate the list self.list = UpdateList(self) self.list.update(self.cache) origin_list = self.list.pkgs.keys() origin_list.sort(lambda x,y: cmp(x.importance, y.importance)) origin_list.reverse() for (i, origin) in enumerate(origin_list): self.checkbox_tree_updates.append(origin.description, selected=True) for pkg in self.list.pkgs[origin]: self.checkbox_tree_updates.addItem(pkg.name, (i, snackArgs['append']), pkg, selected = True) def updateSelectionStates(self): """ helper that goes over the cache and updates the selection states in the UI based on the cache """ for pkg in self.cache: if not self.checkbox_tree_updates.item2key.has_key(pkg): continue # update based on the status if pkg.markedUpgrade or pkg.markedInstall: self.checkbox_tree_updates.setEntryValue(pkg, True) else: self.checkbox_tree_updates.setEntryValue(pkg, False) self.updateUI() def updateUI(self): self.layout.draw() self.screen.refresh() def get_news_and_changelog(self, pkg): changes = "" name = pkg.name # if we don't have it, get it if (not self.cache.all_changes.has_key(name) and not self.cache.all_news.has_key(name)): self.textview_changes.setText(_("Downloading changelog")) lock = thread.allocate_lock() lock.acquire() thread.start_new_thread(self.cache.get_news_and_changelog,(name,lock)) # this lock should never take more than 2s even with network down while lock.locked(): time.sleep(0.03) # build changes from NEWS and changelog if self.cache.all_news.has_key(name): changes += self.cache.all_news[name] if self.cache.all_changes.has_key(name): changes += self.cache.all_changes[name] return changes def checkbox_changed(self): # item is either a apt.package.Package or a str (for the headers) pkg = self.checkbox_tree_updates.getCurrent() descr = "" if hasattr(pkg, "name"): need_refresh = False name = pkg.name if self.options.show_description: descr = pkg.description else: descr = self.get_news_and_changelog(pkg) # check if it is a wanted package selected = self.checkbox_tree_updates.getEntryValue(pkg)[1] marked_install_upgrade = pkg.markedInstall or pkg.markedUpgrade if not selected and marked_install_upgrade: need_refresh = True pkg.markKeep() if selected and not marked_install_upgrade: if not (name in self.list.held_back): # FIXME: properly deal with "fromUser" here need_refresh = True pkg.markInstall() # fixup any problems if self.cache._depcache.BrokenCount: need_refresh = True Fix = apt_pkg.GetPkgProblemResolver(self.cache._depcache) Fix.ResolveByKeep() # update the list UI to reflect the cache state if need_refresh: self.updateSelectionStates() self.textview_changes.setText(descr) self.updateUI() def main(self, options): self.options = options res = self.layout.runOnce() self.screen.finish() button = self.button_bar.buttonPressed(res) if button == "ok": self.screen.suspend() res = self.cache.commit(apt.progress.text.AcquireProgress(), apt.progress.base.InstallProgress())
class TestOriginMatcher(unittest.TestCase): def setUp(self): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-update-origin") self.dpkg_status = open("%s/var/lib/dpkg/status" % self.aptroot, "w") self.dpkg_status.flush() self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open() def tearDown(self): # kill data dirs # FIXME: use tmpdir in the long run for d in ["var/lib/apt/lists/", "var/cache/apt"]: try: shutil.rmtree(os.path.join(self.aptroot, d)) except IOError: pass # kill off status file try: os.remove(os.path.join(self.aptroot, "var/lib/dpkg/status")) except OSError: pass def testOriginMatcherSimple(self): test_pkgs = set() for pkg in self.cache: if pkg.candidate and pkg.candidate.origins: if [l.archive for l in pkg.candidate.origins if l.archive == "xenial-security"]: test_pkgs.add(pkg.name) self.assertTrue(len(test_pkgs) > 0) ul = UpdateList(None, dist="xenial") for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertTrue(ul._is_security_update(pkg), "pkg '%s' is not in xenial-security" % pkg.name) def testOriginMatcherWithVersionInUpdatesAndSecurity(self): # empty dpkg status self.cache.open(apt.progress.base.OpProgress()) # find test packages set test_pkgs = set() for pkg in self.cache: # only test on native arch if ":" in pkg.name: continue # check if the candidate origin is -updates (but not also # -security, often packages are available in both) if pkg.candidate is not None: # ensure that the origin is not in -updates and -security is_in_updates = False is_in_security = False had_security = False for v in pkg.candidate.origins: # test if the package is not in both updates and security if v.archive == "xenial-updates": is_in_updates = True elif v.archive == "xenial-security": is_in_security = True # ensure that the package actually has any version in -security for v in pkg.versions: for (pkgfile, _unused) in v._cand.file_list: o = apt.package.Origin(pkg, pkgfile) if o.archive == "xenial-security": had_security = True break if (is_in_updates and not is_in_security and had_security and len(pkg._pkg.version_list) > 2): test_pkgs.add(pkg.name) self.assertTrue(len(test_pkgs) > 0, "no suitable test package found that has a version in " "both -security and -updates and where -updates is " "newer") # now test if versions in -security are detected ul = UpdateList(None, dist="xenial") for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertTrue(ul._is_security_update(pkg), "package '%s' from xenial-updates contains also a " "(not yet installed) security update, but it is " "not labeled as such" % pkg.name) # now check if it marks the version with -update if the -security # version is installed for pkgname in test_pkgs: pkg = self.cache[pkgname] # FIXME: make this more inteligent (picking the version from # -security sec_ver = pkg._pkg.version_list[1] self.dpkg_status.write("Package: %s\n" "Status: install ok installed\n" "Installed-Size: 1\n" "Version: %s\n" "Architecture: all\n" "Description: foo\n\n" % (pkg.name, sec_ver.ver_str)) self.dpkg_status.flush() self.cache.open() for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertIsNotNone(pkg._pkg.current_ver, "no package '%s' installed" % pkg.name) candidate_version = getattr(pkg.candidate, "version", None) self.assertFalse(ul._is_security_update(pkg), "package '%s' (%s) from xenial-updates is " "labelled as a security update even though we " "have marked this version as installed already" % (pkg.name, candidate_version))
class testOriginMatcher(unittest.TestCase): def setUp(self): self.aptroot = os.path.join(os.getcwd(), "aptroot-update-origin/") self.dpkg_status = open("%s/var/lib/dpkg/status" % self.aptroot,"w") self.dpkg_status.flush() self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open() def tearDown(self): # kill data dirs # FIXME: use tmpdir in the long run for d in ["var/lib/apt/lists/", "var/cache/apt"]: try: shutil.rmtree(os.path.join(self.aptroot, d)) except IOError: pass # kill off status file try: os.remove(os.path.join(self.aptroot, "var/lib/dpkg/status")) except OSError: pass def testOriginMatcherSimple(self): test_pkgs = set() for pkg in self.cache: if pkg.candidate and pkg.candidate.origins: if [l.archive for l in pkg.candidate.origins if l.archive == "lucid-security"]: test_pkgs.add(pkg.name) self.assertTrue(len(test_pkgs) > 0) ul = UpdateList(None) matcher = ul.initMatcher("lucid") for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertEqual(self.cache.matchPackageOrigin(pkg, matcher), matcher[("lucid-security","Ubuntu")], "pkg '%s' is not in lucid-security but in '%s' instead" % (pkg.name, self.cache.matchPackageOrigin(pkg, matcher).description)) def testOriginMatcherWithVersionInUpdatesAndSecurity(self): # empty dpkg status self.cache.open(apt.progress.base.OpProgress()) # find test packages set test_pkgs = set() for pkg in self.cache: # only test on native arch if ":" in pkg.name: continue if pkg.candidateOrigin: for v in pkg.candidateOrigin: if (v.archive == "lucid-updates" and len(pkg._pkg.version_list) > 2): test_pkgs.add(pkg.name) self.assert_(len(test_pkgs) > 0, "no suitable test package found that has a version in both -security and -updates and where -updates is newer") # now test if versions in -security are detected ul = UpdateList(None) matcher = ul.initMatcher("lucid") for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertEqual(self.cache.matchPackageOrigin(pkg, matcher), matcher[("lucid-security","Ubuntu")], "package '%s' from lucid-updates contains also a (not yet installed) security updates, but it is not labeled as such" % pkg.name) # now check if it marks the version with -update if the -security # version is installed for pkgname in test_pkgs: pkg = self.cache[pkgname] # FIXME: make this more inteligent (picking the versin from # -security sec_ver = pkg._pkg.version_list[1] self.dpkg_status.write("Package: %s\n" "Status: install ok installed\n" "Installed-Size: 1\n" "Version: %s\n" "Description: foo\n\n" % (pkg.name, sec_ver.ver_str)) self.dpkg_status.flush() self.cache.open() for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assert_(pkg._pkg.current_ver != None, "no package '%s' installed" % pkg.name) self.assertEqual(self.cache.matchPackageOrigin(pkg, matcher), matcher[("lucid-updates","Ubuntu")], "package '%s' (%s) from lucid-updates is labeld '%s' even though we have marked this version as installed already" % (pkg.name, pkg.candidateVersion, self.cache.matchPackageOrigin(pkg, matcher).description))
class UpdateManagerText(object): DEBUG = False def __init__(self, datadir): self.screen = SnackScreen() # FIXME: self.screen.finish() clears the screen (and all messages) # there too #atexit.register(self.restoreScreen) self.button_bar = ButtonBar(self.screen, ((_("Cancel"), "cancel"), (_("Install"), "ok")), compact=True) self.textview_changes = Textbox(72, 8, _("Changelog"), True, True) self.checkbox_tree_updates = CheckboxTree(height=8, width=72, scroll=1) self.checkbox_tree_updates.setCallback(self.checkbox_changed) self.layout = GridForm(self.screen, _("Updates"), 1, 5) self.layout.add(self.checkbox_tree_updates, 0, 0) # empty line to make it look less crowded self.layout.add(Textbox(60, 1, " ", False, False), 0, 1) self.layout.add(self.textview_changes, 0, 2) # empty line to make it look less crowded self.layout.add(Textbox(60, 1, " ", False, False), 0, 3) self.layout.add(self.button_bar, 0, 4) # FIXME: better progress than the current suspend/resume screen thing self.screen.suspend() if not self.DEBUG: apt_pkg.pkgsystem_lock() self.openCache() print(_("Building Updates List")) self.fillstore() if self.list.distUpgradeWouldDelete > 0: print( _(""" A normal upgrade can not be calculated, please run: sudo apt-get dist-upgrade This can be caused by: * A previous upgrade which didn't complete * Problems with some of the installed software * Unofficial software packages not provided by Ubuntu * Normal changes of a pre-release version of Ubuntu""")) sys.exit(1) self.screen.resume() # def restoreScreen(self): # self.screen.finish() def openCache(self): # open cache progress = apt.progress.text.OpProgress() if hasattr(self, "cache"): self.cache.open(progress) self.cache._initDepCache() else: self.cache = MyCache(progress) self.actiongroup = apt_pkg.ActionGroup(self.cache._depcache) # lock the cache self.cache.lock = True def fillstore(self): # populate the list self.list = UpdateList(self) self.list.update(self.cache) origin_list = sorted(self.list.pkgs, key=operator.attrgetter("importance"), reverse=True) for (i, origin) in enumerate(origin_list): self.checkbox_tree_updates.append(origin.description, selected=True) for pkg in self.list.pkgs[origin]: self.checkbox_tree_updates.addItem(pkg.name, (i, snackArgs['append']), pkg, selected=True) def updateSelectionStates(self): """ helper that goes over the cache and updates the selection states in the UI based on the cache """ for pkg in self.cache: if pkg not in self.checkbox_tree_updates.item2key: continue # update based on the status if pkg.marked_upgrade or pkg.marked_install: self.checkbox_tree_updates.setEntryValue(pkg, True) else: self.checkbox_tree_updates.setEntryValue(pkg, False) self.updateUI() def updateUI(self): self.layout.draw() self.screen.refresh() def get_news_and_changelog(self, pkg): changes = "" name = pkg.name # if we don't have it, get it if (name not in self.cache.all_changes and name not in self.cache.all_news): self.textview_changes.setText(_("Downloading changelog")) lock = threading.Lock() lock.acquire() changelog_thread = threading.Thread( target=self.cache.get_news_and_changelog, args=(name, lock)) changelog_thread.start() # this lock should never take more than 2s even with network down while lock.locked(): time.sleep(0.03) # build changes from NEWS and changelog if name in self.cache.all_news: changes += self.cache.all_news[name] if name in self.cache.all_changes: changes += self.cache.all_changes[name] return changes def checkbox_changed(self): # item is either a apt.package.Package or a str (for the headers) pkg = self.checkbox_tree_updates.getCurrent() descr = "" if hasattr(pkg, "name"): need_refresh = False name = pkg.name if self.options.show_description: descr = getattr(pkg.candidate, "description", None) else: descr = self.get_news_and_changelog(pkg) # check if it is a wanted package selected = self.checkbox_tree_updates.getEntryValue(pkg)[1] marked_install_upgrade = pkg.marked_install or pkg.marked_upgrade if not selected and marked_install_upgrade: need_refresh = True pkg.mark_keep() if selected and not marked_install_upgrade: if not (name in self.list.held_back): # FIXME: properly deal with "fromUser" here need_refresh = True pkg.mark_install() # fixup any problems if self.cache._depcache.broken_count: need_refresh = True Fix = apt_pkg.ProblemResolver(self.cache._depcache) Fix.resolve_by_keep() # update the list UI to reflect the cache state if need_refresh: self.updateSelectionStates() self.textview_changes.setText(descr) self.updateUI() def main(self, options): self.options = options res = self.layout.runOnce() self.screen.finish() button = self.button_bar.buttonPressed(res) if button == "ok": self.screen.suspend() res = self.cache.commit(apt.progress.text.AcquireProgress(), apt.progress.base.InstallProgress())
class GroupingTestCase(unittest.TestCase): # installed_files does not respect aptroot, so we have to patch it @patch('apt.package.Package.installed_files', new_callable=PropertyMock) @patch('gi.repository.Gio.DesktopAppInfo.new_from_filename') def setUp(self, mock_desktop, mock_installed): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-grouping-test") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache.open() mock_installed.__get__ = self.fake_installed_files mock_desktop.side_effect = self.fake_desktop self.updates_list = UpdateList.UpdateList(parent=None, dist='lucid') self.updates_list.update(self.cache) def fake_installed_files(self, mock_prop, pkg, pkg_class): if pkg.name == 'installed-app': return ['/usr/share/applications/installed-app.desktop'] elif pkg.name == 'installed-app-with-subitems': return ['/usr/share/applications/installed-app2.desktop'] else: return [] def fake_desktop(self, path): # These can all be the same for our purposes app = MagicMock() app.get_filename.return_value = path app.get_display_name.return_value = 'App ' + os.path.basename(path) app.get_icon.return_value = Gio.ThemedIcon.new("package") return app def test_app(self): self.assertGreater(len(self.updates_list.update_groups), 0) group = self.updates_list.update_groups[0] self.assertIsInstance(group, UpdateList.UpdateApplicationGroup) self.assertIsNotNone(group.core_item) self.assertEqual(group.core_item.pkg.name, 'installed-app') self.assertListEqual([x.pkg.name for x in group.items], ['installed-app']) def test_app_with_subitems(self): self.assertGreater(len(self.updates_list.update_groups), 1) group = self.updates_list.update_groups[1] self.assertIsInstance(group, UpdateList.UpdateApplicationGroup) self.assertIsNotNone(group.core_item) self.assertEqual(group.core_item.pkg.name, 'installed-app-with-subitems') self.assertListEqual( [x.pkg.name for x in group.items], ['installed-app-with-subitems', 'installed-pkg-single-dep']) def test_pkg(self): self.assertGreater(len(self.updates_list.update_groups), 2) group = self.updates_list.update_groups[2] self.assertIsInstance(group, UpdateList.UpdatePackageGroup) self.assertIsNotNone(group.core_item) self.assertEqual(group.core_item.pkg.name, 'installed-pkg') self.assertListEqual([x.pkg.name for x in group.items], ['installed-pkg']) def test_pkg_multiple_deps(self): self.assertEqual(len(self.updates_list.update_groups), 4) group = self.updates_list.update_groups[3] self.assertIsInstance(group, UpdateList.UpdatePackageGroup) self.assertIsNotNone(group.core_item) self.assertEqual(group.core_item.pkg.name, 'installed-pkg-multiple-deps') self.assertListEqual([x.pkg.name for x in group.items], ['installed-pkg-multiple-deps']) def test_security(self): self.assertEqual(len(self.updates_list.security_groups), 1) group = self.updates_list.security_groups[0] self.assertIsInstance(group, UpdateList.UpdateSystemGroup) self.assertIsNone(group.core_item) self.assertListEqual([x.pkg.name for x in group.items], ['base-pkg'])
class PhasedTestCase(unittest.TestCase): def setUp(self): # mangle the arch real_arch = apt.apt_pkg.config.find("APT::Architecture") apt.apt_pkg.config.set("APT::Architecture", "amd64") self.addCleanup( lambda: apt.apt_pkg.config.set("APT::Architecture", real_arch)) self.aptroot = os.path.join(CURDIR, "aptroot-update-list-test") self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache.open() self.updates_list = UpdateList.UpdateList(parent=None) def assertUpdatesListLen(self, nr): self.assertEqual(self.updates_list.num_updates, nr) def test_phased_percentage_not_included(self): """ Test that updates above the threshold are not included""" with patch.object(self.updates_list.random, "randint") as mock_randint: # threshold is 10 mock_randint.return_value = 11 self.updates_list.update(self.cache) self.assertUpdatesListLen(1) def test_phased_percentage_included(self): """ Test that updates below the threshold are included""" with patch.object(self.updates_list.random, "randint") as mock_randint: # threshold is 10 mock_randint.return_value = 9 self.updates_list.update(self.cache) self.assertUpdatesListLen(3) def test_second_phased_binary_not_included(self): """ Test that there is no overlap between the source packages of the packages being ignored and installed """ with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 11 self.updates_list.update(self.cache) ignored_srcs = set([ pkg.candidate.source_name for pkg in self.updates_list.ignored_phased_updates ]) group = self.updates_list.update_groups[0] install_srcs = set([x.pkg.candidate.source_name for x in group.items]) self.assertEqual(ignored_srcs, set({'zsh'})) self.assertEqual(install_srcs, set({'apt'})) self.assertTrue(len(ignored_srcs & install_srcs) == 0) def test_phased_percentage_included_via_force(self): """ Test that the "always" override config works """ # set config to force override apt.apt_pkg.config.set(self.updates_list.ALWAYS_INCLUDE_PHASED_UPDATES, "1") self.addCleanup(lambda: apt.apt_pkg.config.set( self.updates_list.ALWAYS_INCLUDE_PHASED_UPDATES, "0")) # ensure it's included even if it's above the threshold with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 100 self.updates_list.update(self.cache) self.assertUpdatesListLen(3) def test_phased_percentage_excluded_via_force(self): """ Test that the "never" override config works """ # set config to force override apt.apt_pkg.config.set(self.updates_list.NEVER_INCLUDE_PHASED_UPDATES, "1") self.addCleanup(lambda: apt.apt_pkg.config.set( self.updates_list.NEVER_INCLUDE_PHASED_UPDATES, "0")) # ensure it's excluded even if it's below the threshold with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 0 self.updates_list.update(self.cache) self.assertUpdatesListLen(1) @patch('UpdateManager.Core.UpdateList.UpdateList._is_security_update') def test_phased_percentage_from_security(self, mock_security): """ Test that updates from the security node go in""" # pretend all updates come from security for the sake of this test mock_security.return_value = True with patch.object(self.updates_list.random, "randint") as mock_randint: mock_randint.return_value = 100 self.updates_list.update(self.cache) self.assertUpdatesListLen(3)
class TestOriginMatcher(unittest.TestCase): def setUp(self): self.aptroot = os.path.join(CURDIR, "aptroot-update-origin") self.dpkg_status = open("%s/var/lib/dpkg/status" % self.aptroot, "w") self.dpkg_status.flush() self.cache = MyCache(apt.progress.base.OpProgress(), rootdir=self.aptroot) self.cache._listsLock = 0 self.cache.update() self.cache.open() def tearDown(self): # kill data dirs # FIXME: use tmpdir in the long run for d in ["var/lib/apt/lists/", "var/cache/apt"]: try: shutil.rmtree(os.path.join(self.aptroot, d)) except IOError: pass # kill off status file try: os.remove(os.path.join(self.aptroot, "var/lib/dpkg/status")) except OSError: pass def testOriginMatcherSimple(self): test_pkgs = set() for pkg in self.cache: if pkg.candidate and pkg.candidate.origins: if [l.archive for l in pkg.candidate.origins if l.archive == "lucid-security"]: test_pkgs.add(pkg.name) self.assertTrue(len(test_pkgs) > 0) ul = UpdateList(None, dist="lucid") for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertTrue(ul._is_security_update(pkg), "pkg '%s' is not in lucid-security" % pkg.name) def testOriginMatcherWithVersionInUpdatesAndSecurity(self): # empty dpkg status self.cache.open(apt.progress.base.OpProgress()) # find test packages set test_pkgs = set() for pkg in self.cache: # only test on native arch if ":" in pkg.name: continue # check if the candidate origin is -updates (but not also # -security, often packages are available in both) if pkg.candidate is not None: # ensure that the origin is not -updates and -security is_in_updates = False is_in_security = False for v in pkg.candidate.origins: # test if the package is not in both updates and security if v.archive == "lucid-updates": is_in_updates = True elif v.archive == "lucid-security": is_in_security = True if (is_in_updates and not is_in_security and len(pkg._pkg.version_list) > 2): test_pkgs.add(pkg.name) self.assertTrue(len(test_pkgs) > 0, "no suitable test package found that has a version in " "both -security and -updates and where -updates is " "newer") # now test if versions in -security are detected ul = UpdateList(None, dist="lucid") for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertTrue(ul._is_security_update(pkg), "package '%s' from lucid-updates contains also a " "(not yet installed) security updates, but it is " "not labeled as such" % pkg.name) # now check if it marks the version with -update if the -security # version is installed for pkgname in test_pkgs: pkg = self.cache[pkgname] # FIXME: make this more inteligent (picking the versin from # -security sec_ver = pkg._pkg.version_list[1] self.dpkg_status.write("Package: %s\n" "Status: install ok installed\n" "Installed-Size: 1\n" "Version: %s\n" "Architecture: all\n" "Description: foo\n\n" % (pkg.name, sec_ver.ver_str)) self.dpkg_status.flush() self.cache.open() for pkgname in test_pkgs: pkg = self.cache[pkgname] self.assertIsNotNone(pkg._pkg.current_ver, "no package '%s' installed" % pkg.name) candidate_version = getattr(pkg.candidate, "version", None) self.assertFalse(ul._is_security_update(pkg), "package '%s' (%s) from lucid-updates is " "labelled as a security update even though we " "have marked this version as installed already" % (pkg.name, candidate_version))
def setUp(self): self.cache = MyCache(apt.progress.base.OpProgress())