Large-scale API cleanup
[zeroinstall/zeroinstall-afb.git] / tests / testautopolicy.py
blob7e5a37320ecdea2009d18373e43a1a9282916c82
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 = file(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.handler)
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, 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, 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, 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='XDG_DATA_DIRS' insert='.'/>
152 </requires>
153 <environment name='SELF_GROUP' insert='group' mode='replace'/>
154 <implementation version='1.0' id='%s'>
155 <environment name='SELF_IMPL' insert='impl' mode='replace'/>
156 </implementation>
157 </group>
158 </interface>""" % (foo_iface_uri, local_impl))
159 tmp.flush()
160 self.cache_iface(foo_iface_uri,
161 """<?xml version="1.0" ?>
162 <interface last-modified="0"
163 uri="%s"
164 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
165 <name>Foo</name>
166 <summary>Foo</summary>
167 <description>Foo</description>
168 <implementation version='1.0' id='sha1=123'/>
169 </interface>""" % foo_iface_uri)
170 cached_impl = basedir.save_cache_path('0install.net',
171 'implementations',
172 'sha1=123')
173 policy = Policy(tmp.name, config = self.config)
174 policy.network_use = model.network_offline
175 os.environ['FOO_PATH'] = "old"
176 old, sys.stdout = sys.stdout, StringIO()
177 try:
178 download_and_execute(policy, ['Hello'])
179 finally:
180 sys.stdout = old
181 self.assertEquals(cached_impl + '/.:old',
182 os.environ['FOO_PATH'])
183 self.assertEquals(cached_impl + '/.:/a:/b',
184 os.environ['BAR_PATH'])
186 self.assertEquals(os.path.join(local_impl, 'group'), os.environ['SELF_GROUP'])
187 self.assertEquals(os.path.join(local_impl, 'impl'), os.environ['SELF_IMPL'])
189 del os.environ['FOO_PATH']
190 if 'XDG_DATA_DIRS' in os.environ:
191 del os.environ['XDG_DATA_DIRS']
192 os.environ['BAR_PATH'] = '/old'
193 old, sys.stdout = sys.stdout, StringIO()
194 try:
195 download_and_execute(policy, ['Hello'])
196 finally:
197 sys.stdout = old
198 self.assertEquals(cached_impl + '/.',
199 os.environ['FOO_PATH'])
200 self.assertEquals(cached_impl + '/.:/old',
201 os.environ['BAR_PATH'])
202 self.assertEquals(cached_impl + '/.:/usr/local/share:/usr/share',
203 os.environ['XDG_DATA_DIRS'])
205 def testFeeds(self):
206 self.cache_iface(foo_iface_uri,
207 """<?xml version="1.0" ?>
208 <interface last-modified="0"
209 uri="%s"
210 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
211 <name>Foo</name>
212 <summary>Foo</summary>
213 <description>Foo</description>
214 <feed src='http://bar'/>
215 </interface>""" % foo_iface_uri)
216 self.cache_iface('http://bar',
217 """<?xml version="1.0" ?>
218 <interface last-modified="0"
219 uri="http://bar"
220 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
221 <feed-for interface='%s'/>
222 <name>Bar</name>
223 <summary>Bar</summary>
224 <description>Bar</description>
225 <implementation version='1.0' id='sha1=123' main='dummy'>
226 <archive href='foo' size='10'/>
227 </implementation>
228 </interface>""" % foo_iface_uri)
229 policy = Policy(foo_iface_uri, config = self.config)
230 policy.freshness = 0
231 policy.network_use = model.network_full
232 recalculate(policy)
233 assert policy.ready
234 foo_iface = self.config.iface_cache.get_interface(foo_iface_uri)
235 self.assertEquals('sha1=123', policy.implementation[foo_iface].id)
237 def testBadConfig(self):
238 path = basedir.save_config_path(namespaces.config_site,
239 namespaces.config_prog)
240 glob = os.path.join(path, 'global')
241 assert not os.path.exists(glob)
242 stream = file(glob, 'w')
243 stream.write('hello!')
244 stream.close()
246 logger.setLevel(logging.ERROR)
247 Policy(foo_iface_uri, config = self.config)
248 logger.setLevel(logging.WARN)
250 def testNoLocal(self):
251 self.cache_iface(foo_iface_uri,
252 """<?xml version="1.0" ?>
253 <interface last-modified="1110752708"
254 uri="%s"
255 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
256 <name>Foo</name>
257 <summary>Foo</summary>
258 <description>Foo</description>
259 <feed src='/etc/passwd'/>
260 </interface>""" % foo_iface_uri)
261 self.config.network_use = model.network_offline
262 try:
263 self.config.iface_cache.get_interface(foo_iface_uri)
264 assert False
265 except reader.InvalidInterface, ex:
266 assert 'Invalid feed URL' in str(ex)
268 def testDLfeed(self):
269 self.cache_iface(foo_iface_uri,
270 """<?xml version="1.0" ?>
271 <interface last-modified="1110752708"
272 uri="%s"
273 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
274 <name>Foo</name>
275 <summary>Foo</summary>
276 <description>Foo</description>
277 <feed src='http://example.com'/>
278 </interface>""" % foo_iface_uri)
279 policy = Policy(foo_iface_uri, config = self.config)
280 policy.network_use = model.network_full
281 policy.freshness = 0
283 assert policy.need_download()
285 feed = self.config.iface_cache.get_feed(foo_iface_uri)
286 feed.feeds = [model.Feed('/BadFeed', None, False)]
288 logger.setLevel(logging.ERROR)
289 assert policy.need_download() # Triggers warning
290 logger.setLevel(logging.WARN)
292 def testBestUnusable(self):
293 self.cache_iface(foo_iface_uri,
294 """<?xml version="1.0" ?>
295 <interface last-modified="1110752708"
296 uri="%s"
297 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
298 <name>Foo</name>
299 <summary>Foo</summary>
300 <description>Foo</description>
301 <implementation id='sha1=123' version='1.0' arch='odd-weird' main='dummy'/>
302 </interface>""" % foo_iface_uri)
303 policy = Policy(foo_iface_uri, config = self.config)
304 policy.network_use = model.network_offline
305 recalculate(policy)
306 assert not policy.ready, policy.implementation
307 try:
308 download_and_execute(policy, [])
309 assert False
310 except model.SafeException, ex:
311 assert "has no usable implementations" in str(ex), ex
313 def testNoArchives(self):
314 self.cache_iface(foo_iface_uri,
315 """<?xml version="1.0" ?>
316 <interface last-modified="1110752708"
317 uri="%s"
318 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
319 <name>Foo</name>
320 <summary>Foo</summary>
321 <description>Foo</description>
322 <implementation id='sha1=123' version='1.0' main='dummy'/>
323 </interface>""" % foo_iface_uri)
324 policy = Policy(foo_iface_uri, config = self.config)
325 policy.freshness = 0
326 recalculate(policy)
327 assert not policy.ready
329 def testCycle(self):
330 self.cache_iface(foo_iface_uri,
331 """<?xml version="1.0" ?>
332 <interface last-modified="1110752708"
333 uri="%s"
334 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
335 <name>Foo</name>
336 <summary>Foo</summary>
337 <description>Foo</description>
338 <group>
339 <requires interface='%s'/>
340 <implementation id='sha1=123' version='1.0'>
341 <archive href='foo' size='10'/>
342 </implementation>
343 </group>
344 </interface>""" % (foo_iface_uri, foo_iface_uri))
345 policy = Policy(foo_iface_uri, config = self.config)
346 policy.freshness = 0
347 recalculate(policy)
349 def testConstraints(self):
350 self.cache_iface('http://bar',
351 """<?xml version="1.0" ?>
352 <interface last-modified="1110752708"
353 uri="http://bar"
354 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
355 <name>Bar</name>
356 <summary>Bar</summary>
357 <description>Bar</description>
358 <implementation id='sha1=100' version='1.0'>
359 <archive href='foo' size='10'/>
360 </implementation>
361 <implementation id='sha1=150' stability='developer' version='1.5'>
362 <archive href='foo' size='10'/>
363 </implementation>
364 <implementation id='sha1=200' version='2.0'>
365 <archive href='foo' size='10'/>
366 </implementation>
367 </interface>""")
368 self.cache_iface(foo_iface_uri,
369 """<?xml version="1.0" ?>
370 <interface last-modified="1110752708"
371 uri="%s"
372 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
373 <name>Foo</name>
374 <summary>Foo</summary>
375 <description>Foo</description>
376 <group main='dummy'>
377 <requires interface='http://bar'>
378 <version/>
379 </requires>
380 <implementation id='sha1=123' version='1.0'>
381 <archive href='foo' size='10'/>
382 </implementation>
383 </group>
384 </interface>""" % foo_iface_uri)
385 policy = Policy(foo_iface_uri, config = self.config)
386 policy.network_use = model.network_full
387 policy.freshness = 0
388 #logger.setLevel(logging.DEBUG)
389 recalculate(policy)
390 #logger.setLevel(logging.WARN)
391 foo_iface = self.config.iface_cache.get_interface(foo_iface_uri)
392 bar_iface = self.config.iface_cache.get_interface('http://bar')
393 assert policy.implementation[bar_iface].id == 'sha1=200'
395 dep = policy.implementation[foo_iface].dependencies['http://bar']
396 assert len(dep.restrictions) == 1
397 restriction = dep.restrictions[0]
399 restriction.before = model.parse_version('2.0')
400 recalculate(policy)
401 assert policy.implementation[bar_iface].id == 'sha1=100'
403 restriction.not_before = model.parse_version('1.5')
404 recalculate(policy)
405 assert policy.implementation[bar_iface].id == 'sha1=150'
407 if __name__ == '__main__':
408 unittest.main()