Fixed handling of ~ in Debian versions
[zeroinstall.git] / tests / testdistro.py
blob751757c17e3de941994ff22eb878630a820ebd4b
1 #!/usr/bin/env python
2 from basetest import BaseTest, empty_feed, DummyPackageKit
3 import sys, os, tempfile, imp
4 from io import BytesIO
5 import unittest
7 sys.path.insert(0, '..')
8 from zeroinstall.injector import distro, model, qdom, iface_cache, handler
9 from zeroinstall.support import basedir, windows_args_escape
11 def parse_impls(impls):
12 xml = """<?xml version="1.0" ?>
13 <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
14 <name>Foo</name>
15 <summary>Foo</summary>
16 <description>Foo</description>
17 {impls}
18 </interface>""".format(impls = impls)
19 element = qdom.parse(BytesIO(xml.encode('utf-8')))
20 return model.ZeroInstallFeed(element, "myfeed.xml")
22 class TestDistro(BaseTest):
23 def setUp(self):
24 BaseTest.setUp(self)
25 self.feed = model.ZeroInstallFeed(empty_feed, local_path = '/empty.xml')
27 def tearDown(self):
28 BaseTest.tearDown(self)
30 def testCache(self):
31 src = tempfile.NamedTemporaryFile(mode = 'wt')
32 try:
33 cache = distro.Cache('test-cache', src.name, 1)
34 self.assertEqual(None, cache.get("foo"))
35 cache.put("foo", "1")
36 self.assertEqual("1", cache.get("foo"))
37 cache.put("foo", "2")
38 self.assertEqual("2", cache.get("foo"))
40 # new cache...
41 cache = distro.Cache('test-cache', src.name, 1)
42 self.assertEqual("2", cache.get("foo"))
44 src.write("hi")
45 src.flush()
47 self.assertEqual(None, cache.get("foo"))
48 cache.put("foo", "3")
50 # new cache... (format change)
51 cache = distro.Cache('test-cache', src.name, 2)
52 self.assertEqual(None, cache.get("foo"))
54 finally:
55 src.close()
57 def make_factory(self, distro):
58 def factory(id, only_if_missing = False, installed = True):
59 assert not only_if_missing
60 impl = model.DistributionImplementation(self.feed, id, distro)
61 assert id not in self.feed.implementations
62 self.feed.implementations[id] = impl
63 impl.installed = installed
64 return impl
65 return factory
67 def testDefault(self):
68 host = distro.Distribution()
70 factory = self.make_factory(host)
71 host.get_package_info('gimp', factory)
72 self.assertEqual(self.feed.implementations, {})
74 # Special case: we can always find a version of Python
75 master_feed = model.ZeroInstallFeed(None)
76 master_feed.url = 'http://repo.roscidus.com/python/python'
77 feed = host.get_feed(master_feed)
78 self.assertEqual(1, len(feed.implementations))
80 def testDebian(self):
81 dpkgdir = os.path.join(os.path.dirname(__file__), 'dpkg')
82 host = distro.DebianDistribution(
83 os.path.join(dpkgdir, 'status'))
84 host._packagekit = DummyPackageKit()
86 factory = self.make_factory(host)
87 host.get_package_info('gimp', factory)
88 self.assertEqual({}, self.feed.implementations)
90 # Initially, we only get information about the installed version...
91 host.get_package_info('python-bittorrent', factory)
92 self.assertEqual(1, len(self.feed.implementations))
94 # Tell distro to fetch information about candidates...
95 master_feed = parse_impls("""<package-implementation package='python-bittorrent'/>""")
96 h = handler.Handler()
97 candidates = host.fetch_candidates(master_feed)
98 if candidates:
99 h.wait_for_blocker(candidates)
100 # Now we see the uninstalled package
101 self.feed = model.ZeroInstallFeed(empty_feed, local_path = '/empty.xml')
102 host.get_package_info('python-bittorrent', factory)
103 self.assertEqual(2, len(self.feed.implementations))
105 self.assertEqual(2, len(self.feed.implementations))
106 bittorrent_installed = self.feed.implementations['package:deb:python-bittorrent:3.4.2-10:*']
107 bittorrent_uninstalled = self.feed.implementations['package:deb:python-bittorrent:3.4.2-11.1:*']
108 self.assertEqual('3.4.2-10', bittorrent_installed.get_version())
109 self.assertTrue(bittorrent_installed.installed)
110 self.assertFalse(bittorrent_uninstalled.installed)
111 self.assertEqual(None, bittorrent_installed.machine)
113 self.feed = model.ZeroInstallFeed(empty_feed, local_path = '/empty.xml')
114 host.get_package_info('libxcomposite-dev', factory)
115 self.assertEqual(1, len(self.feed.implementations))
116 libxcomposite = self.feed.implementations['package:deb:libxcomposite-dev:0.3.1-1:i386']
117 self.assertEqual('0.3.1-1', libxcomposite.get_version())
118 self.assertEqual('i386', libxcomposite.machine)
120 # Java is special...
121 master_feed = parse_impls("""<package-implementation package='openjdk-7-jre'/>""")
122 feed = host.get_feed(master_feed)
123 self.assertEqual(1, len(feed.implementations))
124 self.assertEqual('7.3-2.1.1-3', list(feed.implementations.values())[0].get_version())
126 def testRPM(self):
127 rpmdir = os.path.join(os.path.dirname(__file__), 'rpm')
128 os.environ['PATH'] = rpmdir + ':' + self.old_path
129 rpm = distro.RPMDistribution(os.path.join(rpmdir, 'status'))
131 self.assertEqual(2, len(rpm.versions))
133 factory = self.make_factory(rpm)
134 rpm.get_package_info('yast2-update', factory)
135 self.assertEqual(1, len(self.feed.implementations))
136 yast = self.feed.implementations['package:rpm:yast2-update:2.15.23-21:i586']
137 self.assertEqual('2.15.23-21', yast.get_version())
138 self.assertEqual('*-i586', yast.arch)
140 icache = iface_cache.IfaceCache(distro = rpm)
142 feed = parse_impls("""
143 <package-implementation distributions="Debian" package="yast2-mail"/>
144 <package-implementation distributions="RPM" package="yast2-update"/>
145 """)
146 icache._feeds[feed.url] = feed
147 distro_feed_url = feed.get_distro_feed()
148 impls = icache.get_feed(distro_feed_url).implementations
149 self.assertEqual("distribution:myfeed.xml", distro_feed_url)
150 assert len(impls) == 1, impls
151 impl, = impls
152 assert impl == 'package:rpm:yast2-update:2.15.23-21:i586'
154 feed = parse_impls("""
155 <package-implementation distributions="RPM" package="yast2-mail"/>
156 <package-implementation distributions="RPM" package="yast2-update"/>
157 """)
158 icache._feeds[feed.url] = feed
159 del icache._feeds['distribution:' + feed.url]
160 impls = icache.get_feed(feed.get_distro_feed()).implementations
161 assert len(impls) == 2, impls
163 feed = parse_impls("""
164 <package-implementation distributions="" package="yast2-mail"/>
165 <package-implementation package="yast2-update"/>
166 """)
167 icache._feeds[feed.url] = feed
168 del icache._feeds['distribution:' + feed.url]
169 impls = icache.get_feed(feed.get_distro_feed()).implementations
170 assert len(impls) == 2, impls
172 feed = parse_impls("""
173 <package-implementation distributions="Foo Bar Baz" package="yast2-mail"/>
174 """)
175 icache._feeds[feed.url] = feed
176 del icache._feeds['distribution:' + feed.url]
177 impls = icache.get_feed(feed.get_distro_feed()).implementations
178 assert len(impls) == 1, impls
180 def testSlack(self):
181 slackdir = os.path.join(os.path.dirname(__file__), 'slack')
182 slack = distro.SlackDistribution(os.path.join(slackdir, 'packages'))
184 factory = self.make_factory(slack)
185 slack.get_package_info('gimp', factory)
186 self.assertEqual({}, self.feed.implementations)
188 slack.get_package_info('infozip', factory)
189 self.assertEqual(1, len(self.feed.implementations))
190 zip = self.feed.implementations['package:slack:infozip:5.52-2:i486']
191 self.assertEqual('5.52-2', zip.get_version())
192 self.assertEqual('i486', zip.machine)
194 def testArch(self):
195 archdir = os.path.join(os.path.dirname(__file__), 'arch')
196 arch = distro.ArchDistribution(archdir)
198 factory = self.make_factory(arch)
199 arch.get_package_info('gimp', factory)
200 self.assertEqual({}, self.feed.implementations)
202 arch.get_package_info('zeroinstall-injector', factory)
203 self.assertEqual(1, len(self.feed.implementations))
204 zip = self.feed.implementations['package:arch:zeroinstall-injector:1.5-1:*']
205 self.assertEqual('1.5-1', zip.get_version())
207 def testGentoo(self):
208 pkgdir = os.path.join(os.path.dirname(__file__), 'gentoo')
209 ebuilds = distro.GentooDistribution(pkgdir)
211 factory = self.make_factory(ebuilds)
212 ebuilds.get_package_info('media-gfx/gimp', factory)
213 self.assertEqual({}, self.feed.implementations)
215 ebuilds.get_package_info('sys-apps/portage', factory)
216 self.assertEqual(1, len(self.feed.implementations))
217 impl = self.feed.implementations['package:gentoo:sys-apps/portage:2.1.7.16:x86_64']
218 self.assertEqual('2.1.7.16', impl.get_version())
219 self.assertEqual('x86_64', impl.machine)
221 ebuilds.get_package_info('sys-kernel/gentoo-sources', factory)
222 self.assertEqual(3, len(self.feed.implementations))
223 impl = self.feed.implementations['package:gentoo:sys-kernel/gentoo-sources:2.6.30-4:i686']
224 self.assertEqual('2.6.30-4', impl.get_version())
225 self.assertEqual('i686', impl.machine)
226 impl = self.feed.implementations['package:gentoo:sys-kernel/gentoo-sources:2.6.32:x86_64']
227 self.assertEqual('2.6.32', impl.get_version())
228 self.assertEqual('x86_64', impl.machine)
230 ebuilds.get_package_info('app-emulation/emul-linux-x86-baselibs', factory)
231 self.assertEqual(4, len(self.feed.implementations))
232 impl = self.feed.implementations['package:gentoo:app-emulation/emul-linux-x86-baselibs:20100220:i386']
233 self.assertEqual('20100220', impl.get_version())
234 self.assertEqual('i386', impl.machine)
236 def testPorts(self):
237 pkgdir = os.path.join(os.path.dirname(__file__), 'ports')
238 ports = distro.PortsDistribution(pkgdir)
240 factory = self.make_factory(ports)
241 ports.get_package_info('zeroinstall-injector', factory)
242 self.assertEqual(1, len(self.feed.implementations))
243 impl = self.feed.implementations['package:ports:zeroinstall-injector:0.41-2:' + distro.host_machine]
244 self.assertEqual('0.41-2', impl.get_version())
245 self.assertEqual(distro.host_machine, impl.machine)
247 def testMacPorts(self):
248 pkgdir = os.path.join(os.path.dirname(__file__), 'macports')
249 os.environ['PATH'] = pkgdir + ':' + self.old_path
250 ports = distro.MacPortsDistribution(os.path.join(pkgdir, 'registry.db'))
252 factory = self.make_factory(ports)
253 ports.get_package_info('zeroinstall-injector', factory)
254 self.assertEqual(1, len(self.feed.implementations))
255 impl = self.feed.implementations['package:macports:zeroinstall-injector:1.0-0:*']
256 self.assertEqual('1.0-0', impl.get_version())
257 self.assertEqual(None, impl.machine)
259 def testCleanVersion(self):
260 self.assertEqual('0.3.1-1', distro.try_cleanup_distro_version('1:0.3.1-1'))
261 self.assertEqual('0.3.1-1', distro.try_cleanup_distro_version('0.3.1-1ubuntu0'))
262 self.assertEqual('0.3-post1-rc2', distro.try_cleanup_distro_version('0.3-post1-rc2'))
263 self.assertEqual('0.3.1-2', distro.try_cleanup_distro_version('0.3.1-r2-r3'))
264 self.assertEqual('6.17', distro.try_cleanup_distro_version('6b17'))
265 self.assertEqual('20-1', distro.try_cleanup_distro_version('b20_1'))
266 self.assertEqual('17', distro.try_cleanup_distro_version('p17'))
267 self.assertEqual('7-pre3-2.1.1-3', distro.try_cleanup_distro_version('7~u3-2.1.1-3')) # Debian snapshot
268 self.assertEqual('7-pre3-2.1.1-pre1-1', distro.try_cleanup_distro_version('7~u3-2.1.1~pre1-1ubuntu2'))
269 self.assertEqual(None, distro.try_cleanup_distro_version('cvs'))
271 def testCommand(self):
272 dpkgdir = os.path.join(os.path.dirname(__file__), 'dpkg')
273 host = distro.DebianDistribution(
274 os.path.join(dpkgdir, 'status'))
275 host._packagekit = DummyPackageKit()
277 master_feed = parse_impls("""<package-implementation main='/unused' package='python-bittorrent'><command path='/bin/sh' name='run'/></package-implementation>""")
278 icache = iface_cache.IfaceCache(distro = host)
279 icache._feeds[master_feed.url] = master_feed
280 #del icache._feeds['distribution:' + master_feed.url]
281 impl, = icache.get_feed(master_feed.get_distro_feed()).implementations.values()
282 self.assertEqual('/bin/sh', impl.main)
284 def testPortable(self):
285 # Overrides all XDG_* variables
286 os.environ['ZEROINSTALL_PORTABLE_BASE'] = '/portable'
287 imp.reload(basedir)
288 self.assertEqual('/portable/config', basedir.xdg_config_home)
289 self.assertEqual('/portable/cache', basedir.xdg_cache_home)
290 self.assertEqual('/portable/data', basedir.xdg_data_home)
292 self.assertEqual(['/portable/config'], basedir.xdg_config_dirs)
293 self.assertEqual(['/portable/cache'], basedir.xdg_cache_dirs)
294 self.assertEqual(['/portable/data'], basedir.xdg_data_dirs)
296 del os.environ['ZEROINSTALL_PORTABLE_BASE']
297 os.environ['XDG_CONFIG_HOME'] = '/home/me/config'
298 os.environ['XDG_CONFIG_DIRS'] = '/system/config'
300 os.environ['XDG_DATA_HOME'] = '/home/me/data'
301 os.environ['XDG_DATA_DIRS'] = '/system/data' + os.pathsep + '/disto/data'
303 os.environ['XDG_CACHE_HOME'] = '/home/me/cache'
304 os.environ['XDG_CACHE_DIRS'] = '/system/cache'
305 imp.reload(basedir)
307 self.assertEqual('/home/me/config', basedir.xdg_config_home)
308 self.assertEqual('/home/me/cache', basedir.xdg_cache_home)
309 self.assertEqual('/home/me/data', basedir.xdg_data_home)
311 self.assertEqual(['/home/me/config', '/system/config'], basedir.xdg_config_dirs)
312 self.assertEqual(['/home/me/cache', '/system/cache'], basedir.xdg_cache_dirs)
313 self.assertEqual(['/home/me/data', '/system/data', '/disto/data'], basedir.xdg_data_dirs)
315 def testWindowsSupport(self):
316 self.assertEqual("foo bar", windows_args_escape(["foo", "bar"]))
317 self.assertEqual('"foo bar"', windows_args_escape(["foo bar"]))
318 self.assertEqual(r'"foo \"bar\""', windows_args_escape(['foo "bar"']))
319 self.assertEqual(r'"foo \\\"bar\""', windows_args_escape(['foo \\"bar"']))
321 if __name__ == '__main__':
322 unittest.main()