When using --list, sort the results.
[zeroinstall.git] / tests / testautopolicy.py
blob88f2e3907c83b6aa4e96475d47a623cb019f0d23
1 #!/usr/bin/env python2.3
2 import sys, tempfile, os, shutil, logging
3 from StringIO import StringIO
4 import unittest
5 from logging import getLogger, DEBUG, INFO
7 sys.path.insert(0, '..')
9 config_home = tempfile.mktemp()
10 cache_home = tempfile.mktemp()
11 os.environ['XDG_CONFIG_HOME'] = config_home
12 os.environ['XDG_CACHE_HOME'] = cache_home
13 os.environ['XDG_CACHE_DIRS'] = ''
15 from zeroinstall import NeedDownload
16 from zeroinstall.injector import model, basedir, autopolicy, gpg, iface_cache, namespaces, reader
17 import data
18 reload(basedir)
20 foo_iface_uri = 'http://foo'
22 logger = logging.getLogger()
24 class TestAutoPolicy(unittest.TestCase):
25 def setUp(self):
26 os.mkdir(config_home, 0700)
27 os.mkdir(cache_home, 0700)
28 if os.environ.has_key('DISPLAY'):
29 del os.environ['DISPLAY']
30 self.gnupg_home = tempfile.mktemp()
31 os.environ['GNUPGHOME'] = self.gnupg_home
32 os.mkdir(self.gnupg_home, 0700)
33 stream = tempfile.TemporaryFile()
34 stream.write(data.thomas_key)
35 stream.seek(0)
36 gpg.import_key(stream)
37 iface_cache.iface_cache._interfaces = {}
39 def tearDown(self):
40 shutil.rmtree(config_home)
41 shutil.rmtree(cache_home)
42 shutil.rmtree(self.gnupg_home)
44 def cache_iface(self, name, data):
45 cached_ifaces = basedir.save_cache_path('0install.net',
46 'interfaces')
48 f = file(os.path.join(cached_ifaces, model.escape(name)), 'w')
49 f.write(data)
50 f.close()
52 def testNoNeedDl(self):
53 policy = autopolicy.AutoPolicy(foo_iface_uri,
54 download_only = False)
55 policy.freshness = 0
56 assert policy.need_download()
57 self.cache_iface(foo_iface_uri,
58 """<?xml version="1.0" ?>
59 <interface last-modified="1110752708"
60 uri="%s"
61 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
62 <name>Foo</name>
63 <summary>Foo</summary>
64 <description>Foo</description>
65 </interface>""" % foo_iface_uri)
66 iface_cache.iface_cache._interfaces = {}
67 assert not policy.need_download()
69 def testUnknownAlg(self):
70 self.cache_iface(foo_iface_uri,
71 """<?xml version="1.0" ?>
72 <interface
73 uri="%s"
74 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
75 <name>Foo</name>
76 <summary>Foo</summary>
77 <description>Foo</description>
78 <implementation id='unknown=123' version='1.0'>
79 <archive href='http://foo/foo.tgz' size='100'/>
80 </implementation>
81 </interface>""" % foo_iface_uri)
82 policy = autopolicy.AutoPolicy(foo_iface_uri,
83 download_only = False)
84 policy.freshness = 0
85 try:
86 assert policy.need_download()
87 assert False
88 except model.SafeException, ex:
89 assert 'Unknown digest algorithm' in str(ex)
91 def testDownload(self):
92 tmp = tempfile.NamedTemporaryFile()
93 tmp.write(
94 """<?xml version="1.0" ?>
95 <interface
96 main='ThisBetterNotExist'
97 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
98 <name>Foo</name>
99 <summary>Foo</summary>
100 <description>Foo</description>
101 <implementation version='1.0' id='/bin'/>
102 </interface>""")
103 tmp.flush()
104 policy = autopolicy.AutoPolicy(tmp.name, False, False)
105 try:
106 policy.download_and_execute(['Hello'])
107 assert 0
108 except model.SafeException, ex:
109 assert "ThisBetterNotExist" in str(ex)
110 tmp.close()
112 def testNoMain(self):
113 tmp = tempfile.NamedTemporaryFile()
114 tmp.write(
115 """<?xml version="1.0" ?>
116 <interface
117 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
118 <name>Foo</name>
119 <summary>Foo</summary>
120 <description>Foo</description>
121 <implementation version='1.0' id='/bin'/>
122 </interface>""")
123 tmp.flush()
124 policy = autopolicy.AutoPolicy(tmp.name, False, False)
125 try:
126 policy.download_and_execute(['Hello'])
127 assert 0
128 except model.SafeException, ex:
129 assert "library" in str(ex)
130 tmp.close()
132 def testNeedDL(self):
133 self.cache_iface(foo_iface_uri,
134 """<?xml version="1.0" ?>
135 <interface last-modified="0"
136 uri="%s"
137 main='ThisBetterNotExist'
138 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
139 <name>Foo</name>
140 <summary>Foo</summary>
141 <description>Foo</description>
142 <implementation version='1.0' id='sha1=123'>
143 <archive href='http://foo/foo.tgz' size='100'/>
144 </implementation>
145 </interface>""" % foo_iface_uri)
146 policy = autopolicy.AutoPolicy(foo_iface_uri, False, True)
147 policy.freshness = 0
148 policy.network_use = model.network_full
149 policy.recalculate()
150 assert policy.need_download()
151 try:
152 policy.start_downloading_impls()
153 assert False
154 except NeedDownload, ex:
155 pass
157 def testBinding(self):
158 tmp = tempfile.NamedTemporaryFile()
159 tmp.write(
160 """<?xml version="1.0" ?>
161 <interface
162 main='testautopolicy.py'
163 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
164 <name>Bar</name>
165 <summary>Bar</summary>
166 <description>Bar</description>
167 <group>
168 <requires interface='%s'>
169 <environment name='FOO_PATH' insert='.'/>
170 <environment name='BAR_PATH' insert='.' default='/a:/b'/>
171 <environment name='XDG_DATA_DIRS' insert='.'/>
172 </requires>
173 <implementation version='1.0' id='%s'/>
174 </group>
175 </interface>""" % (foo_iface_uri, os.path.dirname(os.path.abspath(__file__))))
176 tmp.flush()
177 self.cache_iface(foo_iface_uri,
178 """<?xml version="1.0" ?>
179 <interface last-modified="0"
180 uri="%s"
181 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
182 <name>Foo</name>
183 <summary>Foo</summary>
184 <description>Foo</description>
185 <implementation version='1.0' id='sha1=123'/>
186 </interface>""" % foo_iface_uri)
187 cached_impl = basedir.save_cache_path('0install.net',
188 'implementations',
189 'sha1=123')
190 policy = autopolicy.AutoPolicy(tmp.name, False,
191 dry_run = True)
192 policy.network_use = model.network_offline
193 os.environ['FOO_PATH'] = "old"
194 old, sys.stdout = sys.stdout, StringIO()
195 try:
196 policy.download_and_execute(['Hello'])
197 finally:
198 sys.stdout = old
199 self.assertEquals(cached_impl + '/.:old',
200 os.environ['FOO_PATH'])
201 self.assertEquals(cached_impl + '/.:/a:/b',
202 os.environ['BAR_PATH'])
204 del os.environ['FOO_PATH']
205 if 'XDG_DATA_DIRS' in os.environ:
206 del os.environ['XDG_DATA_DIRS']
207 os.environ['BAR_PATH'] = '/old'
208 old, sys.stdout = sys.stdout, StringIO()
209 try:
210 policy.download_and_execute(['Hello'])
211 finally:
212 sys.stdout = old
213 self.assertEquals(cached_impl + '/.',
214 os.environ['FOO_PATH'])
215 self.assertEquals(cached_impl + '/.:/old',
216 os.environ['BAR_PATH'])
217 self.assertEquals(cached_impl + '/.:/usr/local/share:/usr/share',
218 os.environ['XDG_DATA_DIRS'])
220 def testFeeds(self):
221 self.cache_iface(foo_iface_uri,
222 """<?xml version="1.0" ?>
223 <interface last-modified="0"
224 uri="%s"
225 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
226 <name>Foo</name>
227 <summary>Foo</summary>
228 <description>Foo</description>
229 <feed src='http://bar'/>
230 </interface>""" % foo_iface_uri)
231 self.cache_iface('http://bar',
232 """<?xml version="1.0" ?>
233 <interface last-modified="0"
234 uri="http://bar"
235 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
236 <feed-for interface='%s'/>
237 <name>Bar</name>
238 <summary>Bar</summary>
239 <description>Bar</description>
240 <implementation version='1.0' id='sha1=123'/>
241 </interface>""" % foo_iface_uri)
242 policy = autopolicy.AutoPolicy(foo_iface_uri, False,
243 dry_run = True)
244 policy.freshness = 0
245 policy.network_use = model.network_full
246 policy.recalculate()
247 assert policy.ready
248 foo_iface = policy.get_interface(foo_iface_uri)
249 self.assertEquals('sha1=123', policy.implementation[foo_iface].id)
251 def testBadConfig(self):
252 path = basedir.save_config_path(namespaces.config_site,
253 namespaces.config_prog)
254 glob = os.path.join(path, 'global')
255 assert not os.path.exists(glob)
256 stream = file(glob, 'w')
257 stream.write('hello!')
258 stream.close()
260 logger.setLevel(logging.ERROR)
261 policy = autopolicy.AutoPolicy(foo_iface_uri,
262 download_only = False)
263 logger.setLevel(logging.WARN)
265 def testRanking(self):
266 self.cache_iface('http://bar',
267 """<?xml version="1.0" ?>
268 <interface last-modified="1110752708"
269 uri="http://bar"
270 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
271 <name>Bar</name>
272 <summary>Bar</summary>
273 <description>Bar</description>
274 <implementation id='sha1=125' version='1.0' arch='odd-weird' stability='buggy'/>
275 <implementation id='sha1=126' version='1.0'/>
276 </interface>""")
277 self.cache_iface(foo_iface_uri,
278 """<?xml version="1.0" ?>
279 <interface last-modified="1110752708"
280 uri="%s"
281 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
282 <name>Foo</name>
283 <summary>Foo</summary>
284 <description>Foo</description>
285 <feed src='http://example.com' arch='odd-unknown'/>
286 <feed src='http://bar'/>
287 <implementation id='sha1=123' version='1.0' arch='odd-strange'/>
288 <implementation id='sha1=124' version='1.0' arch='odd-weird'/>
289 </interface>""" % foo_iface_uri)
290 policy = autopolicy.AutoPolicy(foo_iface_uri,
291 download_only = False)
292 policy.network_use = model.network_full
293 policy.freshness = 0
294 impls = policy.get_ranked_implementations(
295 policy.get_interface(policy.root))
296 assert len(impls) == 4
298 logger.setLevel(logging.ERROR)
299 policy.network_use = model.network_offline # Changes sort order tests
300 policy.recalculate() # Triggers feed-for warning
301 logger.setLevel(logging.WARN)
303 def testNoLocal(self):
304 self.cache_iface(foo_iface_uri,
305 """<?xml version="1.0" ?>
306 <interface last-modified="1110752708"
307 uri="%s"
308 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
309 <name>Foo</name>
310 <summary>Foo</summary>
311 <description>Foo</description>
312 <feed src='/etc/passwd'/>
313 </interface>""" % foo_iface_uri)
314 policy = autopolicy.AutoPolicy(foo_iface_uri,
315 download_only = False)
316 policy.network_use = model.network_offline
317 try:
318 policy.get_interface(foo_iface_uri)
319 assert False
320 except reader.InvalidInterface, ex:
321 assert 'Invalid feed URL' in str(ex)
323 def testDLfeed(self):
324 self.cache_iface(foo_iface_uri,
325 """<?xml version="1.0" ?>
326 <interface last-modified="1110752708"
327 uri="%s"
328 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
329 <name>Foo</name>
330 <summary>Foo</summary>
331 <description>Foo</description>
332 <feed src='http://example.com'/>
333 </interface>""" % foo_iface_uri)
334 policy = autopolicy.AutoPolicy(foo_iface_uri, dry_run = True)
335 policy.network_use = model.network_full
336 policy.freshness = 0
338 try:
339 policy.recalculate()
340 assert False
341 except NeedDownload, ex:
342 pass
344 iface = policy.get_interface(foo_iface_uri)
345 iface.feeds = [model.Feed('/BadFeed', None, False)]
347 logger.setLevel(logging.ERROR)
348 policy.recalculate() # Triggers warning
349 logger.setLevel(logging.WARN)
351 def testBestUnusable(self):
352 self.cache_iface(foo_iface_uri,
353 """<?xml version="1.0" ?>
354 <interface last-modified="1110752708"
355 uri="%s"
356 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
357 <name>Foo</name>
358 <summary>Foo</summary>
359 <description>Foo</description>
360 <implementation id='sha1=123' version='1.0' arch='odd-weird'/>
361 </interface>""" % foo_iface_uri)
362 policy = autopolicy.AutoPolicy(foo_iface_uri,
363 download_only = False)
364 policy.network_use = model.network_offline
365 policy.recalculate()
366 assert not policy.ready
367 try:
368 policy.download_and_execute([])
369 assert False
370 except model.SafeException, ex:
371 assert "Can't find all required implementations" in str(ex)
373 def testNoArchives(self):
374 self.cache_iface(foo_iface_uri,
375 """<?xml version="1.0" ?>
376 <interface last-modified="1110752708"
377 uri="%s"
378 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
379 <name>Foo</name>
380 <summary>Foo</summary>
381 <description>Foo</description>
382 <implementation id='sha1=123' version='1.0'/>
383 </interface>""" % foo_iface_uri)
384 policy = autopolicy.AutoPolicy(foo_iface_uri,
385 download_only = False)
386 policy.freshness = 0
387 policy.recalculate()
388 assert policy.ready
389 try:
390 policy.download_and_execute([])
391 assert False
392 except model.SafeException, ex:
393 assert 'no download locations' in str(ex)
395 def testCycle(self):
396 self.cache_iface(foo_iface_uri,
397 """<?xml version="1.0" ?>
398 <interface last-modified="1110752708"
399 uri="%s"
400 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
401 <name>Foo</name>
402 <summary>Foo</summary>
403 <description>Foo</description>
404 <group>
405 <requires interface='%s'/>
406 <implementation id='sha1=123' version='1.0'/>
407 </group>
408 </interface>""" % (foo_iface_uri, foo_iface_uri))
409 policy = autopolicy.AutoPolicy(foo_iface_uri,
410 download_only = False)
411 policy.recalculate()
413 def testConstraints(self):
414 self.cache_iface('http://bar',
415 """<?xml version="1.0" ?>
416 <interface last-modified="1110752708"
417 uri="http://bar"
418 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
419 <name>Bar</name>
420 <summary>Bar</summary>
421 <description>Bar</description>
422 <implementation id='sha1=100' version='1.0'/>
423 <implementation id='sha1=150' stability='developer' version='1.5'/>
424 <implementation id='sha1=200' version='2.0'/>
425 </interface>""")
426 self.cache_iface(foo_iface_uri,
427 """<?xml version="1.0" ?>
428 <interface last-modified="1110752708"
429 uri="%s"
430 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
431 <name>Foo</name>
432 <summary>Foo</summary>
433 <description>Foo</description>
434 <group>
435 <requires interface='http://bar'>
436 <version/>
437 </requires>
438 <implementation id='sha1=123' version='1.0'/>
439 </group>
440 </interface>""" % foo_iface_uri)
441 policy = autopolicy.AutoPolicy(foo_iface_uri,
442 download_only = False)
443 policy.network_use = model.network_full
444 policy.freshness = 0
445 #logger.setLevel(logging.DEBUG)
446 policy.recalculate()
447 #logger.setLevel(logging.WARN)
448 foo_iface = policy.get_interface(foo_iface_uri)
449 bar_iface = policy.get_interface('http://bar')
450 assert policy.implementation[bar_iface].id == 'sha1=200'
452 dep = policy.implementation[foo_iface].dependencies['http://bar']
453 assert len(dep.restrictions) == 1
454 restriction = dep.restrictions[0]
456 restriction.before = model.parse_version('2.0')
457 policy.recalculate()
458 assert policy.implementation[bar_iface].id == 'sha1=100'
460 restriction.not_before = model.parse_version('1.5')
461 policy.recalculate()
462 assert policy.implementation[bar_iface].id == 'sha1=150'
464 suite = unittest.makeSuite(TestAutoPolicy)
465 if __name__ == '__main__':
466 sys.argv.append('-v')
467 unittest.main()