diff options
Diffstat (limited to 'tests/test_aptsources.py')
-rw-r--r-- | tests/test_aptsources.py | 1573 |
1 files changed, 1573 insertions, 0 deletions
diff --git a/tests/test_aptsources.py b/tests/test_aptsources.py new file mode 100644 index 0000000..1e04552 --- /dev/null +++ b/tests/test_aptsources.py @@ -0,0 +1,1573 @@ +#!/usr/bin/python3 + +import copy +import os +import tempfile +import unittest + +import apt_pkg +import testcommon + +import aptsources.distro +import aptsources.sourceslist + + +class TestAptSources(testcommon.TestCase): + def setUp(self): + testcommon.TestCase.setUp(self) + if apt_pkg.config["APT::Architecture"] not in ("i386", "amd64"): + apt_pkg.config.set("APT::Architecture", "i386") + apt_pkg.config.set("Dir::Etc", os.getcwd()) + apt_pkg.config.set("Dir::Etc::sourceparts", tempfile.mkdtemp()) + if os.path.exists("./build/data/templates"): + self.templates = os.path.abspath("./build/data/templates") + elif os.path.exists("../build/data/templates"): + self.templates = os.path.abspath("../build/data/templates") + else: + self.templates = "/usr/share/python-apt/templates/" + + def tearDown(self): + aptsources.distro._OSRelease.OS_RELEASE_FILE = ( + aptsources.distro._OSRelease.DEFAULT_OS_RELEASE_FILE + ) + if "LSB_ETC_LSB_RELEASE" in os.environ: + del os.environ["LSB_ETC_LSB_RELEASE"] + + def testIsMirror(self): + """aptsources: Test mirror detection.""" + yes = aptsources.sourceslist.is_mirror( + "http://archive.ubuntu.com", "http://de.archive.ubuntu.com" + ) + no = aptsources.sourceslist.is_mirror( + "http://archive.ubuntu.com", "http://ftp.debian.org" + ) + self.assertTrue(yes) + self.assertFalse(no) + + def testSourcesListReading(self): + """aptsources: Test sources.list parsing.""" + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + sources = aptsources.sourceslist.SourcesList(True, self.templates) + self.assertEqual(len(sources.list), 10) + # test load + sources.list = [] + sources.load("data/aptsources/sources.list") + self.assertEqual(len(sources.list), 10) + + def testSourcesListReading_deb822(self): + """aptsources: Test sources.list parsing.""" + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + self.assertEqual(len(sources.list), 5) + # test load + sources.list = [] + sources.load("data/aptsources/sources.list.d/main.sources") + self.assertEqual(len(sources.list), 5) + + for entry in sources.list: + self.assertFalse(entry.invalid) + self.assertFalse(entry.disabled) + self.assertEqual(entry.types, ["deb"]) + self.assertEqual(entry.type, "deb") + self.assertEqual(entry.uris, ["http://de.archive.ubuntu.com/ubuntu/"]) + self.assertEqual(entry.uri, "http://de.archive.ubuntu.com/ubuntu/") + + self.assertEqual(sources.list[0].comps, ["main"]) + self.assertEqual(sources.list[1].comps, ["restricted"]) + self.assertEqual(sources.list[2].comps, ["universe"]) + self.assertEqual(sources.list[3].comps, ["main"]) + self.assertEqual(sources.list[4].comps, ["main"]) + + for entry in sources.list[:-1]: + self.assertIsNone(entry.trusted) + + self.assertTrue(sources.list[-1].trusted) + + for entry in sources.list[:-2]: + self.assertEqual(entry.architectures, []) + self.assertEqual(entry.suites, ["edgy"]) + self.assertEqual(entry.dist, "edgy") + + for entry in sources.list[-2:]: + self.assertEqual(entry.suites, ["natty"]) + self.assertEqual(entry.dist, "natty") + self.assertEqual(entry.architectures, ["amd64", "i386"]) + + def testSourcesListWriting_deb822(self): + """aptsources: Test sources.list parsing.""" + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + with tempfile.TemporaryDirectory() as tmpdir: + for entry in sources.list: + entry.file = os.path.join(tmpdir, os.path.basename(entry.file)) + + sources.save() + + maxDiff = self.maxDiff + self.maxDiff = None + for file in os.listdir("data/aptsources/sources.list.d"): + with open(os.path.join("data/aptsources/sources.list.d", file)) as a: + with open(os.path.join(tmpdir, file)) as b: + self.assertEqual(a.read(), b.read(), f"file {file}") + self.maxDiff = maxDiff + + def testSourcesListAdding(self): + """aptsources: Test additions to sources.list""" + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + sources = aptsources.sourceslist.SourcesList(True, self.templates) + # test to add something that is already there (main) + before = copy.deepcopy(sources) + sources.add("deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"]) + self.assertTrue(sources.list == before.list) + # test to add something that is already there (restricted) + before = copy.deepcopy(sources) + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["restricted"] + ) + self.assertTrue(sources.list == before.list) + + before = copy.deepcopy(sources) + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "natty", + ["main"], + architectures=["amd64", "i386"], + ) + self.assertTrue(sources.list == before.list) + + # test to add something new: multiverse + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"] + ) + found = False + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and "multiverse" in entry.comps + ): + found = True + break + self.assertTrue(found) + + # add a new natty entry without architecture specification + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "natty", ["multiverse"] + ) + found = False + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "natty" + and entry.architectures == [] + and "multiverse" in entry.comps + ): + found = True + break + self.assertTrue(found) + + # Add universe to existing multi-arch line + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "natty", + ["universe"], + architectures=["i386", "amd64"], + ) + found = False + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "natty" + and set(entry.architectures) == {"amd64", "i386"} + and set(entry.comps) == {"main", "universe"} + ): + found = True + break + self.assertTrue(found) + # test to add something new: multiverse *and* + # something that is already there + before = copy.deepcopy(sources) + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "edgy", + ["universe", "something"], + ) + found_universe = 0 + found_something = 0 + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + ): + for c in entry.comps: + if c == "universe": + found_universe += 1 + if c == "something": + found_something += 1 + # print "\n".join([s.str() for s in sources]) + self.assertEqual(found_something, 1) + self.assertEqual(found_universe, 1) + + def testSourcesListAdding_deb822(self): + """aptsources: Test additions to sources.list""" + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + # test to add something that is already there (main) + before = copy.deepcopy(sources) + sources.add("deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"]) + self.assertEqual(sources.list, before.list) + # test to add something that is already there (restricted) + before = copy.deepcopy(sources) + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["restricted"] + ) + self.assertTrue(sources.list == before.list) + + before = copy.deepcopy(sources) + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "natty", + ["main"], + architectures=["amd64", "i386"], + ) + self.assertEqual( + [e.str() for e in sources.list], [e.str() for e in before.list] + ) + + # test to add something new: multiverse + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"] + ) + found = False + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and "multiverse" in entry.comps + ): + found = True + break + self.assertTrue(found) + + # add a new natty entry without architecture specification + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "natty", ["multiverse"] + ) + found = False + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "natty" + and entry.architectures == [] + and "multiverse" in entry.comps + ): + found = True + break + self.assertTrue(found) + + # Add universe to existing multi-arch line + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "natty", + ["universe"], + architectures=["i386", "amd64"], + ) + found = False + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "natty" + and set(entry.architectures) == {"amd64", "i386"} + and set(entry.comps) == {"main", "universe"} + ): + found = True + break + self.assertTrue(found) + # test to add something new: multiverse *and* + # something that is already there + before = copy.deepcopy(sources) + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "edgy", + ["universe", "something"], + ) + found_universe = 0 + found_something = 0 + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + ): + for c in entry.comps: + if c == "universe": + found_universe += 1 + if c == "something": + found_something += 1 + # print "\n".join([s.str() for s in sources]) + self.assertEqual(found_something, 1) + self.assertEqual(found_universe, 1) + + def testAddingWithComment_deb822(self): + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + self._commonTestAddingWithComment() + + def testAddingWithComment_short(self): + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + self._commonTestAddingWithComment() + + def _commonTestAddingWithComment(self): + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + + # test to add something that is already there (main); loses comment + before = copy.deepcopy(sources) + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "edgy", + ["main"], + comment="this will be lost", + ) + self.assertTrue(sources.list == before.list) + for entry in sources: + self.assertNotEqual(entry.comment, "this will be lost") + + # test to add component to existing entry: multiverse; loses comment + sources.add( + "deb", + "http://de.archive.ubuntu.com/ubuntu/", + "edgy", + ["multiverse"], + comment="this will be lost", + ) + for entry in sources: + self.assertNotEqual(entry.comment, "this will be lost") + + before = copy.deepcopy(sources) + # test to add entirely new entry; retains comment + sources.add( + "deb-src", + "http://de.archive.ubuntu.com/ubuntu/", + "edgy", + ["main"], + comment="this will appear", + file=sources.list[0].file, # make sure we test the deb822 code path + ) + self.assertNotEqual(sources.list, before.list) + self.assertEqual(len(sources.list), len(before.list) + 1) + found = False + for entry in sources: + if ( + entry.type == "deb-src" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and entry.comment == "this will appear" + and "main" in entry.comps + ): + found = True + break + self.assertTrue(found) + + def testInsertion_deb822(self): + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + + # test to insert something that is already there (universe); does not + # move existing entry (remains at index 2) + before = copy.deepcopy(sources) + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["universe"], pos=0 + ) + self.assertTrue(sources.list == before.list) + entry = list(sources)[2] + self.assertEqual(entry.type, "deb") + self.assertEqual(entry.uri, "http://de.archive.ubuntu.com/ubuntu/") + self.assertEqual(entry.dist, "edgy") + self.assertIn("universe", entry.comps) + + # test add component to existing entry: multiverse; does not move + # entry to which it is appended (remains at index 0) + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"], pos=2 + ) + entry = list(sources)[0] + self.assertTrue( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and {"main", "multiverse"} <= set(entry.comps) + ) + + # test to add entirely new entry; inserted at 0 + sources.add( + "deb-src", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"], pos=0 + ) + entry = list(sources)[0] + self.assertTrue( + entry.type == "deb-src" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and "main" in entry.comps + ) + + def testInsertion(self): + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + sources = aptsources.sourceslist.SourcesList(True, self.templates) + + # test to insert something that is already there (universe); does not + # move existing entry (remains at index 2) + before = copy.deepcopy(sources) + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["universe"], pos=0 + ) + self.assertTrue(sources.list == before.list) + entry = list(sources)[5] + self.assertTrue( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and "universe" in entry.comps + ) + + # test add component to existing entry: multiverse; does not move + # entry to which it is appended (remains at index 0) + sources.add( + "deb", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["multiverse"], pos=2 + ) + entry = list(sources)[1] + self.assertTrue( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and {"main", "multiverse"} <= set(entry.comps) + ) + + # test to add entirely new entry; inserted at 0 + sources.add( + "deb-src", "http://de.archive.ubuntu.com/ubuntu/", "edgy", ["main"], pos=0 + ) + entry = list(sources)[0] + self.assertTrue( + entry.type == "deb-src" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and entry.dist == "edgy" + and "main" in entry.comps + ) + + def testDuplication_short(self): + apt_pkg.config.set( + "Dir::Etc::sourcelist", "data/aptsources/sources.list.testDuplication" + ) + return self.commonTestDuplication() + + def testDuplication_deb822(self): + apt_pkg.config.set( + "Dir::Etc::sourceparts", "data/aptsources/sources.list.d.testDuplication" + ) + return self.commonTestDuplication() + + def commonTestDuplication(self): + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + test_url = "http://ppa.launchpad.net/me/myproject/ubuntu" + # test to add something that is already there (enabled) + before = copy.deepcopy(sources) + sources.add("deb", test_url, "xenial", ["main"]) + self.assertEqual(sources.list, before.list) + # test to add something that is already there (disabled) + sources.add("# deb-src", test_url, "xenial", ["main"]) + self.assertEqual(sources.list, before.list) + # test to enable something that is already there + sources.add("deb-src", test_url, "xenial", ["main"]) + found = False + self.assertEqual(len(sources.list), 2) + for entry in sources: + if ( + entry.type == "deb-src" + and not entry.disabled + and entry.uri == test_url + and entry.dist == "xenial" + and entry.architectures == [] + and entry.comps == ["main"] + ): + found = True + break + self.assertTrue(found) + + def testMatcher_short(self): + """aptsources: Test matcher""" + apt_pkg.config.set( + "Dir::Etc::sourcelist", "data/aptsources/" "sources.list.testDistribution" + ) + return self.commonTestMatcher() + + def testMatcher_deb822(self): + """aptsources: Test matcher""" + apt_pkg.config.set( + "Dir::Etc::sourceparts", + "data/aptsources/" "sources.list.d.testDistribution", + ) + return self.commonTestMatcher() + + def commonTestMatcher(self): + """aptsources: Test matcher""" + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + distro = aptsources.distro.get_distro( + id="Ubuntu", + codename="bionic", + description="Ubuntu 18.04 LTS", + release="18.04", + ) + distro.get_sources(sources) + # test if all suits of the current distro were detected correctly + self.assertNotEqual(sources.list, []) + for s in sources: + if not s.template: + self.fail("source entry '%s' has no matcher" % s) + + # Hack in a check for splitting of fields here. + if sources.list[-1].file.endswith(".sources"): + self.assertEqual( + sources.list[-1].uris, ["cdrom:[Ubuntu 8.04 _Hardy Heron_]"] + ) + self.assertEqual(sources.list[-1].uri, "cdrom:[Ubuntu 8.04 _Hardy Heron_]") + + def testMultiArch(self): + """aptsources: Test multi-arch parsing""" + + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + assert not sources.list[8].invalid + assert sources.list[8].type == "deb" + assert sources.list[8].architectures == ["amd64", "i386"] + assert sources.list[8].uri == "http://de.archive.ubuntu.com/ubuntu/" + assert sources.list[8].dist == "natty" + assert sources.list[8].comps == ["main"] + assert sources.list[8].line.strip() == str(sources.list[8]) + assert sources.list[8].trusted is None + + def testMultiArch_deb822(self): + """aptsources: Test multi-arch parsing""" + + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + assert not sources.list[3].invalid + assert sources.list[3].type == "deb" + assert sources.list[3].architectures == ["amd64", "i386"] + assert sources.list[3].uri == "http://de.archive.ubuntu.com/ubuntu/" + assert sources.list[3].dist == "natty" + assert sources.list[3].comps == ["main"] + self.assertEqual(sources.list[3].line.strip(), str(sources.list[3])) + self.assertIsNone(sources.list[3].trusted) + + def testMultipleOptions(self): + """aptsources: Test multi-arch parsing""" + + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + sources = aptsources.sourceslist.SourcesList(True, self.templates) + assert sources.list[9].invalid is False + assert sources.list[9].type == "deb" + assert sources.list[9].architectures == ["amd64", "i386"] + self.assertEqual(sources.list[9].uri, "http://de.archive.ubuntu.com/ubuntu/") + assert sources.list[9].dist == "natty" + assert sources.list[9].comps == ["main"] + assert sources.list[9].trusted + assert sources.list[9].line.strip() == str(sources.list[9]) + + def testMultipleOptions_deb822(self): + """aptsources: Test multi-arch parsing""" + + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + assert sources.list[4].invalid is False + assert sources.list[4].type == "deb" + assert sources.list[4].architectures == ["amd64", "i386"] + self.assertEqual(sources.list[4].uri, "http://de.archive.ubuntu.com/ubuntu/") + assert sources.list[4].dist == "natty" + assert sources.list[4].comps == ["main"] + assert sources.list[4].trusted + assert sources.list[4].line.strip() == str(sources.list[4]) + + def test_enable_component(self): + target = "./data/aptsources/sources.list.enable_comps" + line = "deb http://archive.ubuntu.com/ubuntu lucid main\n" + with open(target, "w") as target_file: + target_file.write(line) + apt_pkg.config.set("Dir::Etc::sourcelist", target) + sources = aptsources.sourceslist.SourcesList(True, self.templates) + distro = aptsources.distro.get_distro( + id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04" + ) + # and get the sources + distro.get_sources(sources) + # test enable_component + comp = "multiverse" + distro.enable_component(comp) + comps = set() + for entry in sources: + comps = comps.union(set(entry.comps)) + self.assertTrue("multiverse" in comps) + self.assertTrue("universe" in comps) + + def test_enable_component_deb822(self): + target = ( + apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources" + ) + line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu\nSuites: lucid\nComponents: main\n" + with open(target, "w") as target_file: + target_file.write(line) + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + distro = aptsources.distro.get_distro( + id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04" + ) + # and get the sources + distro.get_sources(sources) + # test enable_component + comp = "multiverse" + distro.enable_component(comp) + comps = set() + for entry in sources: + comps = comps.union(set(entry.comps)) + self.assertTrue("multiverse" in comps) + self.assertTrue("universe" in comps) + + def test_enable_component_deb822_multi(self): + apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null") + + target = ( + apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources" + ) + line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu\nSuites: lucid lucid-updates\nComponents: main\n" + with open(target, "w") as target_file: + target_file.write(line) + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + distro = aptsources.distro.get_distro( + id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04" + ) + # and get the sources + distro.get_sources(sources) + self.assertEqual(len(distro.main_sources), 1) + self.assertEqual(len(sources.list), 1) + # test enable_component + comp = "multiverse" + distro.enable_component(comp) + self.assertEqual(len(sources.list), 2) # split into two + + self.assertEqual( + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu\n" + "Suites: lucid\n" + "Components: main multiverse universe", + str(sources.list[0]), + ) + self.assertEqual( + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu\n" + "Suites: lucid-updates\n" + "Components: main multiverse universe", + str(sources.list[1]), + ) + + comps = set() + for entry in sources: + comps = comps.union(set(entry.comps)) + self.assertTrue("multiverse" in comps) + self.assertTrue("universe" in comps) + + sources.save() + self.assertEqual( + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu\n" + "Suites: lucid lucid-updates\n" + "Components: main multiverse universe", + str(sources.list[0]), + ) + + def test_enable_component_deb822_multi_mixed_origin(self): + apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null") + + target = ( + apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources" + ) + line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu http://example.com/\nSuites: lucid\nComponents: main\n" + with open(target, "w") as target_file: + target_file.write(line) + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + distro = aptsources.distro.get_distro( + id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04" + ) + # and get the sources + distro.get_sources(sources) + self.assertEqual(len(distro.main_sources), 2) + self.assertEqual(len(sources.list), 1) + # test enable_component + comp = "multiverse" + distro.enable_component(comp) + self.assertEqual(len(sources.list), 2) # split into two + + self.assertEqual( + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu\n" + "Suites: lucid\n" + "Components: main multiverse universe", + str(sources.list[0]), + ) + self.assertEqual( + "Types: deb\n" + "URIs: http://example.com/\n" + "Suites: lucid\n" + "Components: main", + str(sources.list[1]), + ) + + sources.save() + self.assertEqual( + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu\n" + "Suites: lucid\n" + "Components: main multiverse universe", + str(sources.list[0]), + ) + self.assertEqual( + "Types: deb\n" + "URIs: http://example.com/\n" + "Suites: lucid\n" + "Components: main", + str(sources.list[1]), + ) + + def test_enable_component_deb822_multi_mixed_ultimate(self): + apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null") + + target = ( + apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources" + ) + line = "Types: deb deb-src\nURIs: http://archive.ubuntu.com/ubuntu http://example.com/\nSuites: lucid lucid-updates notalucid\nComponents: main\n" + with open(target, "w") as target_file: + target_file.write(line) + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + distro = aptsources.distro.get_distro( + id="Ubuntu", codename="lucid", release="10.04", description="Ubuntu 10.04" + ) + # and get the sources + distro.get_sources(sources) + self.assertEqual(len(distro.main_sources), 1) + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 12) + # test enable_component + comp = "multiverse" + distro.enable_component(comp) + self.assertEqual(len(sources.list), 12) # split into two + + expected = [] + for typ in "deb", "deb-src": + for uri in "http://archive.ubuntu.com/ubuntu", "http://example.com/": + for suite in "lucid", "lucid-updates", "notalucid": + comps = "main multiverse universe" + # unofficial source ends up without enablement + if uri == "http://example.com/" or suite == "notalucid": + comps = "main" + expected.append( + f"Types: {typ}\n" + f"URIs: {uri}\n" + f"Suites: {suite}\n" + f"Components: {comps}" + ) + + self.maxDiff = None + self.assertEqual(expected, list(map(str, sources.list))) + sources.save() + + expected = [ + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu\n" + "Suites: lucid lucid-updates\n" + "Components: main multiverse universe", + # unofficial suite + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu http://example.com/\n" + "Suites: notalucid\n" + "Components: main", + # unofficial mirror, FIXME: We'd rather merge the notalucid into here + "Types: deb deb-src\n" + "URIs: http://example.com/\n" + "Suites: lucid lucid-updates\n" + "Components: main", + ] + self.maxDiff = None + self.assertEqual(expected, list(map(str, sources.list))) + + def test_deb822_explode(self): + apt_pkg.config.set("Dir::Etc::sourcelist", "/dev/null") + target = ( + apt_pkg.config.find_dir("dir::etc::sourceparts") + "enable_comps.sources" + ) + line = "Types: deb\nURIs: http://archive.ubuntu.com/ubuntu\nSuites: lucid\nComponents: main\n" + with open(target, "w") as target_file: + target_file.write(line) + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 1) + self.assertIsInstance( + sources.exploded_list()[0], aptsources.sourceslist.Deb822SourceEntry + ) + + sources.list[0].suites += ["fakesuite"] + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 2) + self.assertIsInstance( + sources.exploded_list()[0], aptsources.sourceslist.ExplodedDeb822SourceEntry + ) + self.assertIsInstance( + sources.exploded_list()[1], aptsources.sourceslist.ExplodedDeb822SourceEntry + ) + self.assertEqual(sources.list[0].suites, ["lucid", "fakesuite"]) + sources.remove(sources.exploded_list()[1]) + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 1) + self.assertEqual(sources.list[0].suites, ["lucid"]) + + sources.list[0].types += ["deb-src"] + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 2) + self.assertIsInstance( + sources.exploded_list()[0], aptsources.sourceslist.ExplodedDeb822SourceEntry + ) + self.assertIsInstance( + sources.exploded_list()[1], aptsources.sourceslist.ExplodedDeb822SourceEntry + ) + self.assertEqual(sources.list[0].types, ["deb", "deb-src"]) + sources.remove(sources.exploded_list()[1]) + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 1) + self.assertEqual(sources.list[0].types, ["deb"]) + + sources.list[0].uris += ["http://example.com"] + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 2) + self.assertIsInstance( + sources.exploded_list()[0], aptsources.sourceslist.ExplodedDeb822SourceEntry + ) + self.assertIsInstance( + sources.exploded_list()[1], aptsources.sourceslist.ExplodedDeb822SourceEntry + ) + self.assertEqual( + sources.list[0].uris, + ["http://archive.ubuntu.com/ubuntu", "http://example.com"], + ) + sources.remove(sources.exploded_list()[1]) + self.assertEqual(len(sources.list), 1) + self.assertEqual(len(sources.exploded_list()), 1) + self.assertEqual(sources.list[0].uris, ["http://archive.ubuntu.com/ubuntu"]) + + # test setting attributes + sources.list[0].uris += ["http://example.com"] + with self.assertRaises(AttributeError): + sources.exploded_list()[0].types = ["does not work"] + with self.assertRaises(AttributeError): + sources.exploded_list()[0].uris = ["does not work"] + with self.assertRaises(AttributeError): + sources.exploded_list()[0].suites = ["does not work"] + with self.assertRaises(AttributeError): + sources.exploded_list()[0].doesnotexist = ["does not work"] + + # test overriding + sources.exploded_list()[0].type = "faketype" + self.assertEqual(sources.list[0].type, "faketype") + self.assertEqual(sources.list[1].type, "deb") + sources.exploded_list()[0].type = "deb" + self.assertEqual(sources.list[0].type, "deb") + self.assertEqual(sources.list[1].type, "deb") + sources.save() + self.assertEqual(len(sources.list), 1) + + def testDistribution_short(self): + """aptsources: Test distribution detection.""" + apt_pkg.config.set( + "Dir::Etc::sourcelist", "data/aptsources/" "sources.list.testDistribution" + ) + return self.commonTestDistribution() + + def testDistribution_deb822(self): + """aptsources: Test distribution detection.""" + apt_pkg.config.set( + "Dir::Etc::sourceparts", + "data/aptsources/" "sources.list.d.testDistribution", + ) + return self.commonTestDistribution() + + def commonTestDistribution(self): + """aptsources: Test distribution detection.""" + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + distro = aptsources.distro.get_distro( + id="Ubuntu", + codename="bionic", + description="Ubuntu 18.04 LTS", + release="18.04", + ) + distro.get_sources(sources) + # test if all suits of the current distro were detected correctly + dist_templates = set() + for s in sources: + if s.template: + dist_templates.add(s.template.name) + # print dist_templates + for d in ( + "hardy", + "hardy-security", + "hardy-updates", + "intrepid", + "hardy-backports", + ): + self.assertTrue(d in dist_templates) + # test enable + comp = "restricted" + distro.enable_component(comp) + found = {} + for entry in sources: + if ( + entry.type == "deb" + and entry.uri == "http://de.archive.ubuntu.com/ubuntu/" + and "edgy" in entry.dist + ): + for c in entry.comps: + if c == comp: + if entry.dist not in found: + found[entry.dist] = 0 + found[entry.dist] += 1 + # print "".join([s.str() for s in sources]) + for key in found: + self.assertEqual(found[key], 1) + + # add a not-already available component + comp = "multiverse" + distro.enable_component(comp) + found = {} + for entry in sources: + if entry.type == "deb" and entry.template and entry.template.name == "edgy": + for c in entry.comps: + if c == comp: + if entry.dist not in found.has_key: + found[entry.dist] = 0 + found[entry.dist] += 1 + # print "".join([s.str() for s in sources]) + for key in found: + self.assertEqual(found[key], 1) + + @unittest.skip("lsb-release test broken when it was added") + def test_os_release_distribution(self): + """os-release file can be read and is_like is populated accordingly""" + os.environ["LSB_ETC_LSB_RELEASE"] = os.path.abspath( + "./data/aptsources/lsb-release" + ) + aptsources.distro._OSRelease.OS_RELEASE_FILE = os.path.abspath( + "./data/aptsources/os-release" + ) + distro = aptsources.distro.get_distro() + # Everything but is_like comes from lsb_release, see TODO in + # get_distro. + self.assertEqual("Ubuntu", distro.id) + self.assertEqual("xenial", distro.codename) + self.assertEqual("Ubuntu 16.04.1 LTS", distro.description) + self.assertEqual("16.04", distro.release) + self.assertEqual(["ubuntu", "debian"], distro.is_like) + + def test_enable_disabled_short(self): + """LP: #1042916: Test enabling disabled entry.""" + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + return self.common_test_enable_disabled() + + def test_enable_disabled_deb822(self): + """LP: #1042916: Test enabling disabled entry.""" + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + return self.common_test_enable_disabled() + + def common_test_enable_disabled(self): + """LP: #1042916: Test enabling disabled entry.""" + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + disabled = sources.add( + "deb", + "http://fi.archive.ubuntu.com/ubuntu/", + "precise", + ["main"], + file=sources.list[0].file, # if we use deb822, enable deb822 + ) + disabled.set_enabled(False) + enabled = sources.add( + "deb", + "http://fi.archive.ubuntu.com/ubuntu/", + "precise", + ["main"], + file=sources.list[0].file, # if we use deb822, enable deb822 + ) + self.assertEqual(disabled, enabled) + self.assertFalse(disabled.disabled) + + def test_duplicate_uri_with_trailing_slash_short(self): + """Test replacing entry with same uri except trailing slash""" + apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/" "sources.list") + return self.common_test_duplicate_uri_with_trailing_slash() + + def test_duplicate_uri_with_trailing_slash_deb822(self): + """Test replacing entry with same uri except trailing slash""" + apt_pkg.config.set("Dir::Etc::sourceparts", "data/aptsources/" "sources.list.d") + return self.common_test_duplicate_uri_with_trailing_slash() + + def common_test_duplicate_uri_with_trailing_slash(self): + """Test replacing entry with same uri except trailing slash""" + sources = aptsources.sourceslist.SourcesList(True, self.templates, deb822=True) + line_wslash = "deb http://rslash.ubuntu.com/ubuntu/ precise main" + line_woslash = "deb http://rslash.ubuntu.com/ubuntu precise main" + entry_wslash = aptsources.sourceslist.SourceEntry(line_wslash) + entry_woslash = aptsources.sourceslist.SourceEntry(line_woslash) + self.assertEqual(entry_wslash, entry_woslash) + count = len(sources.list) + sourceslist_wslash = sources.add( + entry_wslash.type, entry_wslash.uri, entry_wslash.dist, entry_wslash.comps + ) + self.assertEqual(count + 1, len(sources.list)) + count = len(sources.list) + sourceslist_woslash = sources.add( + entry_woslash.type, + entry_woslash.uri, + entry_woslash.dist, + entry_woslash.comps, + ) + self.assertEqual(count, len(sources.list)) + self.assertEqual(sourceslist_wslash, sourceslist_woslash) + + def test_deb822_distro_enable_disable_component(self): + """Test enabling and disabling a component in the distro sources. + + This ensures reasonable behavior when enabling and then disabling a component""" + with tempfile.NamedTemporaryFile("w", suffix=".sources") as file: + file.write( + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + ) + file.flush() + + apt_pkg.config.set("Dir::Etc::sourcelist", file.name) + sources = aptsources.sourceslist.SourcesList( + True, self.templates, deb822=True + ) + distro = aptsources.distro.get_distro( + id="Ubuntu", + codename="noble", + description="Ubuntu 24.04 LTS", + release="24.04", + ) + + self.assertEqual(len(sources.list), 2) + distro.get_sources(sources) + distro.enable_component("multiverse") + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates\n" + "Components: main universe multiverse\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe multiverse\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + # Disable it again + # FIXME: The child entries will no longer be valid at this point, so we have to call + # get_sources(), but it's not clear whether this should be considered a bug - + # there may have been other changes rendering entries no longer valid that distro + # is holding on to. + distro.get_sources(sources) + distro.disable_component("multiverse") + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + # Disable universe as well + distro.get_sources(sources) + distro.disable_component("universe") + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates\n" + "Components: main\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + def test_deb822_distro_enable_disable_component_mixed_origin(self): + """Test enabling and disabling a component in the distro sources, with mixed origin + + Here we ensure that we still get idempotent behavior of disable after enable even if the + entry we were modifying also had a non-official repository in it.""" + with tempfile.NamedTemporaryFile("w", suffix=".sources") as file: + file.write( + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + ) + file.flush() + + apt_pkg.config.set("Dir::Etc::sourcelist", file.name) + sources = aptsources.sourceslist.SourcesList( + True, self.templates, deb822=True + ) + distro = aptsources.distro.get_distro( + id="Ubuntu", + codename="noble", + description="Ubuntu 24.04 LTS", + release="24.04", + ) + + self.assertEqual(len(sources.list), 2) + distro.get_sources(sources) + distro.enable_component("multiverse") + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates\n" + "Components: main universe multiverse\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe multiverse\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + # Disable it again + # FIXME: The child entries will no longer be valid at this point, so we have to call + # get_sources(), but it's not clear whether this should be considered a bug - + # there may have been other changes rendering entries no longer valid that distro + # is holding on to. + distro.get_sources(sources) + distro.disable_component("multiverse") + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + # Disable universe too. The behaviour here is interesting: Distro only disables + # universe for the official source, so we end up with the non-official source split out. + distro.get_sources(sources) + distro.disable_component("universe") + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates\n" + "Components: main\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# main archive\n" # note it keeps the comment on the split out child + "Types: deb deb-src\n" + "URIs: http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + def test_deb822_distro_enable_disable_child_source_mixed_origins(self): + """Test enabling and disabling a child source (proposed) in the distro sources, with mixed origin + + Here we ensure that we still get idempotent behavior of disable after enable even if the + entry we were modifying also had a non-official repository in it.""" + with tempfile.NamedTemporaryFile("w", suffix=".sources") as file: + file.write( + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + ) + file.flush() + + apt_pkg.config.set("Dir::Etc::sourcelist", file.name) + sources = aptsources.sourceslist.SourcesList( + True, self.templates, deb822=True + ) + distro = aptsources.distro.get_distro( + id="Ubuntu", + codename="noble", + description="Ubuntu 24.04 LTS", + release="24.04", + ) + + self.assertEqual(len(sources.list), 2) + distro.get_sources(sources) + distro.get_source_code = True + distro.add_source(dist="noble-proposed") + + # FIXME: Component ordering is not stable right now + for entry in sources.list: + entry.comps = sorted(entry.comps) + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + + # FIXME: In an optimal world it would look like this + self.assertNotEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates noble-proposed\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + with open(file.name) as readonly: + self.maxDiff = None + # Sadly our merge algorithm does not always produce optimal merges, because it merges the unofficial entry first + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble-proposed\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + # Disable it again + # FIXME: The child entries will no longer be valid at this point, so we have to call + # get_sources(), but it's not clear whether this should be considered a bug - + # there may have been other changes rendering entries no longer valid that distro + # is holding on to. + distro.get_sources(sources) + for child in distro.child_sources + distro.source_code_sources: + if child.dist.endswith("proposed"): + sources.remove(child) + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb deb-src\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb deb-src\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + def test_deb822_distro_enable_disable_child_source_mixed_origins_no_source_code( + self, + ): + """Test enabling and disabling a child source (proposed) in the distro sources, with mixed origin + + Here we ensure that we still get idempotent behavior of disable after enable even if the + entry we were modifying also had a non-official repository in it.""" + with tempfile.NamedTemporaryFile("w", suffix=".sources") as file: + file.write( + "# main archive\n" + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + ) + file.flush() + + apt_pkg.config.set("Dir::Etc::sourcelist", file.name) + sources = aptsources.sourceslist.SourcesList( + True, self.templates, deb822=True + ) + distro = aptsources.distro.get_distro( + id="Ubuntu", + codename="noble", + description="Ubuntu 24.04 LTS", + release="24.04", + ) + + self.assertEqual(len(sources.list), 2) + distro.get_sources(sources) + self.assertEqual( + [(s.type, s.uri, s.dist, s.comps) for s in distro.main_sources] + + ["separator"] + + [(s.type, s.uri, s.dist, s.comps) for s in distro.child_sources], + [ + ( + "deb", + "http://archive.ubuntu.com/ubuntu/", + "noble", + ["main", "universe"], + ), + "separator", + ( + "deb", + "http://archive.ubuntu.com/ubuntu/", + "noble-updates", + ["main", "universe"], + ), + ( + "deb", + "http://security.ubuntu.com/ubuntu/", + "noble-security", + ["main", "universe"], + ), + ], + ) + distro.add_source(dist="noble-proposed") + + # FIXME: Component ordering is not stable right now + for entry in sources.list: + entry.comps = sorted(entry.comps) + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + + # FIXME: In an optimal world it would look like this + self.assertNotEqual( + readonly.read(), + "# main archive\n" + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble noble-updates noble-proposed\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# main archive\n" + "Types: deb\n" + "URIs: http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + with open(file.name) as readonly: + self.maxDiff = None + # Sadly our merge algorithm does not always produce optimal merges, because it merges the unofficial entry first + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu/\n" + "Suites: noble-proposed\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + # Disable it again + # FIXME: The child entries will no longer be valid at this point, so we have to call + # get_sources(), but it's not clear whether this should be considered a bug - + # there may have been other changes rendering entries no longer valid that distro + # is holding on to. + distro.get_sources(sources) + for child in distro.child_sources + distro.source_code_sources: + if child.dist.endswith("proposed"): + sources.remove(child) + sources.save() + + with open(file.name) as readonly: + self.maxDiff = None + self.assertEqual( + readonly.read(), + "# main archive\n" + "Types: deb\n" + "URIs: http://archive.ubuntu.com/ubuntu/ http://unofficial.example.com/\n" + "Suites: noble noble-updates\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n" + "\n" + "# security\n" + "Types: deb\n" + "URIs: http://security.ubuntu.com/ubuntu/\n" + "Suites: noble-security\n" + "Components: main universe\n" + "Signed-By: /usr/share/keyrings/ubuntu-archive-keyrings.gpg\n", + ) + + +if __name__ == "__main__": + os.chdir(os.path.dirname(__file__)) + unittest.main() |