2 from basetest
import BaseTest
3 import sys
, tempfile
, os
, logging
4 from StringIO
import StringIO
7 sys
.path
.insert(0, '..')
9 from zeroinstall
.injector
import model
, gpg
, namespaces
, reader
, run
, fetch
10 from zeroinstall
.injector
.requirements
import Requirements
11 from zeroinstall
.injector
.driver
import Driver
12 from zeroinstall
.support
import basedir
, tasks
15 foo_iface_uri
= 'http://foo'
17 logger
= logging
.getLogger()
19 def recalculate(driver
):
20 driver
.need_download()
22 def download_and_execute(driver
, prog_args
, main
= None, dry_run
= True):
23 downloaded
= driver
.solve_and_download_impls()
25 tasks
.wait_for_blocker(downloaded
)
26 run
.execute_selections(driver
.solver
.selections
, prog_args
, stores
= driver
.config
.stores
, main
= main
, dry_run
= dry_run
)
28 class TestDriver(BaseTest
):
31 stream
= tempfile
.TemporaryFile()
32 stream
.write(data
.thomas_key
)
34 gpg
.import_key(stream
)
36 def cache_iface(self
, name
, data
):
37 cached_ifaces
= basedir
.save_cache_path('0install.net',
40 f
= open(os
.path
.join(cached_ifaces
, model
.escape(name
)), 'w')
44 def testNoNeedDl(self
):
45 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
46 assert driver
.need_download()
48 driver
= Driver(requirements
= Requirements(os
.path
.abspath('Foo.xml')), config
= self
.config
)
49 assert not driver
.need_download()
50 assert driver
.solver
.ready
52 def testUnknownAlg(self
):
53 self
.cache_iface(foo_iface_uri
,
54 """<?xml version="1.0" ?>
57 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
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'/>
64 </interface>""" % foo_iface_uri
)
65 self
.config
.fetcher
= fetch
.Fetcher(self
.config
)
66 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
68 assert driver
.need_download()
69 download_and_execute(driver
, [])
70 except model
.SafeException
as ex
:
71 assert 'Unknown digest algorithm' in str(ex
)
73 def testDownload(self
):
74 tmp
= tempfile
.NamedTemporaryFile()
76 """<?xml version="1.0" ?>
78 main='ThisBetterNotExist'
79 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
81 <summary>Foo</summary>
82 <description>Foo</description>
83 <implementation version='1.0' id='/bin'/>
86 driver
= Driver(requirements
= Requirements(tmp
.name
), config
= self
.config
)
88 download_and_execute(driver
, ['Hello'])
90 except model
.SafeException
as ex
:
91 assert "ThisBetterNotExist" in str(ex
)
95 tmp
= tempfile
.NamedTemporaryFile()
97 """<?xml version="1.0" ?>
99 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
101 <summary>Foo</summary>
102 <description>Foo</description>
103 <implementation version='1.0' id='/bin'/>
106 driver
= Driver(requirements
= Requirements(tmp
.name
), config
= self
.config
)
108 download_and_execute(driver
, ['Hello'])
110 except model
.SafeException
as ex
:
111 assert "library" in str(ex
), ex
114 def testNeedDL(self
):
115 self
.cache_iface(foo_iface_uri
,
116 """<?xml version="1.0" ?>
117 <interface last-modified="0"
119 main='ThisBetterNotExist'
120 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
122 <summary>Foo</summary>
123 <description>Foo</description>
124 <implementation version='1.0' id='sha1=123'>
125 <archive href='http://foo/foo.tgz' size='100'/>
127 </interface>""" % foo_iface_uri
)
128 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
129 self
.config
.network_use
= model
.network_full
131 assert driver
.need_download()
132 assert driver
.solver
.ready
134 def testBinding(self
):
135 local_impl
= os
.path
.dirname(os
.path
.abspath(__file__
))
136 tmp
= tempfile
.NamedTemporaryFile()
138 """<?xml version="1.0" ?>
141 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
143 <summary>Bar</summary>
144 <description>Bar</description>
146 <requires interface='%s'>
147 <environment name='FOO_PATH' insert='.'/>
148 <environment name='BAR_PATH' insert='.' default='/a:/b'/>
149 <environment name='NO_PATH' value='val'/>
150 <environment name='XDG_DATA_DIRS' insert='.'/>
152 <environment name='SELF_GROUP' insert='group' mode='replace'/>
153 <implementation version='1.0' id='%s'>
154 <environment name='SELF_IMPL' insert='impl' mode='replace'/>
157 </interface>""" % (foo_iface_uri
, local_impl
))
159 self
.cache_iface(foo_iface_uri
,
160 """<?xml version="1.0" ?>
161 <interface last-modified="0"
163 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
165 <summary>Foo</summary>
166 <description>Foo</description>
167 <implementation version='1.0' id='sha1=123'/>
168 </interface>""" % foo_iface_uri
)
169 cached_impl
= basedir
.save_cache_path('0install.net',
172 driver
= Driver(requirements
= Requirements(tmp
.name
), config
= self
.config
)
173 self
.config
.network_use
= model
.network_offline
174 os
.environ
['FOO_PATH'] = "old"
175 old
, sys
.stdout
= sys
.stdout
, StringIO()
177 download_and_execute(driver
, ['Hello'])
180 self
.assertEqual(cached_impl
+ '/.:old',
181 os
.environ
['FOO_PATH'])
182 self
.assertEqual(cached_impl
+ '/.:/a:/b',
183 os
.environ
['BAR_PATH'])
184 self
.assertEqual('val', os
.environ
['NO_PATH'])
186 self
.assertEqual(os
.path
.join(local_impl
, 'group'), os
.environ
['SELF_GROUP'])
187 self
.assertEqual(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()
195 download_and_execute(driver
, ['Hello'])
198 self
.assertEqual(cached_impl
+ '/.',
199 os
.environ
['FOO_PATH'])
200 self
.assertEqual(cached_impl
+ '/.:/old',
201 os
.environ
['BAR_PATH'])
202 self
.assertEqual(cached_impl
+ '/.:/usr/local/share:/usr/share',
203 os
.environ
['XDG_DATA_DIRS'])
206 self
.cache_iface(foo_iface_uri
,
207 """<?xml version="1.0" ?>
208 <interface last-modified="0"
210 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
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"
220 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
221 <feed-for interface='%s'/>
223 <summary>Bar</summary>
224 <description>Bar</description>
225 <implementation version='1.0' id='sha1=123' main='dummy'>
226 <archive href='foo' size='10'/>
228 </interface>""" % foo_iface_uri
)
229 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
230 self
.config
.network_use
= model
.network_full
232 assert driver
.solver
.ready
233 foo_iface
= self
.config
.iface_cache
.get_interface(foo_iface_uri
)
234 self
.assertEqual('sha1=123', driver
.solver
.selections
[foo_iface
].id)
236 def testBadConfig(self
):
237 path
= basedir
.save_config_path(namespaces
.config_site
,
238 namespaces
.config_prog
)
239 glob
= os
.path
.join(path
, 'global')
240 assert not os
.path
.exists(glob
)
241 stream
= open(glob
, 'w')
242 stream
.write('hello!')
245 logger
.setLevel(logging
.ERROR
)
246 Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
247 logger
.setLevel(logging
.WARN
)
249 def testNoLocal(self
):
250 self
.cache_iface(foo_iface_uri
,
251 """<?xml version="1.0" ?>
252 <interface last-modified="1110752708"
254 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
256 <summary>Foo</summary>
257 <description>Foo</description>
258 <feed src='/etc/passwd'/>
259 </interface>""" % foo_iface_uri
)
260 self
.config
.network_use
= model
.network_offline
262 self
.config
.iface_cache
.get_interface(foo_iface_uri
)
264 except reader
.InvalidInterface
as ex
:
265 assert 'Invalid feed URL' in str(ex
)
267 def testDLfeed(self
):
268 self
.cache_iface(foo_iface_uri
,
269 """<?xml version="1.0" ?>
270 <interface last-modified="1110752708"
272 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
274 <summary>Foo</summary>
275 <description>Foo</description>
276 <feed src='http://example.com'/>
277 </interface>""" % foo_iface_uri
)
278 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
279 self
.config
.network_use
= model
.network_full
281 assert driver
.need_download()
283 feed
= self
.config
.iface_cache
.get_feed(foo_iface_uri
)
284 feed
.feeds
= [model
.Feed('/BadFeed', None, False)]
286 logger
.setLevel(logging
.ERROR
)
287 assert driver
.need_download() # Triggers warning
288 logger
.setLevel(logging
.WARN
)
290 def testBestUnusable(self
):
291 self
.cache_iface(foo_iface_uri
,
292 """<?xml version="1.0" ?>
293 <interface last-modified="1110752708"
295 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
297 <summary>Foo</summary>
298 <description>Foo</description>
299 <implementation id='sha1=123' version='1.0' arch='odd-weird' main='dummy'/>
300 </interface>""" % foo_iface_uri
)
301 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
302 self
.config
.network_use
= model
.network_offline
304 assert not driver
.solver
.ready
, driver
.implementation
306 download_and_execute(driver
, [])
308 except model
.SafeException
as ex
:
309 assert "has no usable implementations" in str(ex
), ex
311 def testNoArchives(self
):
312 self
.cache_iface(foo_iface_uri
,
313 """<?xml version="1.0" ?>
314 <interface last-modified="1110752708"
316 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
318 <summary>Foo</summary>
319 <description>Foo</description>
320 <implementation id='sha1=123' version='1.0' main='dummy'/>
321 </interface>""" % foo_iface_uri
)
322 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
324 assert not driver
.solver
.ready
327 self
.cache_iface(foo_iface_uri
,
328 """<?xml version="1.0" ?>
329 <interface last-modified="1110752708"
331 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
333 <summary>Foo</summary>
334 <description>Foo</description>
336 <requires interface='%s'/>
337 <implementation id='sha1=123' version='1.0'>
338 <archive href='foo' size='10'/>
341 </interface>""" % (foo_iface_uri
, foo_iface_uri
))
342 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
345 def testConstraints(self
):
346 self
.cache_iface('http://bar',
347 """<?xml version="1.0" ?>
348 <interface last-modified="1110752708"
350 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
352 <summary>Bar</summary>
353 <description>Bar</description>
354 <implementation id='sha1=100' version='1.0'>
355 <archive href='foo' size='10'/>
357 <implementation id='sha1=150' stability='developer' version='1.5'>
358 <archive href='foo' size='10'/>
360 <implementation id='sha1=200' version='2.0'>
361 <archive href='foo' size='10'/>
364 self
.cache_iface(foo_iface_uri
,
365 """<?xml version="1.0" ?>
366 <interface last-modified="1110752708"
368 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
370 <summary>Foo</summary>
371 <description>Foo</description>
373 <requires interface='http://bar'>
376 <implementation id='sha1=123' version='1.0'>
377 <archive href='foo' size='10'/>
380 </interface>""" % foo_iface_uri
)
381 driver
= Driver(requirements
= Requirements(foo_iface_uri
), config
= self
.config
)
382 self
.config
.network_use
= model
.network_full
383 #logger.setLevel(logging.DEBUG)
385 #logger.setLevel(logging.WARN)
386 foo_iface
= self
.config
.iface_cache
.get_interface(foo_iface_uri
)
387 bar_iface
= self
.config
.iface_cache
.get_interface('http://bar')
388 assert driver
.solver
.selections
[bar_iface
].id == 'sha1=200'
390 dep
= driver
.solver
.selections
[foo_iface
].dependencies
['http://bar']
391 assert len(dep
.restrictions
) == 1
392 restriction
= dep
.restrictions
[0]
394 restriction
.before
= model
.parse_version('2.0')
396 assert driver
.solver
.selections
[bar_iface
].id == 'sha1=100'
398 restriction
.not_before
= model
.parse_version('1.5')
400 assert driver
.solver
.selections
[bar_iface
].id == 'sha1=150'
402 def testSource(self
):
403 iface_cache
= self
.config
.iface_cache
405 foo
= iface_cache
.get_interface('http://foo/Binary.xml')
406 self
.import_feed(foo
.uri
, 'Binary.xml')
407 foo_src
= iface_cache
.get_interface('http://foo/Source.xml')
408 self
.import_feed(foo_src
.uri
, 'Source.xml')
409 compiler
= iface_cache
.get_interface('http://foo/Compiler.xml')
410 self
.import_feed(compiler
.uri
, 'Compiler.xml')
412 self
.config
.freshness
= 0
413 self
.config
.network_use
= model
.network_full
414 driver
= Driver(requirements
= Requirements('http://foo/Binary.xml'), config
= self
.config
)
415 tasks
.wait_for_blocker(driver
.solve_with_downloads())
416 assert driver
.solver
.selections
[foo
].id == 'sha1=123'
418 # Now ask for source instead
419 driver
.requirements
.source
= True
420 driver
.requirements
.command
= 'compile'
421 tasks
.wait_for_blocker(driver
.solve_with_downloads())
422 assert driver
.solver
.ready
, driver
.solver
.get_failure_reason()
423 assert driver
.solver
.selections
[foo
].id == 'sha1=234' # The source
424 assert driver
.solver
.selections
[compiler
].id == 'sha1=345' # A binary needed to compile it
426 if __name__
== '__main__':