2 import sys
, tempfile
, os
, shutil
, tempfile
, subprocess
3 from StringIO
import StringIO
5 from zeroinstall
.injector
import model
, qdom
, config
6 from zeroinstall
.support
import ro_rmtree
, basedir
7 from zeroinstall
.zerostore
import Stores
11 mydir
= os
.path
.abspath(os
.path
.dirname(__file__
))
12 sys
.path
.insert(0, os
.path
.dirname(mydir
))
15 hello_uri
= 'http://0install.net/tests/GNU-Hello.xml'
17 mydir
= os
.path
.realpath(os
.path
.dirname(__file__
))
19 hello_selections
= os
.path
.join(mydir
, 'selections.xml')
20 local_bad_version
= os
.path
.join(mydir
, 'bad-version.xml')
21 local_hello_path
= os
.path
.join(mydir
, 'hello2', 'hello2.xml')
22 local_cprog_command_path
= os
.path
.join(mydir
, 'cprog', 'cprog-command.xml')
23 local_cprog_path
= os
.path
.join(mydir
, 'cprog', 'cprog.xml')
24 local_pinned_path
= os
.path
.join(mydir
, 'pinned-version', 'pinned-version.xml')
25 top_build_deps
= os
.path
.join(mydir
, 'top-build-deps.xml')
27 compile_bin
= os
.path
.join(mydir
, '0compile-coverage')
28 assert os
.path
.exists(compile_bin
)
30 if 'DISPLAY' in os
.environ
:
31 del os
.environ
['DISPLAY']
33 launch_command
= [os
.environ
['0COMPILE_0LAUNCH']]
35 # Ensure it's cached now, to avoid extra output during the tests
36 if subprocess
.call(launch_command
+ ['--source', '-c', '--download-only', hello_uri
]):
37 raise Exception("Failed to download hello world test program")
39 def compile(*args
, **kwargs
):
40 run(*([sys
.executable
, compile_bin
] + list(args
)), **kwargs
)
42 def run(*args
, **kwargs
):
43 if not isinstance(args
[0], basestring
):
44 args
= args
[0] + list(args
[1:])
45 child
= subprocess
.Popen(args
, stdout
= subprocess
.PIPE
, stderr
= subprocess
.STDOUT
)
46 got
, unused
= child
.communicate()
48 if code
!= kwargs
.get('expect_status', 0):
49 raise Exception("Exit status %d:\n%s" % (code
, got
))
51 expected
= kwargs
.get('expect', '')
52 if expected
is not None: # pass None to explicily suppress check
54 if expected
.lower() not in got
.lower():
55 raise Exception("Expected '%s', got '%s'" % (expected
, got
))
57 raise Exception("Expected nothing, got '%s'" % got
)
59 # Detect accidental network access
60 os
.environ
['http_proxy'] = 'localhost:1111'
62 for x
in ['GNUPGHOME', 'XDG_CONFIG_HOME', 'XDG_CACHE_HOME', 'XDG_DATA_HOME']:
65 user_cache_dir
= os
.environ
['XDG_CACHE_DIRS'] = basedir
.xdg_cache_home
67 class TestCompile(unittest
.TestCase
):
70 self
.tmpdir
= tempfile
.mkdtemp(prefix
= '0compile-test-')
71 self
.hello_dir
= os
.path
.join(self
.tmpdir
, 'hello')
73 os
.environ
['HOME'] = self
.tmpdir
76 config_dir
= basedir
.save_config_path('0install.net', 'injector')
77 stream
= open(os
.path
.join(config_dir
, 'implementation-dirs'), 'w')
78 for x
in stores
.stores
:
79 stream
.write(x
.dir + '\n')
82 stream
= open(os
.path
.join(config_dir
, 'global'), 'w')
83 stream
.write('[global]\n'
85 'help_with_testing = True\n'
86 'network_use = off-line\n')
90 os
.chdir(os
.path
.join(self
.tmpdir
, os
.path
.pardir
))
91 ro_rmtree(self
.tmpdir
)
93 def testBadCommand(self
):
94 compile('foo', expect
= 'usage: 0compile', expect_status
= 1)
95 compile('setup', hello_uri
, self
.tmpdir
, expect
= 'already exists', expect_status
= 1)
97 compile('setup', expect
= 'Run 0compile from a directory containing', expect_status
= 1)
98 compile('build', expect
= 'Run 0compile from a directory containing', expect_status
= 1)
99 compile('publish', expect
= 'Run 0compile from a directory containing', expect_status
= 1)
101 def testCompileNoDir(self
):
102 os
.chdir(self
.tmpdir
)
103 compile('setup', hello_uri
, expect
= 'Created directory')
104 os
.chdir('GNU-Hello')
106 def testCompile(self
):
107 compile('setup', hello_uri
, self
.hello_dir
, expect
= 'Created directory')
108 os
.chdir(self
.hello_dir
)
110 compile('build', expect
= 'Executing: "%s"' % os
.path
.join('$SRCDIR','configure'))
112 target_dir
= 'gnu-hello-%s' % support
.get_arch_name().lower()
113 archive_stem
= 'gnu-hello-%s-1.3' % support
.get_arch_name().lower()
114 assert os
.path
.isdir(target_dir
), '%s not a directory' % target_dir
116 run(os
.path
.join(target_dir
,'bin','hello'), expect
= 'Hello, world!')
117 run(launch_command
, os
.path
.join(target_dir
,'0install', 'feed.xml'), expect
= 'Hello, world!')
118 compile('publish', 'http://localhost/downloads', expect
= "Now upload '%s.tar.bz2'" % archive_stem
)
120 def testAutocompile(self
):
121 compile('autocompile', hello_uri
, expect
= "site-packages/http/0install.net/tests__GNU-Hello.xml")
122 run(launch_command
, hello_uri
, expect
= 'Hello, world!')
124 def testRecursive(self
):
125 top
= os
.path
.join(mydir
, 'top.xml')
126 compile('autocompile', top
, expect
= "No dependencies need compiling... compile cprog itself...")
128 # Dependency was registered against its local path, since that was how we depended on it:
129 run(launch_command
, os
.path
.join(mydir
, 'cprog/cprog-command.xml'), expect
= 'Hello from C')
131 # But the top-level feed was registered against its <feed-for>:
132 c
= config
.load_config()
133 i
= c
.iface_cache
.get_interface('http://example.com/top.xml')
134 self
.assertEquals(1, len(i
.extra_feeds
))
137 compile('setup', local_hello_path
, self
.hello_dir
, expect
= 'Created directory')
138 os
.chdir(self
.hello_dir
)
139 compile('build', expect
= 'Executing: ls -l')
140 target_dir
= 'hello2-any-any'
141 assert os
.path
.isdir(target_dir
), '%s not a directory' % target_dir
143 run(launch_command
, os
.path
.join(target_dir
, '0install', 'feed.xml'), expect
= 'ROX-Lib')
145 def testBadVersion(self
):
146 compile('setup', local_bad_version
, self
.hello_dir
, expect
= 'Created directory')
147 os
.chdir(self
.hello_dir
)
148 compile('build', expect
= 'hello2-0.1 requires 0compile >= 300000', expect_status
= 1)
150 def testCommand(self
):
151 comp_dir
= os
.path
.join(self
.tmpdir
, 'cprog-command')
152 compile('setup', local_cprog_command_path
, comp_dir
, expect
= 'Created directory')
154 compile('build', expect
= 'Hello from C!')
155 target_dir
= 'cprog-command-%s' % support
.get_arch_name().lower()
156 binary_feed
= os
.path
.join(target_dir
, '0install', 'feed.xml')
157 run(launch_command
, binary_feed
, expect
= 'Hello from C!')
158 s
= open(binary_feed
, 'r')
159 feed
= model
.ZeroInstallFeed(qdom
.parse(s
), binary_feed
)
161 impl
, = feed
.implementations
.values()
162 assert impl
.arch
, "Missing arch on %s" % impl
163 self
.assertEqual("Public Domain", str(impl
.metadata
['license']))
165 def testCopySrc(self
):
166 comp_dir
= os
.path
.join(self
.tmpdir
, 'cprog')
167 compile('setup', local_cprog_path
, comp_dir
, expect
= 'Created directory')
169 compile('diff', expect
= "No local src directory to diff against", expect_status
= 1)
170 compile('diff', 'foo', expect
= 'usage', expect_status
= 1)
171 compile('copy-src', 'foo', expect
= 'usage', expect_status
= 1)
172 compile('copy-src', expect
= 'Copied as')
173 compile('copy-src', expect
= "Directory '", expect_status
= 1)
175 # 'src' exists, but no changes
177 compile('--verbose', 'build', expect
= 'Hello from C')
178 target_dir
= 'cprog-%s' % support
.get_arch_name().lower()
179 patch_file
= os
.path
.join(target_dir
, '0install', 'from-0.1.patch')
180 assert not os
.path
.exists(patch_file
)
182 # 'src' contains a change
183 prog
= file(os
.path
.join('src','main.c')).read()
184 prog
= prog
.replace('Hello', 'Goodbye')
185 stream
= file(os
.path
.join('src','main.c'), 'w')
188 compile('diff', expect
= 'diff')
189 shutil
.rmtree('build')
190 compile('build', expect
= 'Goodbye from C')
191 assert os
.path
.exists(patch_file
)
193 # Test dup-src's unlinking while we're here
194 compile('build', expect
= 'Goodbye from C')
196 # 'src' contains an error
197 stream
= file(os
.path
.join('src','main.c'), 'w')
198 stream
.write('this is not valid C!')
200 shutil
.rmtree('build')
201 compile('build', expect
= 'Build failed', expect_status
= 1)
202 assert os
.path
.exists(os
.path
.join('build', 'build-failure.log'))
204 # 'src' does not exist
206 shutil
.rmtree('build')
207 compile('build', expect
= 'Hello from C')
208 assert not os
.path
.exists(patch_file
)
210 # Check we fixed the .pc files...
211 pc_data
= open(os
.path
.join(target_dir
, 'pkgconfig', 'cprog.pc')).read()
212 assert pc_data
== "prefix=" + os
.path
.join("${pcfiledir}",os
.path
.pardir
) + "\n", `pc_data`
214 # Check we removed the bad .la files...
215 assert not os
.path
.exists(os
.path
.join(target_dir
, 'lib', 'bad.la')) # libtool - bad
216 assert os
.path
.exists(os
.path
.join(target_dir
, 'lib', 'good.la')) # Ends in .la, but not a libtool archive
217 assert os
.path
.exists(os
.path
.join(target_dir
, 'lib', 'nice.ok')) # Doesn't end in .la
219 def testInlcudeDeps(self
):
220 compile('setup', hello_uri
, self
.hello_dir
, expect
= 'Created directory')
221 os
.chdir(self
.hello_dir
)
222 os
.unlink('0compile.properties')
223 compile('setup', hello_uri
, '.')
224 compile('include-deps', expect
= 'dependencies to')
225 compile('include-deps', expect
= 'Copied 0 depend')
228 compile('setup', hello_selections
, self
.hello_dir
,
229 expect
= 'Created directory')
230 compile('setup', hello_selections
, self
.hello_dir
,
231 expect
= "Directory '", expect_status
= 1)
232 compile('setup', hello_selections
, '.', 'foo',
233 expect
= "usage", expect_status
= 1)
234 os
.chdir(self
.hello_dir
)
235 compile('setup', expect
= "Selections are fixed", expect_status
= 1)
237 def testReportBug(self
):
238 broken_src
= os
.path
.join(self
.hello_dir
, "broken.xml")
239 os
.mkdir(self
.hello_dir
)
240 shutil
.copy(local_hello_path
, broken_src
)
241 os
.chdir(self
.hello_dir
)
242 compile('setup', broken_src
, '.')
243 compile('build', expect
= 'Build failed with exit code', expect_status
= 1)
244 compile('report-bug', expect
= "http://0install.net/api/report-bug")
246 env
= support
.BuildEnv()
247 os
.unlink(os
.path
.join(env
.metadir
, "build-environment.xml"))
248 compile('report-bug', expect
= "file+not+found")
250 def testBuildDeps(self
):
251 compile('autocompile', top_build_deps
, expect
= "build-deps.xml 0.1 requires 3 <= version < 3", expect_status
= 1)
253 def testPinVersions(self
):
254 dest
= os
.path
.join(self
.tmpdir
, 'pinned_version')
255 compile('setup', local_pinned_path
, dest
, expect
= 'Created directory')
257 compile('build', expect
=None)
258 env
= support
.BuildEnv()
259 python_version
= subprocess
.check_output(launch_command
+ [env
.local_iface_file
]).strip()
260 major
, minor
= map(int, python_version
.split("."))
261 version_limit
= "%d.%d" % (major
, minor
+1)
263 def check_feed(path
):
265 Check that the feed has the restriction:
266 <version not-before="maj.minor" before="maj.minor+1"/>
268 from xml
.dom
import minidom
269 with
open(path
) as f
:
270 dom
= minidom
.parse(f
)
271 version_tags
= dom
.documentElement
.getElementsByTagName('version')
272 assert len(version_tags
) == 1, version_tags
273 version_tag
= version_tags
[0]
275 self
.assertEquals(version_tag
.getAttribute("not-before"), python_version
)
276 self
.assertEquals(version_tag
.getAttribute("before"), version_limit
)
278 check_feed(env
.local_iface_file
)
280 compile('publish', 'http://localhost/downloads', expect
=None)
281 check_feed('pinned-version-0.1.xml')
283 suite
= unittest
.makeSuite(TestCompile
)
284 if __name__
== '__main__':