Cope better if no GUI is available
[zeroinstall/solver.git] / tests / testlaunch.py
blob21e300d698624163ea167c88a511df68bac09135
1 #!/usr/bin/env python
3 from __future__ import print_function
5 from basetest import BaseTest, StringIO, BytesIO
6 import sys, tempfile, os
7 import unittest
8 import logging
10 foo_iface_uri = 'http://foo'
12 sys.path.insert(0, '..')
13 from zeroinstall import SafeException
14 from zeroinstall.support import tasks
15 from zeroinstall.injector import run, cli, namespaces, qdom, selections
16 from zeroinstall.zerostore import Store; Store._add_with_helper = lambda *unused: False
17 from zeroinstall.injector.requirements import Requirements
18 from zeroinstall.injector.driver import Driver
20 mydir = os.path.abspath(os.path.dirname(__file__))
22 class SilenceLogger(logging.Filter):
23 def filter(self, record):
24 return 0
25 silenceLogger = SilenceLogger()
27 class TestLaunch(BaseTest):
28 def run_0launch(self, args):
29 old_stdout = sys.stdout
30 old_stderr = sys.stderr
31 try:
32 sys.stdout = StringIO()
33 sys.stderr = StringIO()
34 ex = None
35 try:
36 cli.main(args)
37 print("Finished")
38 except NameError:
39 raise
40 except SystemExit:
41 pass
42 except TypeError:
43 raise
44 except AttributeError:
45 raise
46 except AssertionError:
47 raise
48 except Exception as ex2:
49 ex = ex2 # Python 3
50 out = sys.stdout.getvalue()
51 err = sys.stderr.getvalue()
52 if ex is not None:
53 err += str(ex.__class__)
54 finally:
55 sys.stdout = old_stdout
56 sys.stderr = old_stderr
57 return (out, err)
59 def testHelp(self):
60 out, err = self.run_0launch([])
61 assert out.lower().startswith("usage:")
62 assert not err
64 def testList(self):
65 out, err = self.run_0launch(['--list'])
66 assert not err
67 self.assertEqual("Finished\n", out)
68 cached_ifaces = os.path.join(self.cache_home,
69 '0install.net', 'interfaces')
71 os.makedirs(cached_ifaces)
72 open(os.path.join(cached_ifaces, 'file%3a%2f%2ffoo'), 'w').close()
74 out, err = self.run_0launch(['--list'])
75 assert not err
76 self.assertEqual("file://foo\nFinished\n", out)
78 out, err = self.run_0launch(['--list', 'foo'])
79 assert not err
80 self.assertEqual("file://foo\nFinished\n", out)
82 out, err = self.run_0launch(['--list', 'bar'])
83 assert not err
84 self.assertEqual("Finished\n", out)
86 out, err = self.run_0launch(['--list', 'one', 'two'])
87 assert not err
88 assert out.lower().startswith("usage:")
90 def testVersion(self):
91 out, err = self.run_0launch(['--version'])
92 assert not err
93 assert out.startswith("0launch (zero-install)")
95 def testInvalid(self):
96 a = tempfile.NamedTemporaryFile()
97 out, err = self.run_0launch(['-q', a.name])
98 assert err
100 def testOK(self):
101 out, err = self.run_0launch(['--dry-run', 'http://foo/d'])
102 self.assertEqual("Would download 'http://foo/d'\nFinished\n", out)
103 self.assertEqual("", err)
105 def testRun(self):
106 out, err = self.run_0launch(['Local.xml'])
107 self.assertEqual("", out)
108 assert "test-echo' does not exist" in err, err
110 def testAbsMain(self):
111 with tempfile.NamedTemporaryFile(prefix = 'test-', delete = False) as tmp:
112 tmp.write((
113 """<?xml version="1.0" ?>
114 <interface last-modified="1110752708"
115 uri="%s"
116 xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
117 <name>Foo</name>
118 <summary>Foo</summary>
119 <description>Foo</description>
120 <group main='/bin/sh'>
121 <implementation id='.' version='1'/>
122 </group>
123 </interface>""" % foo_iface_uri).encode('utf-8'))
125 driver = Driver(requirements = Requirements(tmp.name), config = self.config)
126 try:
127 downloaded = driver.solve_and_download_impls()
128 if downloaded:
129 tasks.wait_for_blocker(downloaded)
130 run.execute_selections(driver.solver.selections, [], stores = self.config.stores)
131 assert False
132 except SafeException as ex:
133 assert 'Command path must be relative' in str(ex), ex
135 def testOffline(self):
136 out, err = self.run_0launch(['--offline', 'http://foo/d'])
137 self.assertEqual("Interface 'http://foo/d' has no usable implementations in the cache (and 0install is in off-line mode)\n", err)
138 self.assertEqual("", out)
140 def testDisplay(self):
141 os.environ['DISPLAY'] = ':foo'
142 out, err = self.run_0launch(['--dry-run', 'http://foo/d'])
143 # Uses local copy of GUI
144 assert out.startswith("Would execute: "), repr((out, err))
145 assert 'basetest.py' in out
146 self.assertEqual("", err)
148 del os.environ['DISPLAY']
149 out, err = self.run_0launch(['--gui'])
150 self.assertEqual("Can't use GUI because $DISPLAY is not set\n", err)
151 self.assertEqual("", out)
153 def testRefreshDisplay(self):
154 os.environ['DISPLAY'] = ':foo'
155 out, err = self.run_0launch(['--dry-run', '--refresh', 'http://foo/d'])
156 assert out.startswith("Would execute: ")
157 assert 'basetest.py' in out
158 self.assertEqual("", err)
160 def testNeedDownload(self):
161 os.environ['DISPLAY'] = ':foo'
162 out, err = self.run_0launch(['--download-only', '--dry-run', 'Foo.xml'])
163 self.assertEqual("", err)
164 self.assertEqual("Finished\n", out)
166 def testSelectOnly(self):
167 os.environ['DISPLAY'] = ':foo'
168 out, err = self.run_0launch(['--get-selections', '--select-only', 'Hello.xml'])
169 self.assertEqual("", err)
171 assert out.endswith("Finished\n")
172 out = out[:-len("Finished\n")]
174 root = qdom.parse(BytesIO(str(out).encode('utf-8')))
175 self.assertEqual(namespaces.XMLNS_IFACE, root.uri)
176 sels = selections.Selections(root)
177 sel,= sels.selections.values()
178 self.assertEqual("sha1=3ce644dc725f1d21cfcf02562c76f375944b266a", sel.id)
180 def testHello(self):
181 out, err = self.run_0launch(['--dry-run', 'Foo.xml'])
182 self.assertEqual("", err)
183 assert out.startswith("Would execute: ")
185 out, err = self.run_0launch(['Foo.xml'])
186 # (Foo.xml tries to run a directory; plash gives a different error)
187 assert "Permission denied" in err or "Is a directory" in err
189 def testSource(self):
190 out, err = self.run_0launch(['--dry-run', '--source', '--not-before=1', 'Source.xml'])
191 self.assertEqual("", err)
192 assert 'Compiler.xml' in out
194 def testRanges(self):
195 out, err = self.run_0launch(['--get-selections', '--before=1', '--not-before=0.2', 'Foo.xml'])
196 assert 'tests/rpm' in out, out
197 self.assertEqual("", err)
199 def testLogging(self):
200 log = logging.getLogger()
201 log.addFilter(silenceLogger)
203 out, err = self.run_0launch(['-v', '--list', 'UNKNOWN'])
204 self.assertEqual(logging.INFO, log.level)
206 out, err = self.run_0launch(['-vv', '--version'])
207 self.assertEqual(logging.DEBUG, log.level)
209 log.removeFilter(silenceLogger)
210 log.setLevel(logging.WARN)
212 def testHelp2(self):
213 out, err = self.run_0launch(['--help'])
214 self.assertEqual("", err)
215 assert 'options:' in out.lower()
217 out, err = self.run_0launch([])
218 self.assertEqual("", err)
219 assert 'options:' in out.lower()
221 def testBadFD(self):
222 copy = os.dup(1)
223 try:
224 os.close(1)
225 cli.main(['--list', 'UNKNOWN'])
226 finally:
227 os.dup2(copy, 1)
229 def testShow(self):
230 command_feed = os.path.join(mydir, 'Command.xml')
231 out, err = self.run_0launch(['--show', command_feed])
232 self.assertEqual("", err)
233 assert 'Local.xml' in out, out
235 if __name__ == '__main__':
236 unittest.main()