##// END OF EJS Templates
tests: stabilize Git committer in test_vcs_operations...
Mads Kiilerich -
r8768:d6d3cb59 stable
parent child Browse files
Show More
@@ -1,641 +1,644 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 Test suite for vcs push/pull operations.
15 Test suite for vcs push/pull operations.
16
16
17 The tests need Git > 1.8.1.
17 The tests need Git > 1.8.1.
18
18
19 This file was forked by the Kallithea project in July 2014.
19 This file was forked by the Kallithea project in July 2014.
20 Original author and date, and relevant copyright and licensing information is below:
20 Original author and date, and relevant copyright and licensing information is below:
21 :created_on: Dec 30, 2010
21 :created_on: Dec 30, 2010
22 :author: marcink
22 :author: marcink
23 :copyright: (c) 2013 RhodeCode GmbH, and others.
23 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :license: GPLv3, see LICENSE.md for more details.
24 :license: GPLv3, see LICENSE.md for more details.
25
25
26 """
26 """
27
27
28 import json
28 import json
29 import os
29 import os
30 import re
30 import re
31 import tempfile
31 import tempfile
32 import time
32 import time
33 import urllib.request
33 import urllib.request
34 from subprocess import PIPE, Popen
34 from subprocess import PIPE, Popen
35 from tempfile import _RandomNameSequence
35 from tempfile import _RandomNameSequence
36
36
37 import pytest
37 import pytest
38
38
39 import kallithea
39 import kallithea
40 from kallithea.lib.utils2 import ascii_bytes, safe_str
40 from kallithea.lib.utils2 import ascii_bytes, safe_str
41 from kallithea.model import db, meta
41 from kallithea.model import db, meta
42 from kallithea.model.ssh_key import SshKeyModel
42 from kallithea.model.ssh_key import SshKeyModel
43 from kallithea.model.user import UserModel
43 from kallithea.model.user import UserModel
44 from kallithea.tests import base
44 from kallithea.tests import base
45 from kallithea.tests.fixture import Fixture
45 from kallithea.tests.fixture import Fixture
46
46
47
47
48 DEBUG = True
48 DEBUG = True
49 HOST = '127.0.0.1:4999' # test host
49 HOST = '127.0.0.1:4999' # test host
50
50
51 fixture = Fixture()
51 fixture = Fixture()
52
52
53
53
54 # Parameterize different kinds of VCS testing - both the kind of VCS and the
54 # Parameterize different kinds of VCS testing - both the kind of VCS and the
55 # access method (HTTP/SSH)
55 # access method (HTTP/SSH)
56
56
57 # Mixin for using HTTP and SSH URLs
57 # Mixin for using HTTP and SSH URLs
58 class HttpVcsTest(object):
58 class HttpVcsTest(object):
59 @staticmethod
59 @staticmethod
60 def repo_url_param(webserver, repo_name, **kwargs):
60 def repo_url_param(webserver, repo_name, **kwargs):
61 return webserver.repo_url(repo_name, **kwargs)
61 return webserver.repo_url(repo_name, **kwargs)
62
62
63 class SshVcsTest(object):
63 class SshVcsTest(object):
64 public_keys = {
64 public_keys = {
65 base.TEST_USER_REGULAR_LOGIN: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== kallithea@localhost',
65 base.TEST_USER_REGULAR_LOGIN: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUQ== kallithea@localhost',
66 base.TEST_USER_ADMIN_LOGIN: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUq== kallithea@localhost',
66 base.TEST_USER_ADMIN_LOGIN: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6Ycnc2oUZHQnQwuqgZqTTdMDZD7ataf3JM7oG2Fw8JR6cdmz4QZLe5mfDwaFwG2pWHLRpVqzfrD/Pn3rIO++bgCJH5ydczrl1WScfryV1hYMJ/4EzLGM657J1/q5EI+b9SntKjf4ax+KP322L0TNQGbZUHLbfG2MwHMrYBQpHUq== kallithea@localhost',
67 }
67 }
68
68
69 @classmethod
69 @classmethod
70 def repo_url_param(cls, webserver, repo_name, username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS, client_ip=base.IP_ADDR):
70 def repo_url_param(cls, webserver, repo_name, username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS, client_ip=base.IP_ADDR):
71 user = db.User.get_by_username(username)
71 user = db.User.get_by_username(username)
72 if user.ssh_keys:
72 if user.ssh_keys:
73 ssh_key = user.ssh_keys[0]
73 ssh_key = user.ssh_keys[0]
74 else:
74 else:
75 sshkeymodel = SshKeyModel()
75 sshkeymodel = SshKeyModel()
76 ssh_key = sshkeymodel.create(user, 'test key', cls.public_keys[user.username])
76 ssh_key = sshkeymodel.create(user, 'test key', cls.public_keys[user.username])
77 meta.Session().commit()
77 meta.Session().commit()
78
78
79 return cls._ssh_param(repo_name, user, ssh_key, client_ip)
79 return cls._ssh_param(repo_name, user, ssh_key, client_ip)
80
80
81 # Mixins for using Mercurial and Git
81 # Mixins for using Mercurial and Git
82 class HgVcsTest(object):
82 class HgVcsTest(object):
83 repo_type = 'hg'
83 repo_type = 'hg'
84 repo_name = base.HG_REPO
84 repo_name = base.HG_REPO
85
85
86 class GitVcsTest(object):
86 class GitVcsTest(object):
87 repo_type = 'git'
87 repo_type = 'git'
88 repo_name = base.GIT_REPO
88 repo_name = base.GIT_REPO
89
89
90 # Combine mixins to give the combinations we want to parameterize tests with
90 # Combine mixins to give the combinations we want to parameterize tests with
91 class HgHttpVcsTest(HgVcsTest, HttpVcsTest):
91 class HgHttpVcsTest(HgVcsTest, HttpVcsTest):
92 pass
92 pass
93
93
94 class GitHttpVcsTest(GitVcsTest, HttpVcsTest):
94 class GitHttpVcsTest(GitVcsTest, HttpVcsTest):
95 pass
95 pass
96
96
97 class HgSshVcsTest(HgVcsTest, SshVcsTest):
97 class HgSshVcsTest(HgVcsTest, SshVcsTest):
98 @staticmethod
98 @staticmethod
99 def _ssh_param(repo_name, user, ssh_key, client_ip):
99 def _ssh_param(repo_name, user, ssh_key, client_ip):
100 # Specify a custom ssh command on the command line
100 # Specify a custom ssh command on the command line
101 return r"""--config ui.ssh="bash -c 'SSH_ORIGINAL_COMMAND=\"\$2\" SSH_CONNECTION=\"%s 1024 127.0.0.1 22\" kallithea-cli ssh-serve -c %s %s %s' --" ssh://someuser@somehost/%s""" % (
101 return r"""--config ui.ssh="bash -c 'SSH_ORIGINAL_COMMAND=\"\$2\" SSH_CONNECTION=\"%s 1024 127.0.0.1 22\" kallithea-cli ssh-serve -c %s %s %s' --" ssh://someuser@somehost/%s""" % (
102 client_ip,
102 client_ip,
103 kallithea.CONFIG['__file__'],
103 kallithea.CONFIG['__file__'],
104 user.user_id,
104 user.user_id,
105 ssh_key.user_ssh_key_id,
105 ssh_key.user_ssh_key_id,
106 repo_name)
106 repo_name)
107
107
108 class GitSshVcsTest(GitVcsTest, SshVcsTest):
108 class GitSshVcsTest(GitVcsTest, SshVcsTest):
109 @staticmethod
109 @staticmethod
110 def _ssh_param(repo_name, user, ssh_key, client_ip):
110 def _ssh_param(repo_name, user, ssh_key, client_ip):
111 # Set a custom ssh command in the global environment
111 # Set a custom ssh command in the global environment
112 os.environ['GIT_SSH_COMMAND'] = r"""bash -c 'SSH_ORIGINAL_COMMAND="$2" SSH_CONNECTION="%s 1024 127.0.0.1 22" kallithea-cli ssh-serve -c %s %s %s' --""" % (
112 os.environ['GIT_SSH_COMMAND'] = r"""bash -c 'SSH_ORIGINAL_COMMAND="$2" SSH_CONNECTION="%s 1024 127.0.0.1 22" kallithea-cli ssh-serve -c %s %s %s' --""" % (
113 client_ip,
113 client_ip,
114 kallithea.CONFIG['__file__'],
114 kallithea.CONFIG['__file__'],
115 user.user_id,
115 user.user_id,
116 ssh_key.user_ssh_key_id)
116 ssh_key.user_ssh_key_id)
117 return "ssh://someuser@somehost/%s""" % repo_name
117 return "ssh://someuser@somehost/%s""" % repo_name
118
118
119 parametrize_vcs_test = base.parametrize('vt', [
119 parametrize_vcs_test = base.parametrize('vt', [
120 HgHttpVcsTest,
120 HgHttpVcsTest,
121 GitHttpVcsTest,
121 GitHttpVcsTest,
122 HgSshVcsTest,
122 HgSshVcsTest,
123 GitSshVcsTest,
123 GitSshVcsTest,
124 ])
124 ])
125 parametrize_vcs_test_hg = base.parametrize('vt', [
125 parametrize_vcs_test_hg = base.parametrize('vt', [
126 HgHttpVcsTest,
126 HgHttpVcsTest,
127 HgSshVcsTest,
127 HgSshVcsTest,
128 ])
128 ])
129 parametrize_vcs_test_http = base.parametrize('vt', [
129 parametrize_vcs_test_http = base.parametrize('vt', [
130 HgHttpVcsTest,
130 HgHttpVcsTest,
131 GitHttpVcsTest,
131 GitHttpVcsTest,
132 ])
132 ])
133
133
134 class Command(object):
134 class Command(object):
135
135
136 def __init__(self, cwd):
136 def __init__(self, cwd):
137 self.cwd = cwd
137 self.cwd = cwd
138
138
139 def execute(self, *args, **environ):
139 def execute(self, *args, **environ):
140 """
140 """
141 Runs command on the system with given ``args`` using simple space
141 Runs command on the system with given ``args`` using simple space
142 join without safe quoting.
142 join without safe quoting.
143 """
143 """
144 command = ' '.join(args)
144 command = ' '.join(args)
145 ignoreReturnCode = environ.pop('ignoreReturnCode', False)
145 ignoreReturnCode = environ.pop('ignoreReturnCode', False)
146 if DEBUG:
146 if DEBUG:
147 print('*** CMD %s ***' % command)
147 print('*** CMD %s ***' % command)
148 testenv = dict(os.environ)
148 testenv = dict(os.environ)
149 testenv['LANG'] = 'en_US.UTF-8'
149 testenv['LANG'] = 'en_US.UTF-8'
150 testenv['LANGUAGE'] = 'en_US:en'
150 testenv['LANGUAGE'] = 'en_US:en'
151 testenv['HGPLAIN'] = ''
151 testenv['HGPLAIN'] = ''
152 testenv['HGRCPATH'] = ''
152 testenv['HGRCPATH'] = ''
153 testenv['GIT_COMMITTER_NAME'] = base.TEST_USER_ADMIN_LOGIN
154 testenv['GIT_COMMITTER_EMAIL'] = base.TEST_USER_ADMIN_EMAIL
155 testenv['GIT_AUTHOR_NAME'] = base.TEST_USER_REGULAR_LOGIN
156 testenv['GIT_AUTHOR_EMAIL'] = base.TEST_USER_REGULAR_EMAIL
153 testenv.update(environ)
157 testenv.update(environ)
154 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
158 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
155 stdout, stderr = p.communicate()
159 stdout, stderr = p.communicate()
156 if DEBUG:
160 if DEBUG:
157 if stdout:
161 if stdout:
158 print('stdout:', stdout)
162 print('stdout:', stdout)
159 if stderr:
163 if stderr:
160 print('stderr:', stderr)
164 print('stderr:', stderr)
161 if not ignoreReturnCode:
165 if not ignoreReturnCode:
162 assert p.returncode == 0
166 assert p.returncode == 0
163 return safe_str(stdout), safe_str(stderr)
167 return safe_str(stdout), safe_str(stderr)
164
168
165
169
166 def _get_tmp_dir(prefix='vcs_operations-', suffix=''):
170 def _get_tmp_dir(prefix='vcs_operations-', suffix=''):
167 return tempfile.mkdtemp(dir=base.TESTS_TMP_PATH, prefix=prefix, suffix=suffix)
171 return tempfile.mkdtemp(dir=base.TESTS_TMP_PATH, prefix=prefix, suffix=suffix)
168
172
169
173
170 def _add_files(vcs, dest_dir, files_no=3):
174 def _add_files(vcs, dest_dir, files_no=3):
171 """
175 """
172 Generate some files, add it to dest_dir repo and push back
176 Generate some files, add it to dest_dir repo and push back
173 vcs is git or hg and defines what VCS we want to make those files for
177 vcs is git or hg and defines what VCS we want to make those files for
174
178
175 :param vcs:
179 :param vcs:
176 :param dest_dir:
180 :param dest_dir:
177 """
181 """
178 added_file = '%ssetup.py' % next(_RandomNameSequence())
182 added_file = '%ssetup.py' % next(_RandomNameSequence())
179 open(os.path.join(dest_dir, added_file), 'a').close()
183 open(os.path.join(dest_dir, added_file), 'a').close()
180 Command(dest_dir).execute(vcs, 'add', added_file)
184 Command(dest_dir).execute(vcs, 'add', added_file)
181
185
182 email = 'me@example.com'
186 email = 'me@example.com'
183 if os.name == 'nt':
187 if os.name == 'nt':
184 author_str = 'User <%s>' % email
188 author_str = 'User <%s>' % email
185 else:
189 else:
186 author_str = 'User ǝɯɐᴎ <%s>' % email
190 author_str = 'User ǝɯɐᴎ <%s>' % email
187 for i in range(files_no):
191 for i in range(files_no):
188 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
192 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
189 Command(dest_dir).execute(cmd)
193 Command(dest_dir).execute(cmd)
190 if vcs == 'hg':
194 if vcs == 'hg':
191 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
195 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
192 i, author_str, added_file
196 i, author_str, added_file
193 )
197 )
194 elif vcs == 'git':
198 elif vcs == 'git':
195 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
199 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
196 i, author_str, added_file
200 i, author_str, added_file
197 )
201 )
198 # git commit needs EMAIL on some machines
202 Command(dest_dir).execute(cmd)
199 Command(dest_dir).execute(cmd, EMAIL=email)
200
203
201 def _add_files_and_push(webserver, vt, dest_dir, clone_url, ignoreReturnCode=False, files_no=3):
204 def _add_files_and_push(webserver, vt, dest_dir, clone_url, ignoreReturnCode=False, files_no=3):
202 _add_files(vt.repo_type, dest_dir, files_no=files_no)
205 _add_files(vt.repo_type, dest_dir, files_no=files_no)
203 # PUSH it back
206 # PUSH it back
204 stdout = stderr = None
207 stdout = stderr = None
205 if vt.repo_type == 'hg':
208 if vt.repo_type == 'hg':
206 stdout, stderr = Command(dest_dir).execute('hg push -f --verbose', clone_url, ignoreReturnCode=ignoreReturnCode)
209 stdout, stderr = Command(dest_dir).execute('hg push -f --verbose', clone_url, ignoreReturnCode=ignoreReturnCode)
207 elif vt.repo_type == 'git':
210 elif vt.repo_type == 'git':
208 stdout, stderr = Command(dest_dir).execute('git push -f --verbose', clone_url, "master", ignoreReturnCode=ignoreReturnCode)
211 stdout, stderr = Command(dest_dir).execute('git push -f --verbose', clone_url, "master", ignoreReturnCode=ignoreReturnCode)
209
212
210 return stdout, stderr
213 return stdout, stderr
211
214
212
215
213 def _check_outgoing(vcs, cwd, clone_url):
216 def _check_outgoing(vcs, cwd, clone_url):
214 if vcs == 'hg':
217 if vcs == 'hg':
215 # hg removes the password from default URLs, so we have to provide it here via the clone_url
218 # hg removes the password from default URLs, so we have to provide it here via the clone_url
216 return Command(cwd).execute('hg -q outgoing', clone_url, ignoreReturnCode=True)
219 return Command(cwd).execute('hg -q outgoing', clone_url, ignoreReturnCode=True)
217 elif vcs == 'git':
220 elif vcs == 'git':
218 Command(cwd).execute('git remote update')
221 Command(cwd).execute('git remote update')
219 return Command(cwd).execute('git log origin/master..master')
222 return Command(cwd).execute('git log origin/master..master')
220
223
221
224
222 def set_anonymous_access(enable=True):
225 def set_anonymous_access(enable=True):
223 user = db.User.get_default_user()
226 user = db.User.get_default_user()
224 user.active = enable
227 user.active = enable
225 meta.Session().commit()
228 meta.Session().commit()
226 if enable != db.User.get_default_user().active:
229 if enable != db.User.get_default_user().active:
227 raise Exception('Cannot set anonymous access')
230 raise Exception('Cannot set anonymous access')
228
231
229
232
230 #==============================================================================
233 #==============================================================================
231 # TESTS
234 # TESTS
232 #==============================================================================
235 #==============================================================================
233
236
234
237
235 def _check_proper_git_push(stdout, stderr):
238 def _check_proper_git_push(stdout, stderr):
236 assert 'fatal' not in stderr
239 assert 'fatal' not in stderr
237 assert 'rejected' not in stderr
240 assert 'rejected' not in stderr
238 assert 'Pushing to' in stderr
241 assert 'Pushing to' in stderr
239 assert 'master -> master' in stderr
242 assert 'master -> master' in stderr
240
243
241
244
242 @pytest.mark.usefixtures("test_context_fixture")
245 @pytest.mark.usefixtures("test_context_fixture")
243 class TestVCSOperations(base.TestController):
246 class TestVCSOperations(base.TestController):
244
247
245 @classmethod
248 @classmethod
246 def setup_class(cls):
249 def setup_class(cls):
247 # DISABLE ANONYMOUS ACCESS
250 # DISABLE ANONYMOUS ACCESS
248 set_anonymous_access(False)
251 set_anonymous_access(False)
249
252
250 @pytest.fixture()
253 @pytest.fixture()
251 def testhook_cleanup(self):
254 def testhook_cleanup(self):
252 yield
255 yield
253 # remove hook
256 # remove hook
254 for hook in ['prechangegroup', 'pretxnchangegroup', 'preoutgoing', 'changegroup', 'outgoing', 'incoming']:
257 for hook in ['prechangegroup', 'pretxnchangegroup', 'preoutgoing', 'changegroup', 'outgoing', 'incoming']:
255 entry = db.Ui.get_by_key('hooks', '%s.testhook' % hook)
258 entry = db.Ui.get_by_key('hooks', '%s.testhook' % hook)
256 if entry:
259 if entry:
257 meta.Session().delete(entry)
260 meta.Session().delete(entry)
258 meta.Session().commit()
261 meta.Session().commit()
259
262
260 @pytest.fixture(scope="module")
263 @pytest.fixture(scope="module")
261 def testfork(self):
264 def testfork(self):
262 # create fork so the repo stays untouched
265 # create fork so the repo stays untouched
263 git_fork_name = '%s_fork%s' % (base.GIT_REPO, next(_RandomNameSequence()))
266 git_fork_name = '%s_fork%s' % (base.GIT_REPO, next(_RandomNameSequence()))
264 fixture.create_fork(base.GIT_REPO, git_fork_name)
267 fixture.create_fork(base.GIT_REPO, git_fork_name)
265 hg_fork_name = '%s_fork%s' % (base.HG_REPO, next(_RandomNameSequence()))
268 hg_fork_name = '%s_fork%s' % (base.HG_REPO, next(_RandomNameSequence()))
266 fixture.create_fork(base.HG_REPO, hg_fork_name)
269 fixture.create_fork(base.HG_REPO, hg_fork_name)
267 return {'git': git_fork_name, 'hg': hg_fork_name}
270 return {'git': git_fork_name, 'hg': hg_fork_name}
268
271
269 @parametrize_vcs_test
272 @parametrize_vcs_test
270 def test_clone_repo_by_admin(self, webserver, vt):
273 def test_clone_repo_by_admin(self, webserver, vt):
271 clone_url = vt.repo_url_param(webserver, vt.repo_name)
274 clone_url = vt.repo_url_param(webserver, vt.repo_name)
272 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
275 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
273
276
274 if vt.repo_type == 'git':
277 if vt.repo_type == 'git':
275 assert 'Cloning into' in stdout + stderr
278 assert 'Cloning into' in stdout + stderr
276 assert stderr == '' or stdout == ''
279 assert stderr == '' or stdout == ''
277 elif vt.repo_type == 'hg':
280 elif vt.repo_type == 'hg':
278 assert 'requesting all changes' in stdout
281 assert 'requesting all changes' in stdout
279 assert 'adding changesets' in stdout
282 assert 'adding changesets' in stdout
280 assert 'adding manifests' in stdout
283 assert 'adding manifests' in stdout
281 assert 'adding file changes' in stdout
284 assert 'adding file changes' in stdout
282 assert stderr == ''
285 assert stderr == ''
283
286
284 @parametrize_vcs_test_http
287 @parametrize_vcs_test_http
285 def test_clone_wrong_credentials(self, webserver, vt):
288 def test_clone_wrong_credentials(self, webserver, vt):
286 clone_url = vt.repo_url_param(webserver, vt.repo_name, password='bad!')
289 clone_url = vt.repo_url_param(webserver, vt.repo_name, password='bad!')
287 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
290 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
288 if vt.repo_type == 'git':
291 if vt.repo_type == 'git':
289 assert 'fatal: Authentication failed' in stderr
292 assert 'fatal: Authentication failed' in stderr
290 elif vt.repo_type == 'hg':
293 elif vt.repo_type == 'hg':
291 assert 'abort: authorization failed' in stderr
294 assert 'abort: authorization failed' in stderr
292
295
293 def test_clone_git_dir_as_hg(self, webserver):
296 def test_clone_git_dir_as_hg(self, webserver):
294 clone_url = HgHttpVcsTest.repo_url_param(webserver, base.GIT_REPO)
297 clone_url = HgHttpVcsTest.repo_url_param(webserver, base.GIT_REPO)
295 stdout, stderr = Command(base.TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
298 stdout, stderr = Command(base.TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
296 assert 'HTTP Error 404: Not Found' in stderr or "not a valid repository" in stdout and 'abort:' in stderr
299 assert 'HTTP Error 404: Not Found' in stderr or "not a valid repository" in stdout and 'abort:' in stderr
297
300
298 def test_clone_hg_repo_as_git(self, webserver):
301 def test_clone_hg_repo_as_git(self, webserver):
299 clone_url = GitHttpVcsTest.repo_url_param(webserver, base.HG_REPO)
302 clone_url = GitHttpVcsTest.repo_url_param(webserver, base.HG_REPO)
300 stdout, stderr = Command(base.TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
303 stdout, stderr = Command(base.TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
301 assert 'not found' in stderr
304 assert 'not found' in stderr
302
305
303 @parametrize_vcs_test
306 @parametrize_vcs_test
304 def test_clone_non_existing_path(self, webserver, vt):
307 def test_clone_non_existing_path(self, webserver, vt):
305 clone_url = vt.repo_url_param(webserver, 'trololo')
308 clone_url = vt.repo_url_param(webserver, 'trololo')
306 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
309 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
307 if vt.repo_type == 'git':
310 if vt.repo_type == 'git':
308 assert 'not found' in stderr or 'abort: Access to %r denied' % 'trololo' in stderr
311 assert 'not found' in stderr or 'abort: Access to %r denied' % 'trololo' in stderr
309 elif vt.repo_type == 'hg':
312 elif vt.repo_type == 'hg':
310 assert 'HTTP Error 404: Not Found' in stderr or 'abort: no suitable response from remote hg' in stderr and 'remote: abort: Access to %r denied' % 'trololo' in stdout + stderr
313 assert 'HTTP Error 404: Not Found' in stderr or 'abort: no suitable response from remote hg' in stderr and 'remote: abort: Access to %r denied' % 'trololo' in stdout + stderr
311
314
312 @parametrize_vcs_test
315 @parametrize_vcs_test
313 def test_push_new_repo(self, webserver, vt):
316 def test_push_new_repo(self, webserver, vt):
314 # Clear the log so we know what is added
317 # Clear the log so we know what is added
315 db.UserLog.query().delete()
318 db.UserLog.query().delete()
316 meta.Session().commit()
319 meta.Session().commit()
317
320
318 # Create an empty server repo using the API
321 # Create an empty server repo using the API
319 repo_name = 'new_%s_%s' % (vt.repo_type, next(_RandomNameSequence()))
322 repo_name = 'new_%s_%s' % (vt.repo_type, next(_RandomNameSequence()))
320 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
323 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
321 params = {
324 params = {
322 "id": 7,
325 "id": 7,
323 "api_key": usr.api_key,
326 "api_key": usr.api_key,
324 "method": 'create_repo',
327 "method": 'create_repo',
325 "args": dict(repo_name=repo_name,
328 "args": dict(repo_name=repo_name,
326 owner=base.TEST_USER_ADMIN_LOGIN,
329 owner=base.TEST_USER_ADMIN_LOGIN,
327 repo_type=vt.repo_type),
330 repo_type=vt.repo_type),
328 }
331 }
329 req = urllib.request.Request(
332 req = urllib.request.Request(
330 'http://%s:%s/_admin/api' % webserver.server_address,
333 'http://%s:%s/_admin/api' % webserver.server_address,
331 data=ascii_bytes(json.dumps(params)),
334 data=ascii_bytes(json.dumps(params)),
332 headers={'content-type': 'application/json'})
335 headers={'content-type': 'application/json'})
333 response = urllib.request.urlopen(req)
336 response = urllib.request.urlopen(req)
334 result = json.loads(response.read())
337 result = json.loads(response.read())
335 # Expect something like:
338 # Expect something like:
336 # {u'result': {u'msg': u'Created new repository `new_XXX`', u'task': None, u'success': True}, u'id': 7, u'error': None}
339 # {u'result': {u'msg': u'Created new repository `new_XXX`', u'task': None, u'success': True}, u'id': 7, u'error': None}
337 assert result['result']['success']
340 assert result['result']['success']
338
341
339 # Create local clone of the empty server repo
342 # Create local clone of the empty server repo
340 local_clone_dir = _get_tmp_dir()
343 local_clone_dir = _get_tmp_dir()
341 clone_url = vt.repo_url_param(webserver, repo_name)
344 clone_url = vt.repo_url_param(webserver, repo_name)
342 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, local_clone_dir)
345 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, local_clone_dir)
343
346
344 # Make 3 commits and push to the empty server repo.
347 # Make 3 commits and push to the empty server repo.
345 # The server repo doesn't have any other heads than the
348 # The server repo doesn't have any other heads than the
346 # refs/heads/master we are pushing, but the `git log` in the push hook
349 # refs/heads/master we are pushing, but the `git log` in the push hook
347 # should still list the 3 commits.
350 # should still list the 3 commits.
348 stdout, stderr = _add_files_and_push(webserver, vt, local_clone_dir, clone_url=clone_url)
351 stdout, stderr = _add_files_and_push(webserver, vt, local_clone_dir, clone_url=clone_url)
349 if vt.repo_type == 'git':
352 if vt.repo_type == 'git':
350 _check_proper_git_push(stdout, stderr)
353 _check_proper_git_push(stdout, stderr)
351 elif vt.repo_type == 'hg':
354 elif vt.repo_type == 'hg':
352 assert 'pushing to ' in stdout
355 assert 'pushing to ' in stdout
353 assert 'remote: added ' in stdout
356 assert 'remote: added ' in stdout
354
357
355 # Verify that we got the right events in UserLog. Expect something like:
358 # Verify that we got the right events in UserLog. Expect something like:
356 # <UserLog('id:new_git_XXX:started_following_repo')>
359 # <UserLog('id:new_git_XXX:started_following_repo')>
357 # <UserLog('id:new_git_XXX:user_created_repo')>
360 # <UserLog('id:new_git_XXX:user_created_repo')>
358 # <UserLog('id:new_git_XXX:pull')>
361 # <UserLog('id:new_git_XXX:pull')>
359 # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')>
362 # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')>
360 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
363 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
361 action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
364 action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
362 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == ([
365 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == ([
363 ('started_following_repo', 0),
366 ('started_following_repo', 0),
364 ('user_created_repo', 0),
367 ('user_created_repo', 0),
365 ('pull', 0),
368 ('pull', 0),
366 ('push', 3)]
369 ('push', 3)]
367 if vt.repo_type == 'git' else [
370 if vt.repo_type == 'git' else [
368 ('started_following_repo', 0),
371 ('started_following_repo', 0),
369 ('user_created_repo', 0),
372 ('user_created_repo', 0),
370 # (u'pull', 0), # Mercurial outgoing hook is not called for empty clones
373 # (u'pull', 0), # Mercurial outgoing hook is not called for empty clones
371 ('push', 3)])
374 ('push', 3)])
372
375
373 @parametrize_vcs_test
376 @parametrize_vcs_test
374 def test_push_new_file(self, webserver, testfork, vt):
377 def test_push_new_file(self, webserver, testfork, vt):
375 db.UserLog.query().delete()
378 db.UserLog.query().delete()
376 meta.Session().commit()
379 meta.Session().commit()
377
380
378 dest_dir = _get_tmp_dir()
381 dest_dir = _get_tmp_dir()
379 clone_url = vt.repo_url_param(webserver, vt.repo_name)
382 clone_url = vt.repo_url_param(webserver, vt.repo_name)
380 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
383 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
381
384
382 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
385 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
383 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url=clone_url)
386 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url=clone_url)
384
387
385 if vt.repo_type == 'git':
388 if vt.repo_type == 'git':
386 _check_proper_git_push(stdout, stderr)
389 _check_proper_git_push(stdout, stderr)
387 elif vt.repo_type == 'hg':
390 elif vt.repo_type == 'hg':
388 assert 'pushing to' in stdout
391 assert 'pushing to' in stdout
389 assert 'Repository size' in stdout
392 assert 'Repository size' in stdout
390 assert 'Last revision is now' in stdout
393 assert 'Last revision is now' in stdout
391
394
392 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
395 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
393 action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
396 action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
394 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
397 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
395 [('pull', 0), ('push', 3)]
398 [('pull', 0), ('push', 3)]
396
399
397 @parametrize_vcs_test
400 @parametrize_vcs_test
398 def test_pull(self, webserver, testfork, vt):
401 def test_pull(self, webserver, testfork, vt):
399 db.UserLog.query().delete()
402 db.UserLog.query().delete()
400 meta.Session().commit()
403 meta.Session().commit()
401
404
402 dest_dir = _get_tmp_dir()
405 dest_dir = _get_tmp_dir()
403 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'init', dest_dir)
406 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'init', dest_dir)
404
407
405 clone_url = vt.repo_url_param(webserver, vt.repo_name)
408 clone_url = vt.repo_url_param(webserver, vt.repo_name)
406 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url)
409 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url)
407 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
410 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
408
411
409 if vt.repo_type == 'git':
412 if vt.repo_type == 'git':
410 assert 'FETCH_HEAD' in stderr
413 assert 'FETCH_HEAD' in stderr
411 elif vt.repo_type == 'hg':
414 elif vt.repo_type == 'hg':
412 assert 'new changesets' in stdout
415 assert 'new changesets' in stdout
413
416
414 action_parts = [ul.action for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
417 action_parts = [ul.action for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
415 assert action_parts == ['pull']
418 assert action_parts == ['pull']
416
419
417 # Test handling of URLs with extra '/' around repo_name
420 # Test handling of URLs with extra '/' around repo_name
418 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url.replace('/' + vt.repo_name, '/./%s/' % vt.repo_name), ignoreReturnCode=True)
421 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url.replace('/' + vt.repo_name, '/./%s/' % vt.repo_name), ignoreReturnCode=True)
419 if issubclass(vt, HttpVcsTest):
422 if issubclass(vt, HttpVcsTest):
420 if vt.repo_type == 'git':
423 if vt.repo_type == 'git':
421 # NOTE: when pulling from http://hostname/./vcs_test_git/ , the git client will normalize that and issue an HTTP request to /vcs_test_git/info/refs
424 # NOTE: when pulling from http://hostname/./vcs_test_git/ , the git client will normalize that and issue an HTTP request to /vcs_test_git/info/refs
422 assert 'Already up to date.' in stdout
425 assert 'Already up to date.' in stdout
423 else:
426 else:
424 assert vt.repo_type == 'hg'
427 assert vt.repo_type == 'hg'
425 assert "abort: HTTP Error 404: Not Found" in stderr
428 assert "abort: HTTP Error 404: Not Found" in stderr
426 else:
429 else:
427 assert issubclass(vt, SshVcsTest)
430 assert issubclass(vt, SshVcsTest)
428 if vt.repo_type == 'git':
431 if vt.repo_type == 'git':
429 assert "abort: Access to './%s' denied" % vt.repo_name in stderr
432 assert "abort: Access to './%s' denied" % vt.repo_name in stderr
430 else:
433 else:
431 assert "abort: Access to './%s' denied" % vt.repo_name in stdout + stderr
434 assert "abort: Access to './%s' denied" % vt.repo_name in stdout + stderr
432
435
433 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url.replace('/' + vt.repo_name, '/%s/' % vt.repo_name), ignoreReturnCode=True)
436 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url.replace('/' + vt.repo_name, '/%s/' % vt.repo_name), ignoreReturnCode=True)
434 if vt.repo_type == 'git':
437 if vt.repo_type == 'git':
435 assert 'Already up to date.' in stdout
438 assert 'Already up to date.' in stdout
436 else:
439 else:
437 assert vt.repo_type == 'hg'
440 assert vt.repo_type == 'hg'
438 assert "no changes found" in stdout
441 assert "no changes found" in stdout
439 assert "denied" not in stderr
442 assert "denied" not in stderr
440 assert "denied" not in stdout
443 assert "denied" not in stdout
441 assert "404" not in stdout
444 assert "404" not in stdout
442
445
443 @parametrize_vcs_test
446 @parametrize_vcs_test
444 def test_push_invalidates_cache(self, webserver, testfork, vt):
447 def test_push_invalidates_cache(self, webserver, testfork, vt):
445 pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == testfork[vt.repo_type])]
448 pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == testfork[vt.repo_type])]
446
449
447 dest_dir = _get_tmp_dir()
450 dest_dir = _get_tmp_dir()
448 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
451 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
449 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
452 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
450
453
451 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, files_no=1, clone_url=clone_url)
454 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, files_no=1, clone_url=clone_url)
452
455
453 if vt.repo_type == 'git':
456 if vt.repo_type == 'git':
454 _check_proper_git_push(stdout, stderr)
457 _check_proper_git_push(stdout, stderr)
455
458
456 meta.Session.close() # expire session to make sure SA fetches new Repository instances after last_changeset has been updated by server side hook in another process
459 meta.Session.close() # expire session to make sure SA fetches new Repository instances after last_changeset has been updated by server side hook in another process
457 post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == testfork[vt.repo_type])]
460 post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == testfork[vt.repo_type])]
458 assert pre_cached_tip != post_cached_tip
461 assert pre_cached_tip != post_cached_tip
459
462
460 @parametrize_vcs_test_http
463 @parametrize_vcs_test_http
461 def test_push_wrong_credentials(self, webserver, vt):
464 def test_push_wrong_credentials(self, webserver, vt):
462 dest_dir = _get_tmp_dir()
465 dest_dir = _get_tmp_dir()
463 clone_url = vt.repo_url_param(webserver, vt.repo_name)
466 clone_url = vt.repo_url_param(webserver, vt.repo_name)
464 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
467 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
465
468
466 clone_url = webserver.repo_url(vt.repo_name, username='bad', password='name')
469 clone_url = webserver.repo_url(vt.repo_name, username='bad', password='name')
467 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir,
470 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir,
468 clone_url=clone_url, ignoreReturnCode=True)
471 clone_url=clone_url, ignoreReturnCode=True)
469
472
470 if vt.repo_type == 'git':
473 if vt.repo_type == 'git':
471 assert 'fatal: Authentication failed' in stderr
474 assert 'fatal: Authentication failed' in stderr
472 elif vt.repo_type == 'hg':
475 elif vt.repo_type == 'hg':
473 assert 'abort: authorization failed' in stderr
476 assert 'abort: authorization failed' in stderr
474
477
475 @parametrize_vcs_test
478 @parametrize_vcs_test
476 def test_push_with_readonly_credentials(self, webserver, vt):
479 def test_push_with_readonly_credentials(self, webserver, vt):
477 db.UserLog.query().delete()
480 db.UserLog.query().delete()
478 meta.Session().commit()
481 meta.Session().commit()
479
482
480 dest_dir = _get_tmp_dir()
483 dest_dir = _get_tmp_dir()
481 clone_url = vt.repo_url_param(webserver, vt.repo_name, username=base.TEST_USER_REGULAR_LOGIN, password=base.TEST_USER_REGULAR_PASS)
484 clone_url = vt.repo_url_param(webserver, vt.repo_name, username=base.TEST_USER_REGULAR_LOGIN, password=base.TEST_USER_REGULAR_PASS)
482 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
485 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
483
486
484 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, ignoreReturnCode=True, clone_url=clone_url)
487 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, ignoreReturnCode=True, clone_url=clone_url)
485
488
486 if vt.repo_type == 'git':
489 if vt.repo_type == 'git':
487 assert 'The requested URL returned error: 403' in stderr or 'abort: Push access to %r denied' % str(vt.repo_name) in stderr
490 assert 'The requested URL returned error: 403' in stderr or 'abort: Push access to %r denied' % str(vt.repo_name) in stderr
488 elif vt.repo_type == 'hg':
491 elif vt.repo_type == 'hg':
489 assert 'abort: HTTP Error 403: Forbidden' in stderr or 'abort: push failed on remote' in stderr and 'remote: Push access to %r denied' % str(vt.repo_name) in stdout
492 assert 'abort: HTTP Error 403: Forbidden' in stderr or 'abort: push failed on remote' in stderr and 'remote: Push access to %r denied' % str(vt.repo_name) in stdout
490
493
491 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
494 meta.Session.close() # make sure SA fetches all new log entries (apparently only needed for MariaDB/MySQL ...)
492 action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
495 action_parts = [ul.action.split(':', 1) for ul in db.UserLog.query().order_by(db.UserLog.user_log_id)]
493 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
496 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
494 [('pull', 0)]
497 [('pull', 0)]
495
498
496 @parametrize_vcs_test
499 @parametrize_vcs_test
497 def test_push_back_to_wrong_url(self, webserver, vt):
500 def test_push_back_to_wrong_url(self, webserver, vt):
498 dest_dir = _get_tmp_dir()
501 dest_dir = _get_tmp_dir()
499 clone_url = vt.repo_url_param(webserver, vt.repo_name)
502 clone_url = vt.repo_url_param(webserver, vt.repo_name)
500 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
503 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
501
504
502 stdout, stderr = _add_files_and_push(
505 stdout, stderr = _add_files_and_push(
503 webserver, vt, dest_dir, clone_url='http://%s:%s/tmp' % (
506 webserver, vt, dest_dir, clone_url='http://%s:%s/tmp' % (
504 webserver.server_address[0], webserver.server_address[1]),
507 webserver.server_address[0], webserver.server_address[1]),
505 ignoreReturnCode=True)
508 ignoreReturnCode=True)
506
509
507 if vt.repo_type == 'git':
510 if vt.repo_type == 'git':
508 assert 'not found' in stderr
511 assert 'not found' in stderr
509 elif vt.repo_type == 'hg':
512 elif vt.repo_type == 'hg':
510 assert 'HTTP Error 404: Not Found' in stderr
513 assert 'HTTP Error 404: Not Found' in stderr
511
514
512 @parametrize_vcs_test
515 @parametrize_vcs_test
513 def test_ip_restriction(self, webserver, vt):
516 def test_ip_restriction(self, webserver, vt):
514 user_model = UserModel()
517 user_model = UserModel()
515 try:
518 try:
516 # Add IP constraint that excludes the test context:
519 # Add IP constraint that excludes the test context:
517 user_model.add_extra_ip(base.TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
520 user_model.add_extra_ip(base.TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
518 meta.Session().commit()
521 meta.Session().commit()
519 # IP permissions are cached, need to wait for the cache in the server process to expire
522 # IP permissions are cached, need to wait for the cache in the server process to expire
520 time.sleep(1.5)
523 time.sleep(1.5)
521 clone_url = vt.repo_url_param(webserver, vt.repo_name)
524 clone_url = vt.repo_url_param(webserver, vt.repo_name)
522 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
525 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
523 if vt.repo_type == 'git':
526 if vt.repo_type == 'git':
524 # The message apparently changed in Git 1.8.3, so match it loosely.
527 # The message apparently changed in Git 1.8.3, so match it loosely.
525 assert re.search(r'\b403\b', stderr) or 'abort: User test_admin from 127.0.0.127 cannot be authorized' in stderr
528 assert re.search(r'\b403\b', stderr) or 'abort: User test_admin from 127.0.0.127 cannot be authorized' in stderr
526 elif vt.repo_type == 'hg':
529 elif vt.repo_type == 'hg':
527 assert 'abort: HTTP Error 403: Forbidden' in stderr or 'remote: abort: User test_admin from 127.0.0.127 cannot be authorized' in stdout + stderr
530 assert 'abort: HTTP Error 403: Forbidden' in stderr or 'remote: abort: User test_admin from 127.0.0.127 cannot be authorized' in stdout + stderr
528 finally:
531 finally:
529 # release IP restrictions
532 # release IP restrictions
530 for ip in db.UserIpMap.query():
533 for ip in db.UserIpMap.query():
531 db.UserIpMap.delete(ip.ip_id)
534 db.UserIpMap.delete(ip.ip_id)
532 meta.Session().commit()
535 meta.Session().commit()
533 # IP permissions are cached, need to wait for the cache in the server process to expire
536 # IP permissions are cached, need to wait for the cache in the server process to expire
534 time.sleep(1.5)
537 time.sleep(1.5)
535
538
536 clone_url = vt.repo_url_param(webserver, vt.repo_name)
539 clone_url = vt.repo_url_param(webserver, vt.repo_name)
537 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
540 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
538
541
539 if vt.repo_type == 'git':
542 if vt.repo_type == 'git':
540 assert 'Cloning into' in stdout + stderr
543 assert 'Cloning into' in stdout + stderr
541 assert stderr == '' or stdout == ''
544 assert stderr == '' or stdout == ''
542 elif vt.repo_type == 'hg':
545 elif vt.repo_type == 'hg':
543 assert 'requesting all changes' in stdout
546 assert 'requesting all changes' in stdout
544 assert 'adding changesets' in stdout
547 assert 'adding changesets' in stdout
545 assert 'adding manifests' in stdout
548 assert 'adding manifests' in stdout
546 assert 'adding file changes' in stdout
549 assert 'adding file changes' in stdout
547
550
548 assert stderr == ''
551 assert stderr == ''
549
552
550 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
553 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
551 def test_custom_hooks_preoutgoing(self, testhook_cleanup, webserver, testfork, vt):
554 def test_custom_hooks_preoutgoing(self, testhook_cleanup, webserver, testfork, vt):
552 # set prechangegroup to failing hook (returns True)
555 # set prechangegroup to failing hook (returns True)
553 db.Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
556 db.Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
554 meta.Session().commit()
557 meta.Session().commit()
555 # clone repo
558 # clone repo
556 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
559 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
557 dest_dir = _get_tmp_dir()
560 dest_dir = _get_tmp_dir()
558 stdout, stderr = Command(base.TESTS_TMP_PATH) \
561 stdout, stderr = Command(base.TESTS_TMP_PATH) \
559 .execute(vt.repo_type, 'clone', clone_url, dest_dir, ignoreReturnCode=True)
562 .execute(vt.repo_type, 'clone', clone_url, dest_dir, ignoreReturnCode=True)
560 if vt.repo_type == 'hg':
563 if vt.repo_type == 'hg':
561 assert 'preoutgoing.testhook hook failed' in stdout + stderr
564 assert 'preoutgoing.testhook hook failed' in stdout + stderr
562 elif vt.repo_type == 'git':
565 elif vt.repo_type == 'git':
563 assert 'error: 406' in stderr
566 assert 'error: 406' in stderr
564
567
565 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
568 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
566 def test_custom_hooks_prechangegroup(self, testhook_cleanup, webserver, testfork, vt):
569 def test_custom_hooks_prechangegroup(self, testhook_cleanup, webserver, testfork, vt):
567 # set prechangegroup to failing hook (returns exit code 1)
570 # set prechangegroup to failing hook (returns exit code 1)
568 db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
571 db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
569 meta.Session().commit()
572 meta.Session().commit()
570 # clone repo
573 # clone repo
571 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
574 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=base.TEST_USER_ADMIN_LOGIN, password=base.TEST_USER_ADMIN_PASS)
572 dest_dir = _get_tmp_dir()
575 dest_dir = _get_tmp_dir()
573 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
576 stdout, stderr = Command(base.TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
574
577
575 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url,
578 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url,
576 ignoreReturnCode=True)
579 ignoreReturnCode=True)
577 assert 'failing_test_hook failed' in stdout + stderr
580 assert 'failing_test_hook failed' in stdout + stderr
578 assert 'Traceback' not in stdout + stderr
581 assert 'Traceback' not in stdout + stderr
579 assert 'prechangegroup.testhook hook failed' in stdout + stderr
582 assert 'prechangegroup.testhook hook failed' in stdout + stderr
580 # there are still outgoing changesets
583 # there are still outgoing changesets
581 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
584 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
582 assert stdout != ''
585 assert stdout != ''
583
586
584 # set prechangegroup hook to exception throwing method
587 # set prechangegroup hook to exception throwing method
585 db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
588 db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
586 meta.Session().commit()
589 meta.Session().commit()
587 # re-try to push
590 # re-try to push
588 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
591 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
589 if vt is HgHttpVcsTest:
592 if vt is HgHttpVcsTest:
590 # like with 'hg serve...' 'HTTP Error 500: INTERNAL SERVER ERROR' should be returned
593 # like with 'hg serve...' 'HTTP Error 500: INTERNAL SERVER ERROR' should be returned
591 assert 'HTTP Error 500: INTERNAL SERVER ERROR' in stderr
594 assert 'HTTP Error 500: INTERNAL SERVER ERROR' in stderr
592 elif vt is HgSshVcsTest:
595 elif vt is HgSshVcsTest:
593 assert 'remote: Exception: exception_test_hook threw an exception' in stdout
596 assert 'remote: Exception: exception_test_hook threw an exception' in stdout
594 else: assert False
597 else: assert False
595 # there are still outgoing changesets
598 # there are still outgoing changesets
596 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
599 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
597 assert stdout != ''
600 assert stdout != ''
598
601
599 # set prechangegroup hook to method that returns False
602 # set prechangegroup hook to method that returns False
600 db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
603 db.Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
601 meta.Session().commit()
604 meta.Session().commit()
602 # re-try to push
605 # re-try to push
603 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
606 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
604 assert 'passing_test_hook succeeded' in stdout + stderr
607 assert 'passing_test_hook succeeded' in stdout + stderr
605 assert 'Traceback' not in stdout + stderr
608 assert 'Traceback' not in stdout + stderr
606 assert 'prechangegroup.testhook hook failed' not in stdout + stderr
609 assert 'prechangegroup.testhook hook failed' not in stdout + stderr
607 # no more outgoing changesets
610 # no more outgoing changesets
608 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
611 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
609 assert stdout == ''
612 assert stdout == ''
610 assert stderr == ''
613 assert stderr == ''
611
614
612 def test_add_submodule_git(self, webserver, testfork):
615 def test_add_submodule_git(self, webserver, testfork):
613 dest_dir = _get_tmp_dir()
616 dest_dir = _get_tmp_dir()
614 clone_url = GitHttpVcsTest.repo_url_param(webserver, base.GIT_REPO)
617 clone_url = GitHttpVcsTest.repo_url_param(webserver, base.GIT_REPO)
615
618
616 fork_url = GitHttpVcsTest.repo_url_param(webserver, testfork['git'])
619 fork_url = GitHttpVcsTest.repo_url_param(webserver, testfork['git'])
617
620
618 # add submodule
621 # add submodule
619 stdout, stderr = Command(base.TESTS_TMP_PATH).execute('git clone', fork_url, dest_dir)
622 stdout, stderr = Command(base.TESTS_TMP_PATH).execute('git clone', fork_url, dest_dir)
620 stdout, stderr = Command(dest_dir).execute('git submodule add', clone_url, 'testsubmodule')
623 stdout, stderr = Command(dest_dir).execute('git submodule add', clone_url, 'testsubmodule')
621 stdout, stderr = Command(dest_dir).execute('git commit -am "added testsubmodule pointing to', clone_url, '"', EMAIL=base.TEST_USER_ADMIN_EMAIL)
624 stdout, stderr = Command(dest_dir).execute('git commit -am "added testsubmodule pointing to', clone_url, '"')
622 stdout, stderr = Command(dest_dir).execute('git push', fork_url, 'master')
625 stdout, stderr = Command(dest_dir).execute('git push', fork_url, 'master')
623
626
624 # check for testsubmodule link in files page
627 # check for testsubmodule link in files page
625 self.log_user()
628 self.log_user()
626 response = self.app.get(base.url(controller='files', action='index',
629 response = self.app.get(base.url(controller='files', action='index',
627 repo_name=testfork['git'],
630 repo_name=testfork['git'],
628 revision='tip',
631 revision='tip',
629 f_path='/'))
632 f_path='/'))
630 # check _repo_files_url that will be used to reload as AJAX
633 # check _repo_files_url that will be used to reload as AJAX
631 response.mustcontain('var _repo_files_url = ("/%s/files/");' % testfork['git'])
634 response.mustcontain('var _repo_files_url = ("/%s/files/");' % testfork['git'])
632
635
633 response.mustcontain('<a class="submodule-dir" href="%s" target="_blank"><i class="icon-file-submodule"></i><span>testsubmodule @ ' % clone_url)
636 response.mustcontain('<a class="submodule-dir" href="%s" target="_blank"><i class="icon-file-submodule"></i><span>testsubmodule @ ' % clone_url)
634
637
635 # check that following a submodule link actually works - and redirects
638 # check that following a submodule link actually works - and redirects
636 response = self.app.get(base.url(controller='files', action='index',
639 response = self.app.get(base.url(controller='files', action='index',
637 repo_name=testfork['git'],
640 repo_name=testfork['git'],
638 revision='tip',
641 revision='tip',
639 f_path='/testsubmodule'),
642 f_path='/testsubmodule'),
640 status=302)
643 status=302)
641 assert response.location == clone_url
644 assert response.location == clone_url
General Comments 0
You need to be logged in to leave comments. Login now