More unit-tests for apps
[zeroinstall.git] / tests / testinstall.py
bloba765cf276fb84f00a6e50ad68b5c62fb94f459d4
1 #!/usr/bin/env python
2 from basetest import BaseTest, TestStores
3 import sys, os, tempfile
4 from StringIO import StringIO
5 import unittest
7 sys.path.insert(0, '..')
8 from zeroinstall import cmd
9 from zeroinstall.injector import model, selections, qdom, reader, policy, handler, gpg
11 mydir = os.path.dirname(__file__)
13 class Reply:
14 def __init__(self, reply):
15 self.reply = reply
17 def readline(self):
18 return self.reply
20 class TestInstall(BaseTest):
21 def run_0install(self, args):
22 old_stdout = sys.stdout
23 old_stderr = sys.stderr
24 try:
25 sys.stdout = StringIO()
26 sys.stderr = StringIO()
27 ex = None
28 try:
29 cmd.main(args, config = self.config)
30 except NameError:
31 raise
32 except SystemExit:
33 pass
34 except TypeError:
35 raise
36 except AttributeError:
37 raise
38 except AssertionError:
39 raise
40 except Exception as ex:
41 pass
42 out = sys.stdout.getvalue()
43 err = sys.stderr.getvalue()
44 if ex is not None:
45 err += str(ex.__class__)
46 finally:
47 sys.stdout = old_stdout
48 sys.stderr = old_stderr
49 return (out, err)
51 def testHelp(self):
52 out, err = self.run_0install([])
53 assert out.lower().startswith("usage:")
54 assert 'add-feed' in out
55 assert '--version' in out
56 assert not err, err
58 out2, err = self.run_0install(['--help'])
59 assert not err, err
60 assert out2 == out
62 out, err = self.run_0install(['--version'])
63 assert 'Thomas Leonard' in out
64 assert not err, err
66 out, err = self.run_0install(['foobar'])
67 assert 'Unknown sub-command' in err, err
69 def testSelect(self):
70 out, err = self.run_0install(['select'])
71 assert out.lower().startswith("usage:")
72 assert '--xml' in out
74 out, err = self.run_0install(['select', 'Local.xml'])
75 assert not err, err
76 assert 'Version: 0.1' in out
78 out, err = self.run_0install(['select', 'Local.xml', '--command='])
79 assert not err, err
80 assert 'Version: 0.1' in out
82 local_uri = model.canonical_iface_uri('Local.xml')
83 out, err = self.run_0install(['select', 'Local.xml'])
84 assert not err, err
85 assert 'Version: 0.1' in out
87 out, err = self.run_0install(['select', 'Local.xml', '--xml'])
88 sels = selections.Selections(qdom.parse(StringIO(str(out))))
89 assert sels.selections[local_uri].version == '0.1'
91 out, err = self.run_0install(['select', 'selections.xml'])
92 assert not err, err
93 assert 'Version: 1\n' in out
94 assert '(not cached)' in out
96 out, err = self.run_0install(['select', 'runnable/RunExec.xml'])
97 assert not err, err
98 assert 'Runner' in out, out
100 def testDownload(self):
101 out, err = self.run_0install(['download'])
102 assert out.lower().startswith("usage:")
103 assert '--show' in out
105 out, err = self.run_0install(['download', 'Local.xml', '--show'])
106 assert not err, err
107 assert 'Version: 0.1' in out
109 local_uri = model.canonical_iface_uri('Local.xml')
110 out, err = self.run_0install(['download', 'Local.xml', '--xml'])
111 assert not err, err
112 sels = selections.Selections(qdom.parse(StringIO(str(out))))
113 assert sels.selections[local_uri].version == '0.1'
115 out, err = self.run_0install(['download', 'Local.xml', '--show', '--with-store=/foo'])
116 assert not err, err
117 assert self.config.stores.stores[-1].dir == '/foo'
119 out, err = self.run_0install(['download', '--offline', 'selections.xml'])
120 assert 'Would download' in err
121 self.config.network_use = model.network_full
123 self.config.stores = TestStores()
124 digest = 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
125 self.config.fetcher.allow_download(digest)
126 out, err = self.run_0install(['download', 'Hello.xml', '--show'])
127 assert not err, err
128 assert self.config.stores.lookup_any([digest]).startswith('/fake')
129 assert 'Version: 1\n' in out
131 out, err = self.run_0install(['download', '--offline', 'selections.xml', '--show'])
132 assert '/fake_store' in out
133 self.config.network_use = model.network_full
135 def testDownloadSelections(self):
136 self.config.stores = TestStores()
137 digest = 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
138 self.config.fetcher.allow_download(digest)
139 hello = reader.load_feed('Hello.xml')
140 self.config.fetcher.allow_feed_download('http://example.com:8000/Hello.xml', hello)
141 out, err = self.run_0install(['download', 'selections.xml', '--show'])
142 assert not err, err
143 assert self.config.stores.lookup_any([digest]).startswith('/fake')
144 assert 'Version: 1\n' in out
146 def testUpdate(self):
147 out, err = self.run_0install(['update'])
148 assert out.lower().startswith("usage:")
149 assert '--message' in out, out
151 # Updating a local feed with no dependencies
152 out, err = self.run_0install(['update', 'Local.xml'])
153 assert not err, err
154 assert 'No updates found' in out, out
156 # Using a remote feed for the first time
157 self.config.stores = TestStores()
158 binary_feed = reader.load_feed('Binary.xml')
159 self.config.fetcher.allow_download('sha1=123')
160 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
161 out, err = self.run_0install(['update', 'http://foo/Binary.xml'])
162 assert not err, err
163 assert 'Binary.xml: new -> 1.0' in out, out
165 # No updates.
166 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
167 out, err = self.run_0install(['update', 'http://foo/Binary.xml'])
168 assert not err, err
169 assert 'No updates found' in out, out
171 # New binary release available.
172 new_binary_feed = reader.load_feed('Binary.xml')
173 new_binary_feed.implementations['sha1=123'].version = model.parse_version('1.1')
174 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', new_binary_feed)
175 out, err = self.run_0install(['update', 'http://foo/Binary.xml'])
176 assert not err, err
177 assert 'Binary.xml: 1.0 -> 1.1' in out, out
179 # Compiling from source for the first time.
180 source_feed = reader.load_feed('Source.xml')
181 compiler_feed = reader.load_feed('Compiler.xml')
182 self.config.fetcher.allow_download('sha1=234')
183 self.config.fetcher.allow_download('sha1=345')
184 self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', compiler_feed)
185 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
186 self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed)
187 out, err = self.run_0install(['update', 'http://foo/Binary.xml', '--source'])
188 assert not err, err
189 assert 'Binary.xml: new -> 1.0' in out, out
190 assert 'Compiler.xml: new -> 1.0' in out, out
192 # New compiler released.
193 new_compiler_feed = reader.load_feed('Compiler.xml')
194 new_compiler_feed.implementations['sha1=345'].version = model.parse_version('1.1')
195 self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', new_compiler_feed)
196 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
197 self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed)
198 out, err = self.run_0install(['update', 'http://foo/Binary.xml', '--source'])
199 assert not err, err
200 assert 'Compiler.xml: 1.0 -> 1.1' in out, out
202 # A dependency disappears.
203 new_source_feed = reader.load_feed('Source.xml')
204 new_source_feed.implementations['sha1=234'].requires = []
205 self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', new_compiler_feed)
206 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
207 self.config.fetcher.allow_feed_download('http://foo/Source.xml', new_source_feed)
208 out, err = self.run_0install(['update', 'http://foo/Binary.xml', '--source'])
209 assert not err, err
210 assert 'No longer used: http://foo/Compiler.xml' in out, out
212 def testConfig(self):
213 out, err = self.run_0install(['config', '--help'])
214 assert out.lower().startswith("usage:")
215 assert '--console' in out
217 out, err = self.run_0install(['config'])
218 assert not err, err
219 assert 'full' in out, out
220 assert 'freshness = 0' in out, out
221 assert 'help_with_testing = False' in out, out
223 out, err = self.run_0install(['config', 'help_with_testing'])
224 assert out == 'False\n', out
226 file_config = policy.load_config(handler.Handler())
227 def get_value(name):
228 old_stdout = sys.stdout
229 sys.stdout = StringIO()
230 try:
231 cmd.config.handle(file_config, None, [name])
232 cmd_output = sys.stdout.getvalue()
233 finally:
234 sys.stdout = old_stdout
235 return cmd_output
237 assert get_value('freshness') == '30d\n'
238 assert get_value('network_use') == 'full\n'
239 assert get_value('help_with_testing') == 'False\n'
241 cmd.config.handle(file_config, None, ['freshness', '5m'])
242 cmd.config.handle(file_config, None, ['help_with_testing', 'True'])
243 cmd.config.handle(file_config, None, ['network_use', 'minimal'])
244 assert file_config.freshness == 5 * 60
245 assert file_config.network_use == model.network_minimal
246 assert file_config.help_with_testing == True
248 file_config2 = policy.load_config(handler.Handler())
249 assert file_config2.freshness == 5 * 60
250 assert file_config2.network_use == model.network_minimal
251 assert file_config2.help_with_testing == True
253 cmd.config.handle(file_config, None, ['help_with_testing', 'falsE'])
254 assert file_config.help_with_testing == False
256 for period in ['1s', '2d', '3.5m', '4h', '5d']:
257 secs = cmd.config.TimeInterval.parse(period)
258 assert cmd.config.TimeInterval.format(secs) == period
260 def testAddFeed(self):
261 binary_iface = self.config.iface_cache.get_interface('http://foo/Binary.xml')
263 out, err = self.run_0install(['list-feeds', binary_iface.uri])
264 assert "(no feeds)" in out, out
265 assert not err, err
267 out, err = self.run_0install(['add-feed'])
268 assert out.lower().startswith("usage:")
269 assert 'NEW-FEED' in out
271 sys.stdin = Reply('1')
272 assert binary_iface.extra_feeds == []
274 out, err = self.run_0install(['add-feed', 'Source.xml'])
275 assert not err, err
276 assert "Add as feed for 'http://foo/Binary.xml'" in out, out
277 assert len(binary_iface.extra_feeds) == 1
279 out, err = self.run_0install(['list-feeds', binary_iface.uri])
280 assert "Source.xml" in out
281 assert not err, err
283 out, err = self.run_0install(['remove-feed', 'Source.xml'])
284 assert not err, err
285 assert "Remove as feed for 'http://foo/Binary.xml'" in out, out
286 assert len(binary_iface.extra_feeds) == 0
288 source_feed = reader.load_feed('Source.xml')
289 self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed)
290 out, err = self.run_0install(['add-feed', 'http://foo/Source.xml'])
291 assert not err, err
292 assert 'Downloading feed; please wait' in out, out
293 assert len(binary_iface.extra_feeds) == 1
295 def testImport(self):
296 out, err = self.run_0install(['import'])
297 assert out.lower().startswith("usage:")
298 assert 'FEED' in out
300 stream = open('6FCF121BE2390E0B.gpg')
301 gpg.import_key(stream)
302 stream.close()
303 sys.stdin = Reply('Y\n')
304 out, err = self.run_0install(['import', 'Hello.xml'])
305 assert not out, out
306 assert 'Trusting DE937DD411906ACF7C263B396FCF121BE2390E0B for example.com:8000' in err, out
308 def testList(self):
309 out, err = self.run_0install(['list', 'foo', 'bar'])
310 assert out.lower().startswith("usage:")
311 assert 'PATTERN' in out
313 out, err = self.run_0install(['list'])
314 assert not err, err
315 assert '' == out, repr(out)
317 self.testImport()
319 out, err = self.run_0install(['list'])
320 assert not err, err
321 assert 'http://example.com:8000/Hello.xml\n' == out, repr(out)
323 out, err = self.run_0install(['list', 'foo'])
324 assert not err, err
325 assert '' == out, repr(out)
327 out, err = self.run_0install(['list', 'hello'])
328 assert not err, err
329 assert 'http://example.com:8000/Hello.xml\n' == out, repr(out)
331 def testRun(self):
332 out, err = self.run_0install(['run'])
333 assert out.lower().startswith("usage:")
334 assert 'URI' in out, out
336 out, err = self.run_0install(['run', '--dry-run', 'runnable/Runnable.xml', '--help'])
337 assert not err, err
338 assert 'arg-for-runner' in out, out
339 assert '--help' in out, out
341 def testDigest(self):
342 hw = os.path.join(mydir, 'HelloWorld.tgz')
343 out, err = self.run_0install(['digest', '--algorithm=sha1', hw])
344 assert out == 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a\n', out
345 assert not err, err
347 out, err = self.run_0install(['digest', hw])
348 assert out == 'sha1new=290eb133e146635fe37713fd58174324a16d595f\n', out
349 assert not err, err
351 out, err = self.run_0install(['digest', hw, 'HelloWorld'])
352 assert out == 'sha1new=491678c37f77fadafbaae66b13d48d237773a68f\n', out
353 assert not err, err
355 tmp = tempfile.mkdtemp(prefix = '0install')
356 out, err = self.run_0install(['digest', tmp])
357 assert out == 'sha1new=da39a3ee5e6b4b0d3255bfef95601890afd80709\n', out
358 assert not err, err
359 os.rmdir(tmp)
361 def testApps(self):
362 out, err = self.run_0install(['add', 'local-app'])
363 assert out.lower().startswith("usage:")
365 out, err = self.run_0install(['destroy', 'local-app', 'uri'])
366 assert out.lower().startswith("usage:")
368 local_feed = os.path.join(mydir, 'Local.xml')
370 out, err = self.run_0install(['add', 'local:app', local_feed])
371 assert not out, out
372 assert "Invalid application name 'local:app'" in err, err
374 out, err = self.run_0install(['add', 'local-app', local_feed])
375 assert not out, out
376 assert not err, err
378 out, err = self.run_0install(['add', 'local-app', local_feed])
379 assert not out, out
380 assert "Application 'local-app' already exists" in err, err
382 out, err = self.run_0install(['update', 'local-app'])
383 assert "No updates found. Continuing with version 0.1." in out, out
384 assert not err, err
386 out, err = self.run_0install(['destroy', 'local-app'])
387 assert not out, out
388 assert not err, err
390 out, err = self.run_0install(['destroy', 'local-app'])
391 assert not out, out
392 assert "No such application 'local-app'" in err, err
394 if __name__ == '__main__':
395 unittest.main()