Added <command glob='...'> to support Debian multi-arch Java packages
[zeroinstall.git] / tests / testautopolicy.py
blobb637aca60559dc11b8987248182144795322a5d1
1 #!/usr/bin/env python
2 from basetest import BaseTest
3 import sys, tempfile, os, logging
4 from StringIO import StringIO
5 import unittest
7 sys.path.insert(0, '..')
9 from zeroinstall.injector import model, gpg, namespaces, reader, run, fetch
10 from zeroinstall.injector.policy import Policy
11 from zeroinstall.support import basedir
12 import data
14 foo_iface_uri = 'http://foo'
16 logger = logging.getLogger()
18 def recalculate(policy):
19 policy.need_download()
21 def download_and_execute(policy, prog_args, main = None, dry_run = True):
22 downloaded = policy.solve_and_download_impls()
23 if downloaded:
24 policy.config.handler.wait_for_blocker(downloaded)
25 run.execute_selections(policy.solver.selections, prog_args, stores = policy.config.stores, main = main, dry_run = dry_run)
27 class TestAutoPolicy(BaseTest):
28 def setUp(self):
29 BaseTest.setUp(self)
30 stream = tempfile.TemporaryFile()
31 stream.write(data.thomas_key)
32 stream.seek(0)
33 gpg.import_key(stream)
35 def cache_iface(self, name, data):
36 cached_ifaces = basedir.save_cache_path('0install.net',
37 'interfaces')
39 f = open(os.path.join(cached_ifaces, model.escape(name)), 'w')
40 f.write(data)
41 f.close()
43 def testNoNeedDl(self):
44 policy = Policy(foo_iface_uri, config = self.config)
45 policy.freshness = 0
46 assert policy.need_download()
48 policy = Policy(os.path.abspath('Foo.xml'), config = self.config)
49 assert not policy.need_download()
50 assert policy.ready
52 def testUnknownAlg(self):
53 self.cache_iface(foo_iface_uri,
54 """<?xml version="1.0" ?>
55 <interface
56 uri="%s"
57 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
58 <name>Foo</name>
59 <summary>Foo</summary>
60 <description>Foo</description>
61 <implementation main='.' id='unknown=123' version='1.0'>
62 <archive href='http://foo/foo.tgz' size='100'/>
63 </implementation>
64 </interface>""" % foo_iface_uri)
65 self.config.fetcher = fetch.Fetcher(self.config)
66 policy = Policy(foo_iface_uri, config = self.config)
67 policy.freshness = 0
68 try:
69 assert policy.need_download()
70 download_and_execute(policy, [])
71 except model.SafeException as ex:
72 assert 'Unknown digest algorithm' in str(ex)
74 def testDownload(self):
75 tmp = tempfile.NamedTemporaryFile()
76 tmp.write(
77 """<?xml version="1.0" ?>
78 <interface
79 main='ThisBetterNotExist'
80 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
81 <name>Foo</name>
82 <summary>Foo</summary>
83 <description>Foo</description>
84 <implementation version='1.0' id='/bin'/>
85 </interface>""")
86 tmp.flush()
87 policy = Policy(tmp.name, config = self.config)
88 try:
89 download_and_execute(policy, ['Hello'])
90 assert 0
91 except model.SafeException as ex:
92 assert "ThisBetterNotExist" in str(ex)
93 tmp.close()
95 def testNoMain(self):
96 tmp = tempfile.NamedTemporaryFile()
97 tmp.write(
98 """<?xml version="1.0" ?>
99 <interface
100 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
101 <name>Foo</name>
102 <summary>Foo</summary>
103 <description>Foo</description>
104 <implementation version='1.0' id='/bin'/>
105 </interface>""")
106 tmp.flush()
107 policy = Policy(tmp.name, config = self.config)
108 try:
109 download_and_execute(policy, ['Hello'])
110 assert 0
111 except model.SafeException as ex:
112 assert "library" in str(ex), ex
113 tmp.close()
115 def testNeedDL(self):
116 self.cache_iface(foo_iface_uri,
117 """<?xml version="1.0" ?>
118 <interface last-modified="0"
119 uri="%s"
120 main='ThisBetterNotExist'
121 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
122 <name>Foo</name>
123 <summary>Foo</summary>
124 <description>Foo</description>
125 <implementation version='1.0' id='sha1=123'>
126 <archive href='http://foo/foo.tgz' size='100'/>
127 </implementation>
128 </interface>""" % foo_iface_uri)
129 policy = Policy(foo_iface_uri, config = self.config)
130 policy.freshness = 0
131 policy.network_use = model.network_full
132 recalculate(policy)
133 assert policy.need_download()
134 assert policy.ready
136 def testBinding(self):
137 local_impl = os.path.dirname(os.path.abspath(__file__))
138 tmp = tempfile.NamedTemporaryFile()
139 tmp.write(
140 """<?xml version="1.0" ?>
141 <interface
142 main='testautopolicy.py'
143 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
144 <name>Bar</name>
145 <summary>Bar</summary>
146 <description>Bar</description>
147 <group>
148 <requires interface='%s'>
149 <environment name='FOO_PATH' insert='.'/>
150 <environment name='BAR_PATH' insert='.' default='/a:/b'/>
151 <environment name='NO_PATH' value='val'/>
152 <environment name='XDG_DATA_DIRS' insert='.'/>
153 </requires>
154 <environment name='SELF_GROUP' insert='group' mode='replace'/>
155 <implementation version='1.0' id='%s'>
156 <environment name='SELF_IMPL' insert='impl' mode='replace'/>
157 </implementation>
158 </group>
159 </interface>""" % (foo_iface_uri, local_impl))
160 tmp.flush()
161 self.cache_iface(foo_iface_uri,
162 """<?xml version="1.0" ?>
163 <interface last-modified="0"
164 uri="%s"
165 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
166 <name>Foo</name>
167 <summary>Foo</summary>
168 <description>Foo</description>
169 <implementation version='1.0' id='sha1=123'/>
170 </interface>""" % foo_iface_uri)
171 cached_impl = basedir.save_cache_path('0install.net',
172 'implementations',
173 'sha1=123')
174 policy = Policy(tmp.name, config = self.config)
175 policy.network_use = model.network_offline
176 os.environ['FOO_PATH'] = "old"
177 old, sys.stdout = sys.stdout, StringIO()
178 try:
179 download_and_execute(policy, ['Hello'])
180 finally:
181 sys.stdout = old
182 self.assertEqual(cached_impl + '/.:old',
183 os.environ['FOO_PATH'])
184 self.assertEqual(cached_impl + '/.:/a:/b',
185 os.environ['BAR_PATH'])
186 self.assertEqual('val', os.environ['NO_PATH'])
188 self.assertEqual(os.path.join(local_impl, 'group'), os.environ['SELF_GROUP'])
189 self.assertEqual(os.path.join(local_impl, 'impl'), os.environ['SELF_IMPL'])
191 del os.environ['FOO_PATH']
192 if 'XDG_DATA_DIRS' in os.environ:
193 del os.environ['XDG_DATA_DIRS']
194 os.environ['BAR_PATH'] = '/old'
195 old, sys.stdout = sys.stdout, StringIO()
196 try:
197 download_and_execute(policy, ['Hello'])
198 finally:
199 sys.stdout = old
200 self.assertEqual(cached_impl + '/.',
201 os.environ['FOO_PATH'])
202 self.assertEqual(cached_impl + '/.:/old',
203 os.environ['BAR_PATH'])
204 self.assertEqual(cached_impl + '/.:/usr/local/share:/usr/share',
205 os.environ['XDG_DATA_DIRS'])
207 def testFeeds(self):
208 self.cache_iface(foo_iface_uri,
209 """<?xml version="1.0" ?>
210 <interface last-modified="0"
211 uri="%s"
212 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
213 <name>Foo</name>
214 <summary>Foo</summary>
215 <description>Foo</description>
216 <feed src='http://bar'/>
217 </interface>""" % foo_iface_uri)
218 self.cache_iface('http://bar',
219 """<?xml version="1.0" ?>
220 <interface last-modified="0"
221 uri="http://bar"
222 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
223 <feed-for interface='%s'/>
224 <name>Bar</name>
225 <summary>Bar</summary>
226 <description>Bar</description>
227 <implementation version='1.0' id='sha1=123' main='dummy'>
228 <archive href='foo' size='10'/>
229 </implementation>
230 </interface>""" % foo_iface_uri)
231 policy = Policy(foo_iface_uri, config = self.config)
232 policy.freshness = 0
233 policy.network_use = model.network_full
234 recalculate(policy)
235 assert policy.ready
236 foo_iface = self.config.iface_cache.get_interface(foo_iface_uri)
237 self.assertEqual('sha1=123', policy.implementation[foo_iface].id)
239 def testBadConfig(self):
240 path = basedir.save_config_path(namespaces.config_site,
241 namespaces.config_prog)
242 glob = os.path.join(path, 'global')
243 assert not os.path.exists(glob)
244 stream = open(glob, 'w')
245 stream.write('hello!')
246 stream.close()
248 logger.setLevel(logging.ERROR)
249 Policy(foo_iface_uri, config = self.config)
250 logger.setLevel(logging.WARN)
252 def testNoLocal(self):
253 self.cache_iface(foo_iface_uri,
254 """<?xml version="1.0" ?>
255 <interface last-modified="1110752708"
256 uri="%s"
257 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
258 <name>Foo</name>
259 <summary>Foo</summary>
260 <description>Foo</description>
261 <feed src='/etc/passwd'/>
262 </interface>""" % foo_iface_uri)
263 self.config.network_use = model.network_offline
264 try:
265 self.config.iface_cache.get_interface(foo_iface_uri)
266 assert False
267 except reader.InvalidInterface as ex:
268 assert 'Invalid feed URL' in str(ex)
270 def testDLfeed(self):
271 self.cache_iface(foo_iface_uri,
272 """<?xml version="1.0" ?>
273 <interface last-modified="1110752708"
274 uri="%s"
275 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
276 <name>Foo</name>
277 <summary>Foo</summary>
278 <description>Foo</description>
279 <feed src='http://example.com'/>
280 </interface>""" % foo_iface_uri)
281 policy = Policy(foo_iface_uri, config = self.config)
282 policy.network_use = model.network_full
283 policy.freshness = 0
285 assert policy.need_download()
287 feed = self.config.iface_cache.get_feed(foo_iface_uri)
288 feed.feeds = [model.Feed('/BadFeed', None, False)]
290 logger.setLevel(logging.ERROR)
291 assert policy.need_download() # Triggers warning
292 logger.setLevel(logging.WARN)
294 def testBestUnusable(self):
295 self.cache_iface(foo_iface_uri,
296 """<?xml version="1.0" ?>
297 <interface last-modified="1110752708"
298 uri="%s"
299 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
300 <name>Foo</name>
301 <summary>Foo</summary>
302 <description>Foo</description>
303 <implementation id='sha1=123' version='1.0' arch='odd-weird' main='dummy'/>
304 </interface>""" % foo_iface_uri)
305 policy = Policy(foo_iface_uri, config = self.config)
306 policy.network_use = model.network_offline
307 recalculate(policy)
308 assert not policy.ready, policy.implementation
309 try:
310 download_and_execute(policy, [])
311 assert False
312 except model.SafeException as ex:
313 assert "has no usable implementations" in str(ex), ex
315 def testNoArchives(self):
316 self.cache_iface(foo_iface_uri,
317 """<?xml version="1.0" ?>
318 <interface last-modified="1110752708"
319 uri="%s"
320 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
321 <name>Foo</name>
322 <summary>Foo</summary>
323 <description>Foo</description>
324 <implementation id='sha1=123' version='1.0' main='dummy'/>
325 </interface>""" % foo_iface_uri)
326 policy = Policy(foo_iface_uri, config = self.config)
327 policy.freshness = 0
328 recalculate(policy)
329 assert not policy.ready
331 def testCycle(self):
332 self.cache_iface(foo_iface_uri,
333 """<?xml version="1.0" ?>
334 <interface last-modified="1110752708"
335 uri="%s"
336 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
337 <name>Foo</name>
338 <summary>Foo</summary>
339 <description>Foo</description>
340 <group>
341 <requires interface='%s'/>
342 <implementation id='sha1=123' version='1.0'>
343 <archive href='foo' size='10'/>
344 </implementation>
345 </group>
346 </interface>""" % (foo_iface_uri, foo_iface_uri))
347 policy = Policy(foo_iface_uri, config = self.config)
348 policy.freshness = 0
349 recalculate(policy)
351 def testConstraints(self):
352 self.cache_iface('http://bar',
353 """<?xml version="1.0" ?>
354 <interface last-modified="1110752708"
355 uri="http://bar"
356 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
357 <name>Bar</name>
358 <summary>Bar</summary>
359 <description>Bar</description>
360 <implementation id='sha1=100' version='1.0'>
361 <archive href='foo' size='10'/>
362 </implementation>
363 <implementation id='sha1=150' stability='developer' version='1.5'>
364 <archive href='foo' size='10'/>
365 </implementation>
366 <implementation id='sha1=200' version='2.0'>
367 <archive href='foo' size='10'/>
368 </implementation>
369 </interface>""")
370 self.cache_iface(foo_iface_uri,
371 """<?xml version="1.0" ?>
372 <interface last-modified="1110752708"
373 uri="%s"
374 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
375 <name>Foo</name>
376 <summary>Foo</summary>
377 <description>Foo</description>
378 <group main='dummy'>
379 <requires interface='http://bar'>
380 <version/>
381 </requires>
382 <implementation id='sha1=123' version='1.0'>
383 <archive href='foo' size='10'/>
384 </implementation>
385 </group>
386 </interface>""" % foo_iface_uri)
387 policy = Policy(foo_iface_uri, config = self.config)
388 policy.network_use = model.network_full
389 policy.freshness = 0
390 #logger.setLevel(logging.DEBUG)
391 recalculate(policy)
392 #logger.setLevel(logging.WARN)
393 foo_iface = self.config.iface_cache.get_interface(foo_iface_uri)
394 bar_iface = self.config.iface_cache.get_interface('http://bar')
395 assert policy.implementation[bar_iface].id == 'sha1=200'
397 dep = policy.implementation[foo_iface].dependencies['http://bar']
398 assert len(dep.restrictions) == 1
399 restriction = dep.restrictions[0]
401 restriction.before = model.parse_version('2.0')
402 recalculate(policy)
403 assert policy.implementation[bar_iface].id == 'sha1=100'
405 restriction.not_before = model.parse_version('1.5')
406 recalculate(policy)
407 assert policy.implementation[bar_iface].id == 'sha1=150'
409 if __name__ == '__main__':
410 unittest.main()