Suggest providing a "test" command, not the old self-test attribute
[0release.git] / tests / testrelease.py
blob3f009193696f098db1f5f48dc9881c9b0a872cd4
1 #!/usr/bin/env python
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
6 import unittest
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
15 import support
16 import release # (sets sys.path for 0repo)
17 import repo.cmd
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'
26 test_config = """
27 [global]
28 freshness = 0
29 auto_approve_keys = True
30 help_with_testing = True
31 network_use = full
32 """
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):
46 pass
48 def get_archive_rel_url(archive_basename, impl):
49 return "{version}/{archive}".format(
50 version = impl.get_version(),
51 archive = archive_basename)
52 """
54 def call_with_output_suppressed(cmd, stdin, expect_failure = False, **kwargs):
55 #cmd = [cmd[0], '-v'] + cmd[1:]
56 if stdin:
57 child = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, **kwargs)
58 else:
59 child = subprocess.Popen(cmd, stdout = subprocess.PIPE, **kwargs)
60 stdout, stderr = child.communicate(stdin)
61 if (child.returncode != 0) == expect_failure:
62 return stdout, stderr
63 #print stdout, stderr
64 raise Exception("Return code %d from %s\nstdout: %s\nstderr: %s" % (child.returncode, cmd, stdout, stderr))
66 def make_releases_dir(src_feed = '../hello/HelloWorld.xml', auto_upload = False):
67 os.chdir('releases')
68 call_with_output_suppressed(['0release', src_feed], None)
69 assert os.path.isfile('make-release')
71 lines = file('make-release').readlines()
72 lines[lines.index('ARCHIVE_DIR_PUBLIC_URL=\n')] = 'ARCHIVE_DIR_PUBLIC_URL=http://TESTING/releases/\\$RELEASE_VERSION\n'
74 # Force us to test against this version of 0release
75 for i, line in enumerate(lines):
76 if line.startswith('exec 0launch http://0install.net/2007/interfaces/0release.xml --release'):
77 lines[i] = '0release --release ' + line.split('--release ', 1)[1]
78 break
79 else:
80 assert 0
82 if auto_upload:
83 os.mkdir('archives')
84 lines[lines.index('ARCHIVE_UPLOAD_COMMAND=\n')] = 'ARCHIVE_UPLOAD_COMMAND=\'cp "$@" ../archives/\'\n'
86 s = file('make-release', 'w')
87 s.write(''.join(lines))
88 s.close()
90 class TestRelease(unittest.TestCase):
91 def setUp(self):
92 self.tmp = tempfile.mkdtemp(prefix = '0release-')
93 os.chdir(self.tmp)
94 support.check_call(['tar', 'xzf', test_gpg])
95 os.mkdir('releases')
96 os.environ['GNUPGHOME'] = self.tmp + '/gpg'
97 os.chmod(os.environ['GNUPGHOME'], 0700)
99 config_dir = os.path.join(self.tmp, 'config')
100 injector_config = os.path.join(config_dir, '0install.net', 'injector')
101 os.makedirs(injector_config)
102 s = open(os.path.join(injector_config, 'global'), 'w')
103 s.write(test_config)
104 s.close()
106 if 'ZEROINSTALL_PORTABLE_BASE' in os.environ:
107 del os.environ['ZEROINSTALL_PORTABLE_BASE']
108 os.environ['XDG_CONFIG_HOME'] = config_dir
109 imp.reload(basedir)
110 assert basedir.xdg_config_home == config_dir
112 def tearDown(self):
113 os.chdir(mydir)
114 ro_rmtree(self.tmp)
116 def testSimple(self):
117 support.check_call(['tar', 'xzf', test_repo])
118 make_releases_dir()
120 call_with_output_suppressed(['./make-release', '-k', 'Testing'], '\nP\n\n')
122 call_with_output_suppressed(['./make-release', '-k', 'Testing'], '\nP\nY\n\n')
124 assert 'Prints "Hello World"' in file('0.1/changelog-0.1').read()
125 assert 'Prints "Hello World"' not in file('0.2/changelog-0.2').read()
127 def testUncommitted(self):
128 support.check_call(['tar', 'xzf', test_repo_actions])
129 make_releases_dir()
131 unused, stderr = call_with_output_suppressed(['./make-release', '-k', 'Testing'], None,
132 expect_failure = True, stderr = subprocess.PIPE)
133 assert "Uncommitted changes!" in stderr
135 def testActions(self):
136 support.check_call(['tar', 'xzf', test_repo_actions])
137 os.chdir('hello')
138 support.check_call(['git', 'commit', '-a', '-m', 'Added release instructions'], stdout = subprocess.PIPE)
139 os.chdir('..')
140 make_releases_dir()
142 assert "version = '0.2'\n" not in file('../hello/hello.py').read()
144 child = subprocess.Popen(['./make-release', '-k', 'Testing'], stdin = subprocess.PIPE, stdout = subprocess.PIPE)
145 unused, unused = child.communicate('\nP\n\n')
146 assert child.returncode == 0
148 assert "version = '0.2'\n" in file('../hello/hello.py').read()
150 def testBinaryRelease(self):
151 support.check_call(['tar', 'xzf', test_repo_c])
152 make_releases_dir(src_feed = '../c-prog/c-prog.xml', auto_upload = True)
154 call_with_output_suppressed(['./make-release', '-k', 'Testing', '--builders=host'], '\nP\n\n')
156 feed = self.get_public_feed('HelloWorld-in-C.xml', 'c-prog.xml')
158 assert len(feed.implementations) == 2
159 src_impl, = [x for x in feed.implementations.values() if x.arch == '*-src']
160 host_impl, = [x for x in feed.implementations.values() if x.arch != '*-src']
162 assert src_impl.main == None
163 assert host_impl.main == 'hello'
165 archives = os.listdir('archives')
166 assert os.path.basename(src_impl.download_sources[0].url) in archives, src_impl.download_sources[0].url
168 host_download = host_impl.download_sources[0]
169 self.assertEqual('http://TESTING/releases/1.1/helloworld-in-c-linux-x86_64-1.1.tar.bz2',
170 host_download.url)
171 host_archive = os.path.basename(host_download.url)
172 assert host_archive in archives
173 support.check_call(['tar', 'xjf', os.path.join('archives', host_archive)])
174 c = subprocess.Popen(['0launch', os.path.join(host_download.extract, '0install', 'feed.xml')], stdout = subprocess.PIPE)
175 output, _ = c.communicate()
177 self.assertEquals("Hello from C! (version 1.1)\n", output)
179 def get_public_feed(self, name, uri_basename):
180 with open(name, 'rb') as stream:
181 return model.ZeroInstallFeed(qdom.parse(stream))
183 def run_repo(args):
184 oldcwd = os.getcwd()
186 old_stdout = sys.stdout
187 sys.stdout = StringIO()
188 try:
189 sys.stdin = StringIO('\n') # (simulate a press of Return if needed)
190 repo.cmd.main(['0repo'] + args)
191 return sys.stdout.getvalue()
192 finally:
193 os.chdir(oldcwd)
194 sys.stdout = old_stdout
196 class TestRepoRelease(TestRelease):
197 def setUp(self):
198 TestRelease.setUp(self)
200 # Let GPG initialise (it's a bit verbose)
201 child = subprocess.Popen(['gpg', '-q', '--list-secret-keys'], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
202 unused, unused = child.communicate()
203 child.wait()
205 run_repo(['create', 'my-repo', 'Testing <testing@example.com>'])
206 os.chdir('my-repo')
208 if '0repo-config' in sys.modules:
209 del sys.modules['0repo-config']
211 with open('0repo-config.py', 'at') as stream:
212 stream.write(CUSTOM_REPO_CONFIG)
213 run_repo(['register'])
214 os.chdir('..')
216 def get_public_feed(self, name, uri_basename):
217 with open(os.path.join(self.tmp, 'my-repo', 'public', uri_basename), 'rb') as stream:
218 return model.ZeroInstallFeed(qdom.parse(stream))
220 unittest.makeSuite(TestRelease)
221 unittest.makeSuite(TestRepoRelease)
222 if __name__ == '__main__':
223 unittest.main()