Fixed merge algorithm for <command> elements
[0publish.git] / tests / testlocal.py
blob8d7632971a5ebd0b4372b3cfeb5aa190347079b1
1 #!/usr/bin/env python
2 import sys, os, tempfile, StringIO
3 from zeroinstall.injector.namespaces import XMLNS_IFACE
4 from zeroinstall.injector.reader import InvalidInterface
5 from zeroinstall.injector import model, reader, qdom
6 import unittest
7 from xml.dom import minidom
9 sys.path.insert(0, '..')
11 import create, merge, release
13 header = """<?xml version="1.0" ?>
14 <interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface"
15 uri='http://test/hello.xml'>
16 <name>test</name>
17 <summary>for testing</summary>
18 <description>This is for testing.</description>
19 """
20 footer = """
21 </interface>
22 """
24 def parse(xml):
25 dom = minidom.parseString(xml)
26 uri = dom.documentElement.getAttribute('uri')
27 assert uri
29 tmp = tempfile.NamedTemporaryFile(prefix = 'test-')
30 try:
31 tmp.write(xml)
32 tmp.flush()
33 iface = model.Interface(uri)
34 reader.update(iface, tmp.name, local = True)
35 return iface
36 finally:
37 tmp.close()
39 local_file = os.path.join(os.path.dirname(__file__), 'local.xml')
40 local_file_req = os.path.join(os.path.dirname(__file__), 'local-req.xml')
41 local_file_command = os.path.join(os.path.dirname(__file__), 'local-command.xml')
42 local_file_zi13 = os.path.join(os.path.dirname(__file__), 'zeroinstall-injector-1.3.xml')
44 def tap(s):
45 #print s
46 return s
48 class TestLocal(unittest.TestCase):
49 def testCreate(self):
50 master = parse(create.create_from_local(local_file))
51 assert master.uri == 'http://test/hello.xml', master
52 assert len(master.implementations) == 1
54 def testMergeFirst(self):
55 master = parse(merge.merge(header + footer, local_file))
56 assert master.uri == 'http://test/hello.xml', master
57 assert len(master.implementations) == 1
59 def testMergeSecond(self):
60 master = parse(merge.merge(header + "<implementation id='sha1=123' version='1'/>" + footer, local_file))
61 assert master.uri == 'http://test/hello.xml', master
62 assert len(master.implementations) == 2
64 def testMergeGroup(self):
65 master = parse(merge.merge(header + "<group>\n <implementation id='sha1=123' version='1'/>\n </group>" + footer, local_file))
66 assert master.uri == 'http://test/hello.xml', master
67 assert len(master.implementations) == 2
68 assert master.implementations['sha1=002'].requires == []
70 def testMergeLocalReq(self):
71 master = parse(tap(merge.merge(header + "<group x='x'>\n <implementation id='sha1=123' version='1'/>\n </group>" + footer, local_file_req)))
72 assert master.uri == 'http://test/hello.xml', master
73 assert len(master.implementations) == 2
74 deps = master.implementations['sha1=003'].requires
75 assert len(deps) == 1
76 assert deps[0].interface == 'http://foo', deps[0]
78 assert master.implementations['sha1=003'].metadata['http://mynamespace/foo bob'] == 'bob'
80 def testNotSubset(self):
81 master = parse(merge.merge(header + "<group a='a'>\n <implementation id='sha1=123' version='1'/>\n </group>" + footer, local_file))
82 assert master.uri == 'http://test/hello.xml', master
83 assert len(master.implementations) == 2
84 assert master.implementations['sha1=123'].metadata.get('a', None) == 'a'
85 assert master.implementations['sha1=002'].metadata.get('a', None) == None
87 master = parse(merge.merge(header + """\n
88 <group>
89 <requires interface='http://foo' meta='foo'/>
90 <implementation id='sha1=004' version='1'/>
91 </group>
92 <group>
93 <requires interface='http://foo'>
94 <version before='1'/>
95 </requires>
96 <implementation id='sha1=001' version='1'/>
97 </group>""" + footer, local_file_req))
98 assert len(master.implementations['sha1=001'].requires[0].restrictions) == 1
99 assert len(master.implementations['sha1=003'].requires[0].restrictions) == 0
101 assert master.implementations['sha1=004'].requires[0].metadata.get('meta', None) == 'foo'
102 assert master.implementations['sha1=003'].requires[0].metadata.get('meta', None) == None
104 assert master.implementations['sha1=003'].main == 'hello'
106 def testMergeBest(self):
107 master_xml = merge.merge(header + """\n
108 <group>
109 <implementation id='sha1=123' version='1'/>
110 </group>
111 <group>
112 <requires interface='http://foo'/>
113 <implementation id='sha1=002' version='2'/>
114 </group>""" + footer, local_file_req)
115 master = parse(master_xml)
116 assert master.uri == 'http://test/hello.xml', master
117 assert len(master.implementations) == 3
118 deps = master.implementations['sha1=003'].requires
119 assert len(deps) == 1
120 assert deps[0].interface == 'http://foo', deps[0]
122 assert len(minidom.parseString(master_xml).documentElement.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 2
124 # Again, but with the groups the other way around
125 master_xml = merge.merge(header + """\n
126 <group>
127 <requires interface='http://foo'/>
128 <implementation id='sha1=002' version='2'/>
129 </group>
130 <group>
131 <implementation id='sha1=123' version='1'/>
132 </group>""" + footer, local_file_req)
133 master = parse(master_xml)
134 assert master.uri == 'http://test/hello.xml', master
135 assert len(master.implementations) == 3
136 deps = master.implementations['sha1=003'].requires
137 assert len(deps) == 1
138 assert deps[0].interface == 'http://foo', deps[0]
140 assert len(minidom.parseString(master_xml).documentElement.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 2
142 def testMergeCommand(self):
143 # We create a new group inside this one, sharing the <requires> and adding the <command>
144 master_xml = merge.merge(header + """
145 <group>
146 <requires interface='http://foo'>
147 <environment name='TESTING' value='true' mode='replace'/>
148 </requires>
149 <implementation id='sha1=002' version='2'/>
150 </group>""" + footer, local_file_command)
151 master = parse(master_xml)
152 assert master.uri == 'http://test/hello.xml', master
153 assert len(master.implementations) == 2
154 commands = master.implementations['sha1=003'].commands
155 assert len(commands) == 1
156 assert commands['run'].path == 'run.sh', commands['run'].path
158 new_root = minidom.parseString(master_xml).documentElement
159 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 2
160 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'requires')) == 1
161 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'command')) == 1
163 # We create a new top-level group inside this one, as we can't share the test command
164 master_xml = merge.merge(header + """
165 <group>
166 <requires interface='http://foo'>
167 <environment name='TESTING' value='true' mode='replace'/>
168 </requires>
169 <command name='test' path='test.sh'/>
170 <implementation id='sha1=002' version='2'/>
171 </group>""" + footer, local_file_command)
172 master = parse(master_xml)
173 assert master.uri == 'http://test/hello.xml', master
174 assert len(master.implementations) == 2
175 commands = master.implementations['sha1=003'].commands
176 assert len(commands) == 1
177 assert commands['run'].path == 'run.sh', commands['run'].path
179 new_root = minidom.parseString(master_xml).documentElement
180 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 2
181 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'requires')) == 2
182 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'command')) == 2
184 # We share the <requires> and override the <command>
185 master_xml = merge.merge(header + """
186 <group>
187 <requires interface='http://foo'>
188 <environment name='TESTING' value='true' mode='replace'/>
189 </requires>
190 <command name='run' path='old-run.sh'/>
191 <implementation id='sha1=002' version='2'/>
192 </group>""" + footer, local_file_command)
193 master = parse(master_xml)
194 assert master.uri == 'http://test/hello.xml', master
195 assert len(master.implementations) == 2
196 commands = master.implementations['sha1=003'].commands
197 assert len(commands) == 1
198 assert commands['run'].path == 'run.sh', commands['run'].path
200 new_root = minidom.parseString(master_xml).documentElement
201 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 2
202 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'requires')) == 1
203 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'command')) == 2
205 # We share the <requires> and the <command>
206 master_xml = merge.merge(header + """
207 <group>
208 <requires interface='http://foo'>
209 <environment name='TESTING' value='true' mode='replace'/>
210 </requires>
211 <command name='run' path='run.sh'/>
212 <implementation id='sha1=002' version='2'/>
213 </group>""" + footer, local_file_command)
214 master = parse(master_xml)
215 assert master.uri == 'http://test/hello.xml', master
216 assert len(master.implementations) == 2
217 commands = master.implementations['sha1=003'].commands
218 assert len(commands) == 1
219 assert commands['run'].path == 'run.sh', commands['run'].path
221 new_root = minidom.parseString(master_xml).documentElement
222 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 1
223 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'requires')) == 1
224 assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'command')) == 1
226 def testMerge2(self):
227 master_xml = merge.merge(header + """
228 <group license="OSI Approved :: GNU Lesser General Public License (LGPL)" main="0launch">
229 <command name="run" path="0launch">
230 <runner interface="http://repo.roscidus.com/python/python">
231 <version before="3"/>
232 </runner>
233 </command>
235 <group>
236 <command name="run" path="0launch"/>
237 <implementation id="sha1new=7d1ecfbd76a42d56f029f9d0c72e4ac26c8561de" released="2011-07-23" version="1.2"/>
238 </group>
239 </group>
240 """ + footer, local_file_zi13)
241 doc = minidom.parseString(master_xml)
243 n_groups = len(doc.getElementsByTagName("group"))
244 assert n_groups == 2
246 def testLocalContext(self):
247 def get_context(xml_frag):
248 doc = minidom.parseString(header + xml_frag + footer)
249 impls = list(doc.getElementsByTagNameNS(XMLNS_IFACE, 'implementation'))
250 assert len(impls) == 1
251 return merge.Context(impls[0])
253 ctx = get_context("<implementation id='sha1=001' version='1'/>")
254 assert ctx.attribs[(None, 'id')] == 'sha1=001'
255 assert ctx.attribs[(None, 'version')] == '1'
257 ctx = get_context("<group t='t' x='1' y:z='2' xmlns:y='yns'><implementation id='sha1=001' version='1' t='r'/></group>")
258 assert ctx.attribs[(None, 'id')] == 'sha1=001'
259 assert ctx.attribs[(None, 'version')] == '1'
260 assert ctx.attribs[(None, 't')] == 'r'
261 assert ctx.attribs[(None, 'x')] == '1'
262 assert ctx.attribs[('yns', 'z')] == '2'
264 def testSetAtttibs(self):
265 local_data = open(local_file).read()
266 result = release.set_attributes(local_data, '0.2', id = 'sha1=98765', version='3.7', main = None)
267 feed = model.ZeroInstallFeed(qdom.parse(StringIO.StringIO(str(result))), "local.xml")
268 assert len(feed.implementations) == 1
269 assert feed.implementations['sha1=98765'].get_version() == '3.7'
271 try:
272 result = release.set_attributes(local_data, '0.3', id = 'sha1=98765', version='3.7', main = None)
273 assert 0
274 except Exception, ex:
275 assert str(ex) == 'No implementations with version=0.3'
277 suite = unittest.makeSuite(TestLocal)
278 if __name__ == '__main__':
279 unittest.main()