WIP: Added Driver and Settings objects to clean up API
[zeroinstall.git] / tests / testinstall.py
blobd9b841c3ea6b632656ae0ea2d403fe596473a19c
1 #!/usr/bin/env python
2 from basetest import BaseTest, TestStores
3 import sys
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 class Reply:
12 def __init__(self, reply):
13 self.reply = reply
15 def readline(self):
16 return self.reply
18 class TestInstall(BaseTest):
19 def run_0install(self, args):
20 old_stdout = sys.stdout
21 old_stderr = sys.stderr
22 try:
23 sys.stdout = StringIO()
24 sys.stderr = StringIO()
25 ex = None
26 try:
27 cmd.main(args, config = self.config)
28 except NameError:
29 raise
30 except SystemExit:
31 pass
32 except TypeError:
33 raise
34 except AttributeError:
35 raise
36 except AssertionError:
37 raise
38 except Exception, ex:
39 pass
40 out = sys.stdout.getvalue()
41 err = sys.stderr.getvalue()
42 if ex is not None:
43 err += str(ex.__class__)
44 finally:
45 sys.stdout = old_stdout
46 sys.stderr = old_stderr
47 return (out, err)
49 def testHelp(self):
50 out, err = self.run_0install([])
51 assert out.lower().startswith("usage:")
52 assert 'add-feed' in out
53 assert '--version' in out
54 assert not err, err
56 out2, err = self.run_0install(['--help'])
57 assert not err, err
58 assert out2 == out
60 out, err = self.run_0install(['--version'])
61 assert 'Thomas Leonard' in out
62 assert not err, err
64 out, err = self.run_0install(['foobar'])
65 assert 'Unknown sub-command' in err, err
67 def testSelect(self):
68 out, err = self.run_0install(['select'])
69 assert out.lower().startswith("usage:")
70 assert '--xml' in out
72 out, err = self.run_0install(['select', 'Local.xml'])
73 assert not err, err
74 assert 'Version: 0.1' in out
76 local_uri = model.canonical_iface_uri('Local.xml')
77 out, err = self.run_0install(['select', 'Local.xml'])
78 assert not err, err
79 assert 'Version: 0.1' in out
81 out, err = self.run_0install(['select', 'Local.xml', '--xml'])
82 sels = selections.Selections(qdom.parse(StringIO(str(out))))
83 assert sels.selections[local_uri].version == '0.1'
85 out, err = self.run_0install(['select', 'selections.xml'])
86 assert not err, err
87 assert 'Version: 1\n' in out
88 assert '(not cached)' in out
90 def testDownload(self):
91 out, err = self.run_0install(['download'])
92 assert out.lower().startswith("usage:")
93 assert '--show' in out
95 out, err = self.run_0install(['download', 'Local.xml', '--show'])
96 assert not err, err
97 assert 'Version: 0.1' in out
99 local_uri = model.canonical_iface_uri('Local.xml')
100 out, err = self.run_0install(['download', 'Local.xml', '--xml'])
101 assert not err, err
102 sels = selections.Selections(qdom.parse(StringIO(str(out))))
103 assert sels.selections[local_uri].version == '0.1'
105 out, err = self.run_0install(['download', 'Local.xml', '--show', '--with-store=/foo'])
106 assert not err, err
107 assert self.config.stores.stores[-1].dir == '/foo'
109 out, err = self.run_0install(['download', '--offline', 'selections.xml'])
110 assert 'Would download' in err
111 self.config.network_use = model.network_full
113 self.config.stores = TestStores()
114 digest = 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
115 self.config.fetcher.allow_download(digest)
116 out, err = self.run_0install(['download', 'Hello.xml', '--show'])
117 assert not err, err
118 assert self.config.stores.lookup_any([digest]).startswith('/fake')
119 assert 'Version: 1\n' in out
121 out, err = self.run_0install(['download', '--offline', 'selections.xml', '--show'])
122 assert '/fake_store' in out
123 self.config.network_use = model.network_full
125 def testDownloadSelections(self):
126 self.config.stores = TestStores()
127 digest = 'sha1=3ce644dc725f1d21cfcf02562c76f375944b266a'
128 self.config.fetcher.allow_download(digest)
129 hello = reader.load_feed('Hello.xml')
130 self.config.fetcher.allow_feed_download('http://example.com:8000/Hello.xml', hello)
131 out, err = self.run_0install(['download', 'selections.xml', '--show'])
132 assert not err, err
133 assert self.config.stores.lookup_any([digest]).startswith('/fake')
134 assert 'Version: 1\n' in out
136 def testUpdate(self):
137 out, err = self.run_0install(['update'])
138 assert out.lower().startswith("usage:")
139 assert '--message' in out, out
141 # Updating a local feed with no dependencies
142 out, err = self.run_0install(['update', 'Local.xml'])
143 assert not err, err
144 assert 'No updates found' in out, out
146 # Using a remote feed for the first time
147 self.config.stores = TestStores()
148 self.config.driver_factory.stores = self.config.stores
149 binary_feed = reader.load_feed('Binary.xml')
150 self.config.fetcher.allow_download('sha1=123')
151 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
152 out, err = self.run_0install(['update', 'http://foo/Binary.xml'])
153 assert not err, err
154 assert 'Binary.xml: new -> 1.0' in out, out
156 # No updates.
157 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
158 out, err = self.run_0install(['update', 'http://foo/Binary.xml'])
159 assert not err, err
160 assert 'No updates found' in out, out
162 # New binary release available.
163 new_binary_feed = reader.load_feed('Binary.xml')
164 new_binary_feed.implementations['sha1=123'].version = model.parse_version('1.1')
165 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', new_binary_feed)
166 out, err = self.run_0install(['update', 'http://foo/Binary.xml'])
167 assert not err, err
168 assert 'Binary.xml: 1.0 -> 1.1' in out, out
170 # Compiling from source for the first time.
171 source_feed = reader.load_feed('Source.xml')
172 compiler_feed = reader.load_feed('Compiler.xml')
173 self.config.fetcher.allow_download('sha1=234')
174 self.config.fetcher.allow_download('sha1=345')
175 self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', compiler_feed)
176 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
177 self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed)
178 out, err = self.run_0install(['update', 'http://foo/Binary.xml', '--source'])
179 assert not err, err
180 assert 'Binary.xml: new -> 1.0' in out, out
181 assert 'Compiler.xml: new -> 1.0' in out, out
183 # New compiler released.
184 new_compiler_feed = reader.load_feed('Compiler.xml')
185 new_compiler_feed.implementations['sha1=345'].version = model.parse_version('1.1')
186 self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', new_compiler_feed)
187 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
188 self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed)
189 out, err = self.run_0install(['update', 'http://foo/Binary.xml', '--source'])
190 assert not err, err
191 assert 'Compiler.xml: 1.0 -> 1.1' in out, out
193 # A dependency disappears.
194 new_source_feed = reader.load_feed('Source.xml')
195 new_source_feed.implementations['sha1=234'].requires = []
196 self.config.fetcher.allow_feed_download('http://foo/Compiler.xml', new_compiler_feed)
197 self.config.fetcher.allow_feed_download('http://foo/Binary.xml', binary_feed)
198 self.config.fetcher.allow_feed_download('http://foo/Source.xml', new_source_feed)
199 out, err = self.run_0install(['update', 'http://foo/Binary.xml', '--source'])
200 assert not err, err
201 assert 'No longer used: http://foo/Compiler.xml' in out, out
203 def testConfig(self):
204 out, err = self.run_0install(['config', '--help'])
205 assert out.lower().startswith("usage:")
206 assert '--console' in out
208 out, err = self.run_0install(['config'])
209 assert not err, err
210 assert 'full' in out, out
211 assert 'freshness = 0' in out, out
212 assert 'help_with_testing = False' in out, out
214 out, err = self.run_0install(['config', 'help_with_testing'])
215 assert out == 'False\n', out
217 file_config = policy.load_config(handler.Handler())
218 def get_value(name):
219 old_stdout = sys.stdout
220 sys.stdout = StringIO()
221 try:
222 cmd.config.handle(file_config, None, [name])
223 cmd_output = sys.stdout.getvalue()
224 finally:
225 sys.stdout = old_stdout
226 return cmd_output
228 assert get_value('freshness') == '30d\n'
229 assert get_value('network_use') == 'full\n'
230 assert get_value('help_with_testing') == 'False\n'
232 cmd.config.handle(file_config, None, ['freshness', '5m'])
233 cmd.config.handle(file_config, None, ['help_with_testing', 'True'])
234 cmd.config.handle(file_config, None, ['network_use', 'minimal'])
235 assert file_config.freshness == 5 * 60
236 assert file_config.network_use == model.network_minimal
237 assert file_config.help_with_testing == True
239 file_config2 = policy.load_config(handler.Handler())
240 assert file_config2.freshness == 5 * 60
241 assert file_config2.network_use == model.network_minimal
242 assert file_config2.help_with_testing == True
244 cmd.config.handle(file_config, None, ['help_with_testing', 'falsE'])
245 assert file_config.help_with_testing == False
247 for period in ['1s', '2d', '3.5m', '4h', '5d']:
248 secs = cmd.config.TimeInterval.parse(period)
249 assert cmd.config.TimeInterval.format(secs) == period
251 def testAddFeed(self):
252 binary_iface = self.config.iface_cache.get_interface('http://foo/Binary.xml')
254 out, err = self.run_0install(['list-feeds', binary_iface.uri])
255 assert "(no feeds)" in out, out
256 assert not err, err
258 out, err = self.run_0install(['add-feed'])
259 assert out.lower().startswith("usage:")
260 assert 'NEW-FEED' in out
262 sys.stdin = Reply('1')
263 assert binary_iface.extra_feeds == []
265 out, err = self.run_0install(['add-feed', 'Source.xml'])
266 assert not err, err
267 assert "Add as feed for 'http://foo/Binary.xml'" in out, out
268 assert len(binary_iface.extra_feeds) == 1
270 out, err = self.run_0install(['list-feeds', binary_iface.uri])
271 assert "Source.xml" in out
272 assert not err, err
274 out, err = self.run_0install(['remove-feed', 'Source.xml'])
275 assert not err, err
276 assert "Remove as feed for 'http://foo/Binary.xml'" in out, out
277 assert len(binary_iface.extra_feeds) == 0
279 source_feed = reader.load_feed('Source.xml')
280 self.config.fetcher.allow_feed_download('http://foo/Source.xml', source_feed)
281 out, err = self.run_0install(['add-feed', 'http://foo/Source.xml'])
282 assert not err, err
283 assert 'Downloading feed; please wait' in out, out
284 assert len(binary_iface.extra_feeds) == 1
286 def testImport(self):
287 out, err = self.run_0install(['import'])
288 assert out.lower().startswith("usage:")
289 assert 'FEED' in out
291 stream = file('6FCF121BE2390E0B.gpg')
292 gpg.import_key(stream)
293 stream.close()
294 sys.stdin = Reply('Y\n')
295 out, err = self.run_0install(['import', 'Hello.xml'])
296 assert not out, out
297 assert 'Trusting DE937DD411906ACF7C263B396FCF121BE2390E0B for example.com:8000' in err, out
299 def testList(self):
300 out, err = self.run_0install(['list', 'foo', 'bar'])
301 assert out.lower().startswith("usage:")
302 assert 'PATTERN' in out
304 out, err = self.run_0install(['list'])
305 assert not err, err
306 assert '' == out, repr(out)
308 self.testImport()
310 out, err = self.run_0install(['list'])
311 assert not err, err
312 assert 'http://example.com:8000/Hello.xml\n' == out, repr(out)
314 out, err = self.run_0install(['list', 'foo'])
315 assert not err, err
316 assert '' == out, repr(out)
318 out, err = self.run_0install(['list', 'hello'])
319 assert not err, err
320 assert 'http://example.com:8000/Hello.xml\n' == out, repr(out)
322 def testRun(self):
323 out, err = self.run_0install(['run'])
324 assert out.lower().startswith("usage:")
325 assert 'URI' in out, out
327 out, err = self.run_0install(['run', '--dry-run', 'runnable/Runnable.xml', '--help'])
328 assert not err, err
329 assert 'arg-for-runner' in out, out
330 assert '--help' in out, out
332 if __name__ == '__main__':
333 unittest.main()