##// END OF EJS Templates
tests: push with force in test_vcs_operations.py _add_files_and_push...
Mads Kiilerich -
r7660:76e2072b default
parent child Browse files
Show More
@@ -1,577 +1,577 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 os
28 import os
29 import re
29 import re
30 import tempfile
30 import tempfile
31 import time
31 import time
32 import urllib2
32 import urllib2
33 import json
33 import json
34 from tempfile import _RandomNameSequence
34 from tempfile import _RandomNameSequence
35 from subprocess import Popen, PIPE
35 from subprocess import Popen, PIPE
36
36
37 import pytest
37 import pytest
38
38
39 from kallithea.tests.base import *
39 from kallithea.tests.base import *
40 from kallithea.tests.fixture import Fixture
40 from kallithea.tests.fixture import Fixture
41 from kallithea.model.db import User, Repository, UserIpMap, CacheInvalidation, Ui, UserLog
41 from kallithea.model.db import User, Repository, UserIpMap, CacheInvalidation, Ui, UserLog
42 from kallithea.model.meta import Session
42 from kallithea.model.meta import Session
43 from kallithea.model.repo import RepoModel
43 from kallithea.model.repo import RepoModel
44 from kallithea.model.user import UserModel
44 from kallithea.model.user import UserModel
45
45
46 DEBUG = True
46 DEBUG = True
47 HOST = '127.0.0.1:4999' # test host
47 HOST = '127.0.0.1:4999' # test host
48
48
49 fixture = Fixture()
49 fixture = Fixture()
50
50
51
51
52 # Parameterize different kinds of VCS testing - both the kind of VCS and the
52 # Parameterize different kinds of VCS testing - both the kind of VCS and the
53 # access method (HTTP/SSH)
53 # access method (HTTP/SSH)
54
54
55 # Mixin for using HTTP URLs
55 # Mixin for using HTTP URLs
56 class HttpVcsTest(object):
56 class HttpVcsTest(object):
57 @staticmethod
57 @staticmethod
58 def repo_url_param(webserver, repo_name, **kwargs):
58 def repo_url_param(webserver, repo_name, **kwargs):
59 return webserver.repo_url(repo_name, **kwargs)
59 return webserver.repo_url(repo_name, **kwargs)
60
60
61 # Mixins for using Mercurial and Git
61 # Mixins for using Mercurial and Git
62 class HgVcsTest(object):
62 class HgVcsTest(object):
63 repo_type = 'hg'
63 repo_type = 'hg'
64 repo_name = HG_REPO
64 repo_name = HG_REPO
65
65
66 class GitVcsTest(object):
66 class GitVcsTest(object):
67 repo_type = 'git'
67 repo_type = 'git'
68 repo_name = GIT_REPO
68 repo_name = GIT_REPO
69
69
70 # Combine mixins to give the combinations we want to parameterize tests with
70 # Combine mixins to give the combinations we want to parameterize tests with
71 class HgHttpVcsTest(HgVcsTest, HttpVcsTest):
71 class HgHttpVcsTest(HgVcsTest, HttpVcsTest):
72 pass
72 pass
73
73
74 class GitHttpVcsTest(GitVcsTest, HttpVcsTest):
74 class GitHttpVcsTest(GitVcsTest, HttpVcsTest):
75 pass
75 pass
76
76
77 parametrize_vcs_test = parametrize('vt', [
77 parametrize_vcs_test = parametrize('vt', [
78 HgHttpVcsTest,
78 HgHttpVcsTest,
79 GitHttpVcsTest,
79 GitHttpVcsTest,
80 ])
80 ])
81 parametrize_vcs_test_hg = parametrize('vt', [
81 parametrize_vcs_test_hg = parametrize('vt', [
82 HgHttpVcsTest,
82 HgHttpVcsTest,
83 ])
83 ])
84 parametrize_vcs_test_http = parametrize('vt', [
84 parametrize_vcs_test_http = parametrize('vt', [
85 HgHttpVcsTest,
85 HgHttpVcsTest,
86 GitHttpVcsTest,
86 GitHttpVcsTest,
87 ])
87 ])
88
88
89 class Command(object):
89 class Command(object):
90
90
91 def __init__(self, cwd):
91 def __init__(self, cwd):
92 self.cwd = cwd
92 self.cwd = cwd
93
93
94 def execute(self, *args, **environ):
94 def execute(self, *args, **environ):
95 """
95 """
96 Runs command on the system with given ``args`` using simple space
96 Runs command on the system with given ``args`` using simple space
97 join without safe quoting.
97 join without safe quoting.
98 """
98 """
99 command = ' '.join(args)
99 command = ' '.join(args)
100 ignoreReturnCode = environ.pop('ignoreReturnCode', False)
100 ignoreReturnCode = environ.pop('ignoreReturnCode', False)
101 if DEBUG:
101 if DEBUG:
102 print '*** CMD %s ***' % command
102 print '*** CMD %s ***' % command
103 testenv = dict(os.environ)
103 testenv = dict(os.environ)
104 testenv['LANG'] = 'en_US.UTF-8'
104 testenv['LANG'] = 'en_US.UTF-8'
105 testenv['LANGUAGE'] = 'en_US:en'
105 testenv['LANGUAGE'] = 'en_US:en'
106 testenv['HGPLAIN'] = ''
106 testenv['HGPLAIN'] = ''
107 testenv['HGRCPATH'] = ''
107 testenv['HGRCPATH'] = ''
108 testenv.update(environ)
108 testenv.update(environ)
109 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
109 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
110 stdout, stderr = p.communicate()
110 stdout, stderr = p.communicate()
111 if DEBUG:
111 if DEBUG:
112 if stdout:
112 if stdout:
113 print 'stdout:', stdout
113 print 'stdout:', stdout
114 if stderr:
114 if stderr:
115 print 'stderr:', stderr
115 print 'stderr:', stderr
116 if not ignoreReturnCode:
116 if not ignoreReturnCode:
117 assert p.returncode == 0
117 assert p.returncode == 0
118 return stdout, stderr
118 return stdout, stderr
119
119
120
120
121 def _get_tmp_dir(prefix='vcs_operations-', suffix=''):
121 def _get_tmp_dir(prefix='vcs_operations-', suffix=''):
122 return tempfile.mkdtemp(dir=TESTS_TMP_PATH, prefix=prefix, suffix=suffix)
122 return tempfile.mkdtemp(dir=TESTS_TMP_PATH, prefix=prefix, suffix=suffix)
123
123
124
124
125 def _add_files(vcs, dest_dir, files_no=3):
125 def _add_files(vcs, dest_dir, files_no=3):
126 """
126 """
127 Generate some files, add it to dest_dir repo and push back
127 Generate some files, add it to dest_dir repo and push back
128 vcs is git or hg and defines what VCS we want to make those files for
128 vcs is git or hg and defines what VCS we want to make those files for
129
129
130 :param vcs:
130 :param vcs:
131 :param dest_dir:
131 :param dest_dir:
132 """
132 """
133 added_file = '%ssetup.py' % _RandomNameSequence().next()
133 added_file = '%ssetup.py' % _RandomNameSequence().next()
134 open(os.path.join(dest_dir, added_file), 'a').close()
134 open(os.path.join(dest_dir, added_file), 'a').close()
135 Command(dest_dir).execute(vcs, 'add', added_file)
135 Command(dest_dir).execute(vcs, 'add', added_file)
136
136
137 email = 'me@example.com'
137 email = 'me@example.com'
138 if os.name == 'nt':
138 if os.name == 'nt':
139 author_str = 'User <%s>' % email
139 author_str = 'User <%s>' % email
140 else:
140 else:
141 author_str = 'User ǝɯɐᴎ <%s>' % email
141 author_str = 'User ǝɯɐᴎ <%s>' % email
142 for i in xrange(files_no):
142 for i in xrange(files_no):
143 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
143 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
144 Command(dest_dir).execute(cmd)
144 Command(dest_dir).execute(cmd)
145 if vcs == 'hg':
145 if vcs == 'hg':
146 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
146 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
147 i, author_str, added_file
147 i, author_str, added_file
148 )
148 )
149 elif vcs == 'git':
149 elif vcs == 'git':
150 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
150 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
151 i, author_str, added_file
151 i, author_str, added_file
152 )
152 )
153 # git commit needs EMAIL on some machines
153 # git commit needs EMAIL on some machines
154 Command(dest_dir).execute(cmd, EMAIL=email)
154 Command(dest_dir).execute(cmd, EMAIL=email)
155
155
156 def _add_files_and_push(webserver, vt, dest_dir, clone_url, ignoreReturnCode=False, files_no=3):
156 def _add_files_and_push(webserver, vt, dest_dir, clone_url, ignoreReturnCode=False, files_no=3):
157 _add_files(vt.repo_type, dest_dir, files_no=files_no)
157 _add_files(vt.repo_type, dest_dir, files_no=files_no)
158 # PUSH it back
158 # PUSH it back
159 stdout = stderr = None
159 stdout = stderr = None
160 if vt.repo_type == 'hg':
160 if vt.repo_type == 'hg':
161 stdout, stderr = Command(dest_dir).execute('hg push --verbose', clone_url, ignoreReturnCode=ignoreReturnCode)
161 stdout, stderr = Command(dest_dir).execute('hg push -f --verbose', clone_url, ignoreReturnCode=ignoreReturnCode)
162 elif vt.repo_type == 'git':
162 elif vt.repo_type == 'git':
163 stdout, stderr = Command(dest_dir).execute('git push --verbose', clone_url, "master", ignoreReturnCode=ignoreReturnCode)
163 stdout, stderr = Command(dest_dir).execute('git push -f --verbose', clone_url, "master", ignoreReturnCode=ignoreReturnCode)
164
164
165 return stdout, stderr
165 return stdout, stderr
166
166
167
167
168 def _check_outgoing(vcs, cwd, clone_url):
168 def _check_outgoing(vcs, cwd, clone_url):
169 if vcs == 'hg':
169 if vcs == 'hg':
170 # hg removes the password from default URLs, so we have to provide it here via the clone_url
170 # hg removes the password from default URLs, so we have to provide it here via the clone_url
171 return Command(cwd).execute('hg -q outgoing', clone_url, ignoreReturnCode=True)
171 return Command(cwd).execute('hg -q outgoing', clone_url, ignoreReturnCode=True)
172 elif vcs == 'git':
172 elif vcs == 'git':
173 Command(cwd).execute('git remote update')
173 Command(cwd).execute('git remote update')
174 return Command(cwd).execute('git log origin/master..master')
174 return Command(cwd).execute('git log origin/master..master')
175
175
176
176
177 def set_anonymous_access(enable=True):
177 def set_anonymous_access(enable=True):
178 user = User.get_default_user()
178 user = User.get_default_user()
179 user.active = enable
179 user.active = enable
180 Session().commit()
180 Session().commit()
181 if enable != User.get_default_user().active:
181 if enable != User.get_default_user().active:
182 raise Exception('Cannot set anonymous access')
182 raise Exception('Cannot set anonymous access')
183
183
184
184
185 #==============================================================================
185 #==============================================================================
186 # TESTS
186 # TESTS
187 #==============================================================================
187 #==============================================================================
188
188
189
189
190 def _check_proper_git_push(stdout, stderr):
190 def _check_proper_git_push(stdout, stderr):
191 assert 'fatal' not in stderr
191 assert 'fatal' not in stderr
192 assert 'rejected' not in stderr
192 assert 'rejected' not in stderr
193 assert 'Pushing to' in stderr
193 assert 'Pushing to' in stderr
194 assert 'master -> master' in stderr
194 assert 'master -> master' in stderr
195
195
196
196
197 @pytest.mark.usefixtures("test_context_fixture")
197 @pytest.mark.usefixtures("test_context_fixture")
198 class TestVCSOperations(TestController):
198 class TestVCSOperations(TestController):
199
199
200 @classmethod
200 @classmethod
201 def setup_class(cls):
201 def setup_class(cls):
202 # DISABLE ANONYMOUS ACCESS
202 # DISABLE ANONYMOUS ACCESS
203 set_anonymous_access(False)
203 set_anonymous_access(False)
204
204
205 @pytest.fixture()
205 @pytest.fixture()
206 def testhook_cleanup(self):
206 def testhook_cleanup(self):
207 yield
207 yield
208 # remove hook
208 # remove hook
209 for hook in ['prechangegroup', 'pretxnchangegroup', 'preoutgoing', 'changegroup', 'outgoing', 'incoming']:
209 for hook in ['prechangegroup', 'pretxnchangegroup', 'preoutgoing', 'changegroup', 'outgoing', 'incoming']:
210 entry = Ui.get_by_key('hooks', '%s.testhook' % hook)
210 entry = Ui.get_by_key('hooks', '%s.testhook' % hook)
211 if entry:
211 if entry:
212 Session().delete(entry)
212 Session().delete(entry)
213 Session().commit()
213 Session().commit()
214
214
215 @pytest.fixture(scope="module")
215 @pytest.fixture(scope="module")
216 def testfork(self):
216 def testfork(self):
217 # create fork so the repo stays untouched
217 # create fork so the repo stays untouched
218 git_fork_name = u'%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
218 git_fork_name = u'%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
219 fixture.create_fork(GIT_REPO, git_fork_name)
219 fixture.create_fork(GIT_REPO, git_fork_name)
220 hg_fork_name = u'%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
220 hg_fork_name = u'%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
221 fixture.create_fork(HG_REPO, hg_fork_name)
221 fixture.create_fork(HG_REPO, hg_fork_name)
222 return {'git': git_fork_name, 'hg': hg_fork_name}
222 return {'git': git_fork_name, 'hg': hg_fork_name}
223
223
224 @parametrize_vcs_test
224 @parametrize_vcs_test
225 def test_clone_repo_by_admin(self, webserver, vt):
225 def test_clone_repo_by_admin(self, webserver, vt):
226 clone_url = vt.repo_url_param(webserver, vt.repo_name)
226 clone_url = vt.repo_url_param(webserver, vt.repo_name)
227 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
227 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
228
228
229 if vt.repo_type == 'git':
229 if vt.repo_type == 'git':
230 assert 'Cloning into' in stdout + stderr
230 assert 'Cloning into' in stdout + stderr
231 assert stderr == '' or stdout == ''
231 assert stderr == '' or stdout == ''
232 elif vt.repo_type == 'hg':
232 elif vt.repo_type == 'hg':
233 assert 'requesting all changes' in stdout
233 assert 'requesting all changes' in stdout
234 assert 'adding changesets' in stdout
234 assert 'adding changesets' in stdout
235 assert 'adding manifests' in stdout
235 assert 'adding manifests' in stdout
236 assert 'adding file changes' in stdout
236 assert 'adding file changes' in stdout
237 assert stderr == ''
237 assert stderr == ''
238
238
239 @parametrize_vcs_test_http
239 @parametrize_vcs_test_http
240 def test_clone_wrong_credentials(self, webserver, vt):
240 def test_clone_wrong_credentials(self, webserver, vt):
241 clone_url = vt.repo_url_param(webserver, vt.repo_name, password='bad!')
241 clone_url = vt.repo_url_param(webserver, vt.repo_name, password='bad!')
242 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
242 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
243 if vt.repo_type == 'git':
243 if vt.repo_type == 'git':
244 assert 'fatal: Authentication failed' in stderr
244 assert 'fatal: Authentication failed' in stderr
245 elif vt.repo_type == 'hg':
245 elif vt.repo_type == 'hg':
246 assert 'abort: authorization failed' in stderr
246 assert 'abort: authorization failed' in stderr
247
247
248 def test_clone_git_dir_as_hg(self, webserver):
248 def test_clone_git_dir_as_hg(self, webserver):
249 clone_url = HgHttpVcsTest.repo_url_param(webserver, GIT_REPO)
249 clone_url = HgHttpVcsTest.repo_url_param(webserver, GIT_REPO)
250 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
250 stdout, stderr = Command(TESTS_TMP_PATH).execute('hg clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
251 assert 'HTTP Error 404: Not Found' in stderr
251 assert 'HTTP Error 404: Not Found' in stderr
252
252
253 def test_clone_hg_repo_as_git(self, webserver):
253 def test_clone_hg_repo_as_git(self, webserver):
254 clone_url = GitHttpVcsTest.repo_url_param(webserver, HG_REPO)
254 clone_url = GitHttpVcsTest.repo_url_param(webserver, HG_REPO)
255 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
255 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
256 assert 'not found' in stderr
256 assert 'not found' in stderr
257
257
258 @parametrize_vcs_test
258 @parametrize_vcs_test
259 def test_clone_non_existing_path(self, webserver, vt):
259 def test_clone_non_existing_path(self, webserver, vt):
260 clone_url = vt.repo_url_param(webserver, 'trololo')
260 clone_url = vt.repo_url_param(webserver, 'trololo')
261 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
261 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
262 if vt.repo_type == 'git':
262 if vt.repo_type == 'git':
263 assert 'not found' in stderr
263 assert 'not found' in stderr
264 elif vt.repo_type == 'hg':
264 elif vt.repo_type == 'hg':
265 assert 'HTTP Error 404: Not Found' in stderr
265 assert 'HTTP Error 404: Not Found' in stderr
266
266
267 @parametrize_vcs_test
267 @parametrize_vcs_test
268 def test_push_new_repo(self, webserver, vt):
268 def test_push_new_repo(self, webserver, vt):
269 # Clear the log so we know what is added
269 # Clear the log so we know what is added
270 UserLog.query().delete()
270 UserLog.query().delete()
271 Session().commit()
271 Session().commit()
272
272
273 # Create an empty server repo using the API
273 # Create an empty server repo using the API
274 repo_name = u'new_%s_%s' % (vt.repo_type, _RandomNameSequence().next())
274 repo_name = u'new_%s_%s' % (vt.repo_type, _RandomNameSequence().next())
275 usr = User.get_by_username(TEST_USER_ADMIN_LOGIN)
275 usr = User.get_by_username(TEST_USER_ADMIN_LOGIN)
276 params = {
276 params = {
277 "id": 7,
277 "id": 7,
278 "api_key": usr.api_key,
278 "api_key": usr.api_key,
279 "method": 'create_repo',
279 "method": 'create_repo',
280 "args": dict(repo_name=repo_name,
280 "args": dict(repo_name=repo_name,
281 owner=TEST_USER_ADMIN_LOGIN,
281 owner=TEST_USER_ADMIN_LOGIN,
282 repo_type=vt.repo_type),
282 repo_type=vt.repo_type),
283 }
283 }
284 req = urllib2.Request(
284 req = urllib2.Request(
285 'http://%s:%s/_admin/api' % webserver.server_address,
285 'http://%s:%s/_admin/api' % webserver.server_address,
286 data=json.dumps(params),
286 data=json.dumps(params),
287 headers={'content-type': 'application/json'})
287 headers={'content-type': 'application/json'})
288 response = urllib2.urlopen(req)
288 response = urllib2.urlopen(req)
289 result = json.loads(response.read())
289 result = json.loads(response.read())
290 # Expect something like:
290 # Expect something like:
291 # {u'result': {u'msg': u'Created new repository `new_XXX`', u'task': None, u'success': True}, u'id': 7, u'error': None}
291 # {u'result': {u'msg': u'Created new repository `new_XXX`', u'task': None, u'success': True}, u'id': 7, u'error': None}
292 assert result[u'result'][u'success']
292 assert result[u'result'][u'success']
293
293
294 # Create local clone of the empty server repo
294 # Create local clone of the empty server repo
295 local_clone_dir = _get_tmp_dir()
295 local_clone_dir = _get_tmp_dir()
296 clone_url = vt.repo_url_param(webserver, repo_name)
296 clone_url = vt.repo_url_param(webserver, repo_name)
297 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, local_clone_dir)
297 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, local_clone_dir)
298
298
299 # Make 3 commits and push to the empty server repo.
299 # Make 3 commits and push to the empty server repo.
300 # The server repo doesn't have any other heads than the
300 # The server repo doesn't have any other heads than the
301 # refs/heads/master we are pushing, but the `git log` in the push hook
301 # refs/heads/master we are pushing, but the `git log` in the push hook
302 # should still list the 3 commits.
302 # should still list the 3 commits.
303 stdout, stderr = _add_files_and_push(webserver, vt, local_clone_dir, clone_url=clone_url)
303 stdout, stderr = _add_files_and_push(webserver, vt, local_clone_dir, clone_url=clone_url)
304 if vt.repo_type == 'git':
304 if vt.repo_type == 'git':
305 _check_proper_git_push(stdout, stderr)
305 _check_proper_git_push(stdout, stderr)
306 elif vt.repo_type == 'hg':
306 elif vt.repo_type == 'hg':
307 assert 'pushing to ' in stdout
307 assert 'pushing to ' in stdout
308 assert 'remote: added ' in stdout
308 assert 'remote: added ' in stdout
309
309
310 # Verify that we got the right events in UserLog. Expect something like:
310 # Verify that we got the right events in UserLog. Expect something like:
311 # <UserLog('id:new_git_XXX:started_following_repo')>
311 # <UserLog('id:new_git_XXX:started_following_repo')>
312 # <UserLog('id:new_git_XXX:user_created_repo')>
312 # <UserLog('id:new_git_XXX:user_created_repo')>
313 # <UserLog('id:new_git_XXX:pull')>
313 # <UserLog('id:new_git_XXX:pull')>
314 # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')>
314 # <UserLog('id:new_git_XXX:push:aed9d4c1732a1927da3be42c47eb9afdc200d427,d38b083a07af10a9f44193486959a96a23db78da,4841ff9a2b385bec995f4679ef649adb3f437622')>
315 action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
315 action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
316 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == ([
316 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == ([
317 (u'started_following_repo', 0),
317 (u'started_following_repo', 0),
318 (u'user_created_repo', 0),
318 (u'user_created_repo', 0),
319 (u'pull', 0),
319 (u'pull', 0),
320 (u'push', 3)]
320 (u'push', 3)]
321 if vt.repo_type == 'git' else [
321 if vt.repo_type == 'git' else [
322 (u'started_following_repo', 0),
322 (u'started_following_repo', 0),
323 (u'user_created_repo', 0),
323 (u'user_created_repo', 0),
324 # (u'pull', 0), # Mercurial outgoing hook is not called for empty clones
324 # (u'pull', 0), # Mercurial outgoing hook is not called for empty clones
325 (u'push', 3)])
325 (u'push', 3)])
326
326
327 @parametrize_vcs_test
327 @parametrize_vcs_test
328 def test_push_new_file(self, webserver, testfork, vt):
328 def test_push_new_file(self, webserver, testfork, vt):
329 UserLog.query().delete()
329 UserLog.query().delete()
330 Session().commit()
330 Session().commit()
331
331
332 dest_dir = _get_tmp_dir()
332 dest_dir = _get_tmp_dir()
333 clone_url = vt.repo_url_param(webserver, vt.repo_name)
333 clone_url = vt.repo_url_param(webserver, vt.repo_name)
334 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
334 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
335
335
336 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
336 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
337 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url=clone_url)
337 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url=clone_url)
338
338
339 if vt.repo_type == 'git':
339 if vt.repo_type == 'git':
340 _check_proper_git_push(stdout, stderr)
340 _check_proper_git_push(stdout, stderr)
341 elif vt.repo_type == 'hg':
341 elif vt.repo_type == 'hg':
342 assert 'pushing to' in stdout
342 assert 'pushing to' in stdout
343 assert 'Repository size' in stdout
343 assert 'Repository size' in stdout
344 assert 'Last revision is now' in stdout
344 assert 'Last revision is now' in stdout
345
345
346 action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
346 action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
347 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
347 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
348 [(u'pull', 0), (u'push', 3)]
348 [(u'pull', 0), (u'push', 3)]
349
349
350 @parametrize_vcs_test
350 @parametrize_vcs_test
351 def test_pull(self, webserver, testfork, vt):
351 def test_pull(self, webserver, testfork, vt):
352 UserLog.query().delete()
352 UserLog.query().delete()
353 Session().commit()
353 Session().commit()
354
354
355 dest_dir = _get_tmp_dir()
355 dest_dir = _get_tmp_dir()
356 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'init', dest_dir)
356 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'init', dest_dir)
357
357
358 clone_url = vt.repo_url_param(webserver, vt.repo_name)
358 clone_url = vt.repo_url_param(webserver, vt.repo_name)
359 print (vt, clone_url)
359 print (vt, clone_url)
360 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url)
360 stdout, stderr = Command(dest_dir).execute(vt.repo_type, 'pull', clone_url)
361
361
362 if vt.repo_type == 'git':
362 if vt.repo_type == 'git':
363 assert 'FETCH_HEAD' in stderr
363 assert 'FETCH_HEAD' in stderr
364 elif vt.repo_type == 'hg':
364 elif vt.repo_type == 'hg':
365 assert 'new changesets' in stdout
365 assert 'new changesets' in stdout
366
366
367 action_parts = [ul.action for ul in UserLog.query().order_by(UserLog.user_log_id)]
367 action_parts = [ul.action for ul in UserLog.query().order_by(UserLog.user_log_id)]
368 assert action_parts == [u'pull']
368 assert action_parts == [u'pull']
369
369
370 @parametrize_vcs_test
370 @parametrize_vcs_test
371 def test_push_invalidates_cache(self, webserver, testfork, vt):
371 def test_push_invalidates_cache(self, webserver, testfork, vt):
372 pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
372 pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
373
373
374 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
374 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
375 == testfork[vt.repo_type]).scalar()
375 == testfork[vt.repo_type]).scalar()
376 if not key:
376 if not key:
377 key = CacheInvalidation(testfork[vt.repo_type], testfork[vt.repo_type])
377 key = CacheInvalidation(testfork[vt.repo_type], testfork[vt.repo_type])
378 Session().add(key)
378 Session().add(key)
379
379
380 key.cache_active = True
380 key.cache_active = True
381 Session().commit()
381 Session().commit()
382
382
383 dest_dir = _get_tmp_dir()
383 dest_dir = _get_tmp_dir()
384 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
384 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type])
385 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
385 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
386
386
387 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, files_no=1, clone_url=clone_url)
387 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, files_no=1, clone_url=clone_url)
388
388
389 if vt.repo_type == 'git':
389 if vt.repo_type == 'git':
390 _check_proper_git_push(stdout, stderr)
390 _check_proper_git_push(stdout, stderr)
391
391
392 post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
392 post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in Repository.query().filter(Repository.repo_name == testfork[vt.repo_type])]
393 assert pre_cached_tip != post_cached_tip
393 assert pre_cached_tip != post_cached_tip
394
394
395 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
395 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
396 == testfork[vt.repo_type]).all()
396 == testfork[vt.repo_type]).all()
397 assert key == []
397 assert key == []
398
398
399 @parametrize_vcs_test_http
399 @parametrize_vcs_test_http
400 def test_push_wrong_credentials(self, webserver, vt):
400 def test_push_wrong_credentials(self, webserver, vt):
401 dest_dir = _get_tmp_dir()
401 dest_dir = _get_tmp_dir()
402 clone_url = vt.repo_url_param(webserver, vt.repo_name)
402 clone_url = vt.repo_url_param(webserver, vt.repo_name)
403 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
403 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
404
404
405 clone_url = webserver.repo_url(vt.repo_name, username='bad', password='name')
405 clone_url = webserver.repo_url(vt.repo_name, username='bad', password='name')
406 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir,
406 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir,
407 clone_url=clone_url, ignoreReturnCode=True)
407 clone_url=clone_url, ignoreReturnCode=True)
408
408
409 if vt.repo_type == 'git':
409 if vt.repo_type == 'git':
410 assert 'fatal: Authentication failed' in stderr
410 assert 'fatal: Authentication failed' in stderr
411 elif vt.repo_type == 'hg':
411 elif vt.repo_type == 'hg':
412 assert 'abort: authorization failed' in stderr
412 assert 'abort: authorization failed' in stderr
413
413
414 @parametrize_vcs_test
414 @parametrize_vcs_test
415 def test_push_with_readonly_credentials(self, webserver, vt):
415 def test_push_with_readonly_credentials(self, webserver, vt):
416 UserLog.query().delete()
416 UserLog.query().delete()
417 Session().commit()
417 Session().commit()
418
418
419 dest_dir = _get_tmp_dir()
419 dest_dir = _get_tmp_dir()
420 clone_url = vt.repo_url_param(webserver, vt.repo_name, username=TEST_USER_REGULAR_LOGIN, password=TEST_USER_REGULAR_PASS)
420 clone_url = vt.repo_url_param(webserver, vt.repo_name, username=TEST_USER_REGULAR_LOGIN, password=TEST_USER_REGULAR_PASS)
421 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
421 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
422
422
423 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, ignoreReturnCode=True, clone_url=clone_url)
423 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, ignoreReturnCode=True, clone_url=clone_url)
424
424
425 if vt.repo_type == 'git':
425 if vt.repo_type == 'git':
426 assert 'The requested URL returned error: 403' in stderr
426 assert 'The requested URL returned error: 403' in stderr
427 elif vt.repo_type == 'hg':
427 elif vt.repo_type == 'hg':
428 assert 'abort: HTTP Error 403: Forbidden' in stderr
428 assert 'abort: HTTP Error 403: Forbidden' in stderr
429
429
430 action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
430 action_parts = [ul.action.split(':', 1) for ul in UserLog.query().order_by(UserLog.user_log_id)]
431 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
431 assert [(t[0], (t[1].count(',') + 1) if len(t) == 2 else 0) for t in action_parts] == \
432 [(u'pull', 0)]
432 [(u'pull', 0)]
433
433
434 @parametrize_vcs_test
434 @parametrize_vcs_test
435 def test_push_back_to_wrong_url(self, webserver, vt):
435 def test_push_back_to_wrong_url(self, webserver, vt):
436 dest_dir = _get_tmp_dir()
436 dest_dir = _get_tmp_dir()
437 clone_url = vt.repo_url_param(webserver, vt.repo_name)
437 clone_url = vt.repo_url_param(webserver, vt.repo_name)
438 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
438 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
439
439
440 stdout, stderr = _add_files_and_push(
440 stdout, stderr = _add_files_and_push(
441 webserver, vt, dest_dir, clone_url='http://%s:%s/tmp' % (
441 webserver, vt, dest_dir, clone_url='http://%s:%s/tmp' % (
442 webserver.server_address[0], webserver.server_address[1]),
442 webserver.server_address[0], webserver.server_address[1]),
443 ignoreReturnCode=True)
443 ignoreReturnCode=True)
444
444
445 if vt.repo_type == 'git':
445 if vt.repo_type == 'git':
446 assert 'not found' in stderr
446 assert 'not found' in stderr
447 elif vt.repo_type == 'hg':
447 elif vt.repo_type == 'hg':
448 assert 'HTTP Error 404: Not Found' in stderr
448 assert 'HTTP Error 404: Not Found' in stderr
449
449
450 @parametrize_vcs_test
450 @parametrize_vcs_test
451 def test_ip_restriction(self, webserver, vt):
451 def test_ip_restriction(self, webserver, vt):
452 user_model = UserModel()
452 user_model = UserModel()
453 try:
453 try:
454 # Add IP constraint that excludes the test context:
454 # Add IP constraint that excludes the test context:
455 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
455 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
456 Session().commit()
456 Session().commit()
457 # IP permissions are cached, need to wait for the cache in the server process to expire
457 # IP permissions are cached, need to wait for the cache in the server process to expire
458 time.sleep(1.5)
458 time.sleep(1.5)
459 clone_url = vt.repo_url_param(webserver, vt.repo_name)
459 clone_url = vt.repo_url_param(webserver, vt.repo_name)
460 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
460 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir(), ignoreReturnCode=True)
461 if vt.repo_type == 'git':
461 if vt.repo_type == 'git':
462 # The message apparently changed in Git 1.8.3, so match it loosely.
462 # The message apparently changed in Git 1.8.3, so match it loosely.
463 assert re.search(r'\b403\b', stderr)
463 assert re.search(r'\b403\b', stderr)
464 elif vt.repo_type == 'hg':
464 elif vt.repo_type == 'hg':
465 assert 'abort: HTTP Error 403: Forbidden' in stderr
465 assert 'abort: HTTP Error 403: Forbidden' in stderr
466 finally:
466 finally:
467 # release IP restrictions
467 # release IP restrictions
468 for ip in UserIpMap.query():
468 for ip in UserIpMap.query():
469 UserIpMap.delete(ip.ip_id)
469 UserIpMap.delete(ip.ip_id)
470 Session().commit()
470 Session().commit()
471 # IP permissions are cached, need to wait for the cache in the server process to expire
471 # IP permissions are cached, need to wait for the cache in the server process to expire
472 time.sleep(1.5)
472 time.sleep(1.5)
473
473
474 clone_url = vt.repo_url_param(webserver, vt.repo_name)
474 clone_url = vt.repo_url_param(webserver, vt.repo_name)
475 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
475 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, _get_tmp_dir())
476
476
477 if vt.repo_type == 'git':
477 if vt.repo_type == 'git':
478 assert 'Cloning into' in stdout + stderr
478 assert 'Cloning into' in stdout + stderr
479 assert stderr == '' or stdout == ''
479 assert stderr == '' or stdout == ''
480 elif vt.repo_type == 'hg':
480 elif vt.repo_type == 'hg':
481 assert 'requesting all changes' in stdout
481 assert 'requesting all changes' in stdout
482 assert 'adding changesets' in stdout
482 assert 'adding changesets' in stdout
483 assert 'adding manifests' in stdout
483 assert 'adding manifests' in stdout
484 assert 'adding file changes' in stdout
484 assert 'adding file changes' in stdout
485
485
486 assert stderr == ''
486 assert stderr == ''
487
487
488 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
488 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
489 def test_custom_hooks_preoutgoing(self, testhook_cleanup, webserver, testfork, vt):
489 def test_custom_hooks_preoutgoing(self, testhook_cleanup, webserver, testfork, vt):
490 # set prechangegroup to failing hook (returns True)
490 # set prechangegroup to failing hook (returns True)
491 Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
491 Ui.create_or_update_hook('preoutgoing.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
492 Session().commit()
492 Session().commit()
493 # clone repo
493 # clone repo
494 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS)
494 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS)
495 dest_dir = _get_tmp_dir()
495 dest_dir = _get_tmp_dir()
496 stdout, stderr = Command(TESTS_TMP_PATH) \
496 stdout, stderr = Command(TESTS_TMP_PATH) \
497 .execute(vt.repo_type, 'clone', clone_url, dest_dir, ignoreReturnCode=True)
497 .execute(vt.repo_type, 'clone', clone_url, dest_dir, ignoreReturnCode=True)
498 if vt.repo_type == 'hg':
498 if vt.repo_type == 'hg':
499 assert 'preoutgoing.testhook hook failed' in stdout
499 assert 'preoutgoing.testhook hook failed' in stdout
500 elif vt.repo_type == 'git':
500 elif vt.repo_type == 'git':
501 assert 'error: 406' in stderr
501 assert 'error: 406' in stderr
502
502
503 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
503 @parametrize_vcs_test_hg # git hooks doesn't work like hg hooks
504 def test_custom_hooks_prechangegroup(self, testhook_cleanup, webserver, testfork, vt):
504 def test_custom_hooks_prechangegroup(self, testhook_cleanup, webserver, testfork, vt):
505 # set prechangegroup to failing hook (returns exit code 1)
505 # set prechangegroup to failing hook (returns exit code 1)
506 Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
506 Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.failing_test_hook')
507 Session().commit()
507 Session().commit()
508 # clone repo
508 # clone repo
509 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS)
509 clone_url = vt.repo_url_param(webserver, testfork[vt.repo_type], username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS)
510 dest_dir = _get_tmp_dir()
510 dest_dir = _get_tmp_dir()
511 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
511 stdout, stderr = Command(TESTS_TMP_PATH).execute(vt.repo_type, 'clone', clone_url, dest_dir)
512
512
513 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url,
513 stdout, stderr = _add_files_and_push(webserver, vt, dest_dir, clone_url,
514 ignoreReturnCode=True)
514 ignoreReturnCode=True)
515 assert 'failing_test_hook failed' in stdout + stderr
515 assert 'failing_test_hook failed' in stdout + stderr
516 assert 'Traceback' not in stdout + stderr
516 assert 'Traceback' not in stdout + stderr
517 assert 'prechangegroup.testhook hook failed' in stdout + stderr
517 assert 'prechangegroup.testhook hook failed' in stdout + stderr
518 # there are still outgoing changesets
518 # there are still outgoing changesets
519 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
519 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
520 assert stdout != ''
520 assert stdout != ''
521
521
522 # set prechangegroup hook to exception throwing method
522 # set prechangegroup hook to exception throwing method
523 Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
523 Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.exception_test_hook')
524 Session().commit()
524 Session().commit()
525 # re-try to push
525 # re-try to push
526 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
526 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
527 if vt is HgHttpVcsTest:
527 if vt is HgHttpVcsTest:
528 # like with 'hg serve...' 'HTTP Error 500: INTERNAL SERVER ERROR' should be returned
528 # like with 'hg serve...' 'HTTP Error 500: INTERNAL SERVER ERROR' should be returned
529 assert 'HTTP Error 500: INTERNAL SERVER ERROR' in stderr
529 assert 'HTTP Error 500: INTERNAL SERVER ERROR' in stderr
530 else: assert False
530 else: assert False
531 # there are still outgoing changesets
531 # there are still outgoing changesets
532 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
532 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
533 assert stdout != ''
533 assert stdout != ''
534
534
535 # set prechangegroup hook to method that returns False
535 # set prechangegroup hook to method that returns False
536 Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
536 Ui.create_or_update_hook('prechangegroup.testhook', 'python:kallithea.tests.fixture.passing_test_hook')
537 Session().commit()
537 Session().commit()
538 # re-try to push
538 # re-try to push
539 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
539 stdout, stderr = Command(dest_dir).execute('%s push' % vt.repo_type, clone_url, ignoreReturnCode=True)
540 assert 'passing_test_hook succeeded' in stdout + stderr
540 assert 'passing_test_hook succeeded' in stdout + stderr
541 assert 'Traceback' not in stdout + stderr
541 assert 'Traceback' not in stdout + stderr
542 assert 'prechangegroup.testhook hook failed' not in stdout + stderr
542 assert 'prechangegroup.testhook hook failed' not in stdout + stderr
543 # no more outgoing changesets
543 # no more outgoing changesets
544 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
544 stdout, stderr = _check_outgoing(vt.repo_type, dest_dir, clone_url)
545 assert stdout == ''
545 assert stdout == ''
546 assert stderr == ''
546 assert stderr == ''
547
547
548 def test_add_submodule_git(self, webserver, testfork):
548 def test_add_submodule_git(self, webserver, testfork):
549 dest_dir = _get_tmp_dir()
549 dest_dir = _get_tmp_dir()
550 clone_url = GitHttpVcsTest.repo_url_param(webserver, GIT_REPO)
550 clone_url = GitHttpVcsTest.repo_url_param(webserver, GIT_REPO)
551
551
552 fork_url = GitHttpVcsTest.repo_url_param(webserver, testfork['git'])
552 fork_url = GitHttpVcsTest.repo_url_param(webserver, testfork['git'])
553
553
554 # add submodule
554 # add submodule
555 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', fork_url, dest_dir)
555 stdout, stderr = Command(TESTS_TMP_PATH).execute('git clone', fork_url, dest_dir)
556 stdout, stderr = Command(dest_dir).execute('git submodule add', clone_url, 'testsubmodule')
556 stdout, stderr = Command(dest_dir).execute('git submodule add', clone_url, 'testsubmodule')
557 stdout, stderr = Command(dest_dir).execute('git commit -am "added testsubmodule pointing to', clone_url, '"', EMAIL=TEST_USER_ADMIN_EMAIL)
557 stdout, stderr = Command(dest_dir).execute('git commit -am "added testsubmodule pointing to', clone_url, '"', EMAIL=TEST_USER_ADMIN_EMAIL)
558 stdout, stderr = Command(dest_dir).execute('git push', fork_url, 'master')
558 stdout, stderr = Command(dest_dir).execute('git push', fork_url, 'master')
559
559
560 # check for testsubmodule link in files page
560 # check for testsubmodule link in files page
561 self.log_user()
561 self.log_user()
562 response = self.app.get(url(controller='files', action='index',
562 response = self.app.get(url(controller='files', action='index',
563 repo_name=testfork['git'],
563 repo_name=testfork['git'],
564 revision='tip',
564 revision='tip',
565 f_path='/'))
565 f_path='/'))
566 # check _repo_files_url that will be used to reload as AJAX
566 # check _repo_files_url that will be used to reload as AJAX
567 response.mustcontain('var _repo_files_url = ("/%s/files/");' % testfork['git'])
567 response.mustcontain('var _repo_files_url = ("/%s/files/");' % testfork['git'])
568
568
569 response.mustcontain('<a class="submodule-dir" href="%s" target="_blank"><i class="icon-file-submodule"></i><span>testsubmodule @ ' % clone_url)
569 response.mustcontain('<a class="submodule-dir" href="%s" target="_blank"><i class="icon-file-submodule"></i><span>testsubmodule @ ' % clone_url)
570
570
571 # check that following a submodule link actually works - and redirects
571 # check that following a submodule link actually works - and redirects
572 response = self.app.get(url(controller='files', action='index',
572 response = self.app.get(url(controller='files', action='index',
573 repo_name=testfork['git'],
573 repo_name=testfork['git'],
574 revision='tip',
574 revision='tip',
575 f_path='/testsubmodule'),
575 f_path='/testsubmodule'),
576 status=302)
576 status=302)
577 assert response.location == clone_url
577 assert response.location == clone_url
General Comments 0
You need to be logged in to leave comments. Login now