30719fad36e30020466e00cb62abc2be9aebc55a
2 # Copyright (C) 2007, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
4 import sys
, os
, shutil
, tempfile
, subprocess
, imp
5 from StringIO
import StringIO
8 from zeroinstall
.injector
import model
, qdom
, writer
9 from zeroinstall
.injector
.config
import load_config
10 from zeroinstall
.support
import basedir
, ro_rmtree
12 sys
.path
.insert(0, '..')
13 os
.environ
['http_proxy'] = 'localhost:1111' # Prevent accidental network access
16 import release
# (sets sys.path for 0repo)
19 mydir
= os
.path
.realpath(os
.path
.dirname(__file__
))
20 release_feed
= mydir
+ '/../0release.xml'
21 test_repo
= mydir
+ '/test-repo.tgz'
22 test_repo_actions
= mydir
+ '/test-repo-actions.tgz'
23 test_repo_c
= mydir
+ '/c-prog.tgz'
24 test_gpg
= mydir
+ '/gpg.tgz'
29 auto_approve_keys = True
30 help_with_testing = True
34 CUSTOM_REPO_CONFIG
= """
35 REPOSITORY_BASE_URL = "http://0install.net/tests/"
36 ARCHIVES_BASE_URL = "http://TESTING/releases"
38 def upload_archives(archives):
39 for dir_rel_url, files in paths.group_by_target_url_dir(archives):
40 target_dir = join('..', 'releases', 'archives') # hack: skip dir_rel_url
41 if not os.path.isdir(target_dir):
42 os.makedirs(target_dir)
43 subprocess.check_call(["cp"] + files + [target_dir])
45 def check_new_impl(impl):
48 def get_archive_rel_url(archive_basename, impl):
49 return "{version}/{archive}".format(
50 version = impl.get_version(),
51 archive = archive_basename)
53 def check_uploaded_archive(archive, url):
57 def call_with_output_suppressed(cmd
, stdin
, expect_failure
= False, **kwargs
):
58 #cmd = [cmd[0], '-v'] + cmd[1:]
60 child
= subprocess
.Popen(cmd
, stdin
= subprocess
.PIPE
, stdout
= subprocess
.PIPE
, **kwargs
)
62 child
= subprocess
.Popen(cmd
, stdout
= subprocess
.PIPE
, **kwargs
)
63 stdout
, stderr
= child
.communicate(stdin
)
64 if (child
.returncode
!= 0) == expect_failure
:
67 raise Exception("Return code %d from %s\nstdout: %s\nstderr: %s" % (child
.returncode
, cmd
, stdout
, stderr
))
69 def make_releases_dir(src_feed
= '../hello/HelloWorld.xml', auto_upload
= False):
71 call_with_output_suppressed(['0release', src_feed
], None)
72 assert os
.path
.isfile('make-release')
74 lines
= file('make-release').readlines()
75 lines
[lines
.index('ARCHIVE_DIR_PUBLIC_URL=\n')] = 'ARCHIVE_DIR_PUBLIC_URL=http://TESTING/releases/\\$RELEASE_VERSION\n'
77 # Force us to test against this version of 0release
78 for i
, line
in enumerate(lines
):
79 if line
.startswith('exec 0launch http://0install.net/2007/interfaces/0release.xml --release'):
80 lines
[i
] = '0release --release ' + line
.split('--release ', 1)[1]
87 lines
[lines
.index('ARCHIVE_UPLOAD_COMMAND=\n')] = 'ARCHIVE_UPLOAD_COMMAND=\'cp "$@" ../archives/\'\n'
89 s
= file('make-release', 'w')
90 s
.write(''.join(lines
))
93 class TestRelease(unittest
.TestCase
):
95 self
.tmp
= tempfile
.mkdtemp(prefix
= '0release-')
97 support
.check_call(['tar', 'xzf', test_gpg
])
99 os
.environ
['GNUPGHOME'] = self
.tmp
+ '/gpg'
100 os
.chmod(os
.environ
['GNUPGHOME'], 0700)
102 config_dir
= os
.path
.join(self
.tmp
, 'config')
103 injector_config
= os
.path
.join(config_dir
, '0install.net', 'injector')
104 os
.makedirs(injector_config
)
105 s
= open(os
.path
.join(injector_config
, 'global'), 'w')
109 if 'ZEROINSTALL_PORTABLE_BASE' in os
.environ
:
110 del os
.environ
['ZEROINSTALL_PORTABLE_BASE']
111 os
.environ
['XDG_CONFIG_HOME'] = config_dir
113 assert basedir
.xdg_config_home
== config_dir
119 def testSimple(self
):
120 support
.check_call(['tar', 'xzf', test_repo
])
123 call_with_output_suppressed(['./make-release', '-k', 'Testing'], '\nP\n\n')
125 call_with_output_suppressed(['./make-release', '-k', 'Testing'], '\nP\nY\n\n')
127 assert 'Prints "Hello World"' in file('0.1/changelog-0.1').read()
128 assert 'Prints "Hello World"' not in file('0.2/changelog-0.2').read()
130 def testUncommitted(self
):
131 support
.check_call(['tar', 'xzf', test_repo_actions
])
134 unused
, stderr
= call_with_output_suppressed(['./make-release', '-k', 'Testing'], None,
135 expect_failure
= True, stderr
= subprocess
.PIPE
)
136 assert "Uncommitted changes!" in stderr
138 def testActions(self
):
139 support
.check_call(['tar', 'xzf', test_repo_actions
])
141 support
.check_call(['git', 'commit', '-a', '-m', 'Added release instructions'], stdout
= subprocess
.PIPE
)
145 assert "version = '0.2'\n" not in file('../hello/hello.py').read()
147 child
= subprocess
.Popen(['./make-release', '-k', 'Testing'], stdin
= subprocess
.PIPE
, stdout
= subprocess
.PIPE
)
148 unused
, unused
= child
.communicate('\nP\n\n')
149 assert child
.returncode
== 0
151 assert "version = '0.2'\n" in file('../hello/hello.py').read()
153 def testBinaryRelease(self
):
154 support
.check_call(['tar', 'xzf', test_repo_c
])
155 make_releases_dir(src_feed
= '../c-prog/c-prog.xml', auto_upload
= True)
157 call_with_output_suppressed(['./make-release', '-k', 'Testing', '--builders=host'], '\nP\n\n')
159 feed
= self
.get_public_feed('HelloWorld-in-C.xml', 'c-prog.xml')
161 assert len(feed
.implementations
) == 2
162 src_impl
, = [x
for x
in feed
.implementations
.values() if x
.arch
== '*-src']
163 host_impl
, = [x
for x
in feed
.implementations
.values() if x
.arch
!= '*-src']
165 assert src_impl
.main
== None
166 assert host_impl
.main
== 'hello'
168 archives
= os
.listdir('archives')
169 assert os
.path
.basename(src_impl
.download_sources
[0].url
) in archives
, src_impl
.download_sources
[0].url
171 host_download
= host_impl
.download_sources
[0]
172 self
.assertEqual('http://TESTING/releases/1.1/helloworld-in-c-linux-x86_64-1.1.tar.bz2',
174 host_archive
= os
.path
.basename(host_download
.url
)
175 assert host_archive
in archives
176 support
.check_call(['tar', 'xjf', os
.path
.join('archives', host_archive
)])
177 c
= subprocess
.Popen(['0launch', os
.path
.join(host_download
.extract
, '0install', 'feed.xml')], stdout
= subprocess
.PIPE
)
178 output
, _
= c
.communicate()
180 self
.assertEquals("Hello from C! (version 1.1)\n", output
)
182 def get_public_feed(self
, name
, uri_basename
):
183 with
open(name
, 'rb') as stream
:
184 return model
.ZeroInstallFeed(qdom
.parse(stream
))
189 old_stdout
= sys
.stdout
190 sys
.stdout
= StringIO()
192 sys
.stdin
= StringIO('\n') # (simulate a press of Return if needed)
193 repo
.cmd
.main(['0repo'] + args
)
194 return sys
.stdout
.getvalue()
197 sys
.stdout
= old_stdout
199 class TestRepoRelease(TestRelease
):
201 TestRelease
.setUp(self
)
203 # Let GPG initialise (it's a bit verbose)
204 child
= subprocess
.Popen(['gpg', '-q', '--list-secret-keys'], stdout
= subprocess
.PIPE
, stderr
= subprocess
.PIPE
)
205 unused
, unused
= child
.communicate()
208 run_repo(['create', 'my-repo', 'Testing <testing@example.com>'])
211 if '0repo-config' in sys
.modules
:
212 del sys
.modules
['0repo-config']
214 with
open('0repo-config.py', 'at') as stream
:
215 stream
.write(CUSTOM_REPO_CONFIG
)
216 run_repo(['register'])
219 def get_public_feed(self
, name
, uri_basename
):
220 with
open(os
.path
.join(self
.tmp
, 'my-repo', 'public', uri_basename
), 'rb') as stream
:
221 return model
.ZeroInstallFeed(qdom
.parse(stream
))
223 unittest
.makeSuite(TestRelease
)
224 unittest
.makeSuite(TestRepoRelease
)
225 if __name__
== '__main__':