2 from basetest
import BaseTest
6 sys
.path
.insert(0, '..')
7 from zeroinstall
.injector
import solver
, arch
8 from zeroinstall
.injector
.requirements
import Requirements
11 logger
= logging
.getLogger()
12 #logger.setLevel(logging.DEBUG)
14 mydir
= os
.path
.dirname(os
.path
.abspath(__file__
))
15 command_dep
= os
.path
.join(mydir
, 'command-dep.xml')
17 class TestSolver(BaseTest
):
19 iface_cache
= self
.config
.iface_cache
20 s
= solver
.DefaultSolver(self
.config
)
22 foo
= iface_cache
.get_interface('http://foo/Binary.xml')
23 self
.import_feed(foo
.uri
, 'Binary.xml')
24 foo_src
= iface_cache
.get_interface('http://foo/Source.xml')
25 self
.import_feed(foo_src
.uri
, 'Source.xml')
26 compiler
= iface_cache
.get_interface('http://foo/Compiler.xml')
27 self
.import_feed(compiler
.uri
, 'Compiler.xml')
29 binary_arch
= arch
.Architecture({None: 1}, {None: 1})
30 assert str(binary_arch
).startswith("<Arch")
31 s
.solve('http://foo/Binary.xml', binary_arch
)
34 assert s
.feeds_used
== set([foo
.uri
]), s
.feeds_used
35 assert s
.selections
[foo
].id == 'sha1=123'
37 # Now ask for source instead
38 s
.solve('http://foo/Binary.xml',
39 arch
.SourceArchitecture(binary_arch
),
40 command_name
= 'compile')
41 assert s
.ready
, s
.get_failure_reason()
42 assert s
.feeds_used
== set([foo
.uri
, foo_src
.uri
, compiler
.uri
]), s
.feeds_used
43 assert s
.selections
[foo
].id == 'sha1=234' # The source
44 assert s
.selections
[compiler
].id == 'sha1=345' # A binary needed to compile it
48 def testCommand(self
):
49 s
= solver
.DefaultSolver(self
.config
)
50 binary_arch
= arch
.Architecture({None: 1}, {None: 1})
51 s
.solve(command_dep
, binary_arch
)
52 command
= s
.selections
.selections
[s
.selections
.interface
].get_command("run")
53 dep
, = command
.requires
54 dep_impl
= s
.selections
.selections
[dep
.interface
]
55 assert dep_impl
.get_command("run").path
== "test-gui"
57 def testDetails(self
):
58 iface_cache
= self
.config
.iface_cache
59 s
= solver
.DefaultSolver(self
.config
)
61 foo_binary_uri
= 'http://foo/Binary.xml'
62 foo
= iface_cache
.get_interface(foo_binary_uri
)
63 self
.import_feed(foo_binary_uri
, 'Binary.xml')
64 foo_src
= iface_cache
.get_interface('http://foo/Source.xml')
65 self
.import_feed(foo_src
.uri
, 'Source.xml')
66 compiler
= iface_cache
.get_interface('http://foo/Compiler.xml')
67 self
.import_feed(compiler
.uri
, 'Compiler.xml')
69 r
= Requirements('http://foo/Binary.xml')
73 s
.record_details
= True
75 assert s
.ready
, s
.get_failure_reason()
77 foo_bin_impls
= iface_cache
.get_feed(foo_binary_uri
).implementations
78 foo_src_impls
= iface_cache
.get_feed(foo_src
.uri
).implementations
79 foo_impls
= iface_cache
.get_feed(foo
.uri
).implementations
80 compiler_impls
= iface_cache
.get_feed(compiler
.uri
).implementations
82 assert len(s
.details
) == 2
84 (foo_src_impls
['impossible'], None),
85 (foo_src_impls
['sha1=234'], None),
86 (foo_impls
['sha1=123'], 'Not source code'),
87 (foo_src_impls
['old'], None),
88 ], sorted(s
.details
[foo
]))
90 (compiler_impls
['sha1=999'], None),
91 (compiler_impls
['sha1=345'], None),
92 (compiler_impls
['sha1=678'], None),
93 ], s
.details
[compiler
])
95 def justify(uri
, impl
, expected
):
96 iface
= iface_cache
.get_interface(uri
)
97 e
= s
.justify_decision(r
, iface
, impl
)
98 self
.assertEqual(expected
, e
)
100 justify(foo_binary_uri
, foo_bin_impls
["sha1=123"],
101 'Binary 1.0 cannot be used (regardless of other components): Not source code')
102 justify(foo_binary_uri
, foo_src_impls
["sha1=234"],
103 'Binary 1.0 was selected as the preferred version.')
104 justify(foo_binary_uri
, foo_src_impls
["old"],
105 'Binary 0.1 is ranked lower than 1.0: newer versions are preferred')
106 justify(foo_binary_uri
, foo_src_impls
["impossible"],
107 '''There is no possible selection using Binary 3.\nCan't find all required implementations:\n- <Interface http://foo/Binary.xml> -> impossible\n- <Interface http://foo/Compiler.xml> -> None''')
108 justify(compiler
.uri
, compiler_impls
["sha1=999"],
109 '''Compiler 5 is selectable, but using it would produce a less optimal solution overall.\n\nThe changes would be:\n\nhttp://foo/Binary.xml: 1.0 to 0.1''')
111 def testRecursive(self
):
112 iface_cache
= self
.config
.iface_cache
113 s
= solver
.DefaultSolver(self
.config
)
115 foo
= iface_cache
.get_interface('http://foo/Recursive.xml')
116 self
.import_feed(foo
.uri
, 'Recursive.xml')
118 binary_arch
= arch
.Architecture({None: 1}, {None: 1})
119 s
.record_details
= True
120 s
.solve('http://foo/Recursive.xml', binary_arch
)
123 foo_impls
= iface_cache
.get_feed(foo
.uri
).implementations
125 assert len(s
.details
) == 1
126 assert s
.details
[foo
] == [(foo_impls
['sha1=abc'], None)]
128 def testMultiArch(self
):
129 iface_cache
= self
.config
.iface_cache
130 s
= solver
.DefaultSolver(self
.config
)
132 foo
= iface_cache
.get_interface('http://foo/MultiArch.xml')
133 self
.import_feed(foo
.uri
, 'MultiArch.xml')
134 lib
= iface_cache
.get_interface('http://foo/MultiArchLib.xml')
135 self
.import_feed(lib
.uri
, 'MultiArchLib.xml')
137 # On an i686 system we can only use the i486 implementation
139 binary_arch
= arch
.get_architecture('Linux', 'i686')
140 s
.solve('http://foo/MultiArch.xml', binary_arch
)
142 assert s
.selections
[foo
].machine
== 'i486'
143 assert s
.selections
[lib
].machine
== 'i486'
145 # On an 64 bit system we could use either, but we prefer the 64
146 # bit implementation. The i486 version of the library is newer,
147 # but we must pick one that is compatible with the main binary.
149 binary_arch
= arch
.get_architecture('Linux', 'x86_64')
150 s
.solve('http://foo/MultiArch.xml', binary_arch
)
152 assert s
.selections
[foo
].machine
== 'x86_64'
153 assert s
.selections
[lib
].machine
== 'x86_64'
156 host_arch
= arch
.get_host_architecture()
157 host_arch2
= arch
.get_architecture(None, None)
158 self
.assertEqual(host_arch
.os_ranks
, host_arch2
.os_ranks
)
159 self
.assertEqual(host_arch
.machine_ranks
, host_arch2
.machine_ranks
)
161 other
= arch
.get_architecture('FooBar', 'i486')
162 self
.assertEqual(3, len(other
.os_ranks
))
164 assert 'POSIX' in other
.os_ranks
165 assert 'FooBar' in other
.os_ranks
166 assert None in other
.os_ranks
167 assert 'i486' in other
.machine_ranks
168 assert 'ppc' not in other
.machine_ranks
170 win
= arch
.get_architecture('Windows', 'i486')
171 self
.assertEqual(2, len(win
.os_ranks
))
172 assert 'POSIX' not in win
.os_ranks
174 def testRanking(self
):
175 iface_cache
= self
.config
.iface_cache
176 s
= solver
.DefaultSolver(self
.config
)
177 ranking
= os
.path
.join(os
.path
.abspath(os
.path
.dirname(__file__
)), 'Ranking.xml')
178 iface
= iface_cache
.get_interface(ranking
)
180 binary_arch
= arch
.get_architecture('Linux', 'x86_64')
183 s
.solve(ranking
, binary_arch
)
186 impl
= s
.selections
[iface
]
187 selected
.append(impl
.get_version() + ' ' + impl
.arch
)
188 impl
.arch
= 'Foo-odd' # prevent reselection
190 '0.2 Linux-i386', # poor arch, but newest version
191 '0.1 Linux-x86_64', # 64-bit is best match for host arch
192 '0.1 Linux-i686', '0.1 Linux-i586', '0.1 Linux-i486'], # ordering of x86 versions
196 iface_cache
= self
.config
.iface_cache
198 locale
.setlocale(locale
.LC_ALL
, 'en_US.UTF-8')
200 s
= solver
.DefaultSolver(self
.config
)
201 iface
= iface_cache
.get_interface('http://foo/Langs.xml')
202 self
.import_feed(iface
.uri
, 'Langs.xml')
204 # 1 is the oldest, but the only one in our language
205 binary_arch
= arch
.get_architecture(None, 'arch_1')
206 s
.solve('http://foo/Langs.xml', binary_arch
)
208 self
.assertEqual('sha1=1', s
.selections
[iface
].id)
210 # 6 is the newest, and close enough, even though not
211 # quite the right locale
212 binary_arch
= arch
.get_architecture(None, 'arch_2')
213 s
.solve('http://foo/Langs.xml', binary_arch
)
215 self
.assertEqual('sha1=6', s
.selections
[iface
].id)
217 # 9 is the newest, although 7 is a closer match
218 binary_arch
= arch
.get_architecture(None, 'arch_3')
219 s
.solve('http://foo/Langs.xml', binary_arch
)
221 self
.assertEqual('sha1=9', s
.selections
[iface
].id)
223 # 11 is the newest we understand
224 binary_arch
= arch
.get_architecture(None, 'arch_4')
225 s
.solve('http://foo/Langs.xml', binary_arch
)
227 self
.assertEqual('sha1=11', s
.selections
[iface
].id)
229 # 13 is the newest we understand
230 binary_arch
= arch
.get_architecture(None, 'arch_5')
231 s
.solve('http://foo/Langs.xml', binary_arch
)
233 self
.assertEqual('sha1=13', s
.selections
[iface
].id)
235 def check(target_arch
, langs
, expected
):
237 binary_arch
= arch
.get_architecture(None, target_arch
)
238 s
.solve('http://foo/Langs.xml', binary_arch
)
240 self
.assertEqual(expected
, s
.selections
[iface
].id)
242 # We don't understand any, so pick the newest
243 check('arch_2', ['es_ES'], 'sha1=6')
245 # These two have the same version number. Choose the
246 # one most appropriate to our country
247 check('arch_6', ['zh_CN'], 'sha1=15')
248 check('arch_6', ['zh_TW'], 'sha1=16')
250 # Same, but one doesn't have a country code
251 check('arch_7', ['bn'], 'sha1=17')
252 check('arch_7', ['bn_IN'], 'sha1=18')
254 locale
.setlocale(locale
.LC_ALL
, '')
256 def testDecideBug(self
):
257 s
= solver
.DefaultSolver(self
.config
)
258 watch_xml
= os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'watchdog.xml')
259 s
.solve(watch_xml
, arch
.get_architecture(None, None), command_name
= 'test')
261 def testRecommendBug(self
):
262 s
= solver
.DefaultSolver(self
.config
)
263 optional_missing_xml
= os
.path
.join(os
.path
.dirname(os
.path
.abspath(__file__
)), 'OptionalMissing.xml')
264 s
.solve(optional_missing_xml
, arch
.get_architecture(None, None), command_name
= None)
266 if __name__
== '__main__':