##// END OF EJS Templates
ruff: Do not assign a `lambda` expression, use a `def`
Mads Kiilerich -
r8764:e2d7830a default
parent child Browse files
Show More
@@ -1,2817 +1,2818 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 """
15 """
16 Tests for the JSON-RPC web api.
16 Tests for the JSON-RPC web api.
17 """
17 """
18
18
19 import os
19 import os
20 import random
20 import random
21 import re
21 import re
22 import string
22 import string
23 from typing import Sized
23 from typing import Sized
24
24
25 import mock
25 import mock
26 import pytest
26 import pytest
27 from webtest import TestApp
27 from webtest import TestApp
28
28
29 from kallithea.lib import ext_json
29 from kallithea.lib import ext_json
30 from kallithea.lib.auth import AuthUser
30 from kallithea.lib.auth import AuthUser
31 from kallithea.lib.utils2 import ascii_bytes
31 from kallithea.lib.utils2 import ascii_bytes
32 from kallithea.model import db, meta
32 from kallithea.model import db, meta
33 from kallithea.model.changeset_status import ChangesetStatusModel
33 from kallithea.model.changeset_status import ChangesetStatusModel
34 from kallithea.model.gist import GistModel
34 from kallithea.model.gist import GistModel
35 from kallithea.model.pull_request import PullRequestModel
35 from kallithea.model.pull_request import PullRequestModel
36 from kallithea.model.repo import RepoModel
36 from kallithea.model.repo import RepoModel
37 from kallithea.model.repo_group import RepoGroupModel
37 from kallithea.model.repo_group import RepoGroupModel
38 from kallithea.model.scm import ScmModel
38 from kallithea.model.scm import ScmModel
39 from kallithea.model.user import UserModel
39 from kallithea.model.user import UserModel
40 from kallithea.model.user_group import UserGroupModel
40 from kallithea.model.user_group import UserGroupModel
41 from kallithea.tests import base
41 from kallithea.tests import base
42 from kallithea.tests.fixture import Fixture, raise_exception
42 from kallithea.tests.fixture import Fixture, raise_exception
43
43
44
44
45 API_URL = '/_admin/api'
45 API_URL = '/_admin/api'
46 TEST_USER_GROUP = 'test_user_group'
46 TEST_USER_GROUP = 'test_user_group'
47 TEST_REPO_GROUP = 'test_repo_group'
47 TEST_REPO_GROUP = 'test_repo_group'
48
48
49 fixture = Fixture()
49 fixture = Fixture()
50
50
51
51
52 def _build_data(apikey, method, **kw):
52 def _build_data(apikey, method, **kw):
53 """
53 """
54 Builds API data with given random ID
54 Builds API data with given random ID
55 For convenience, the json is returned as str
55 For convenience, the json is returned as str
56 """
56 """
57 random_id = random.randrange(1, 9999)
57 random_id = random.randrange(1, 9999)
58 return random_id, ext_json.dumps({
58 return random_id, ext_json.dumps({
59 "id": random_id,
59 "id": random_id,
60 "api_key": apikey,
60 "api_key": apikey,
61 "method": method,
61 "method": method,
62 "args": kw
62 "args": kw
63 })
63 })
64
64
65
65
66 jsonify = lambda obj: ext_json.loads(ext_json.dumps(obj))
66 def jsonify(obj):
67 return ext_json.loads(ext_json.dumps(obj))
67
68
68
69
69 def api_call(test_obj, params):
70 def api_call(test_obj, params):
70 response = test_obj.app.post(API_URL, content_type='application/json',
71 response = test_obj.app.post(API_URL, content_type='application/json',
71 params=params)
72 params=params)
72 return response
73 return response
73
74
74
75
75 ## helpers
76 ## helpers
76 def make_user_group(name=TEST_USER_GROUP):
77 def make_user_group(name=TEST_USER_GROUP):
77 gr = fixture.create_user_group(name, cur_user=base.TEST_USER_ADMIN_LOGIN)
78 gr = fixture.create_user_group(name, cur_user=base.TEST_USER_ADMIN_LOGIN)
78 UserGroupModel().add_user_to_group(user_group=gr,
79 UserGroupModel().add_user_to_group(user_group=gr,
79 user=base.TEST_USER_ADMIN_LOGIN)
80 user=base.TEST_USER_ADMIN_LOGIN)
80 meta.Session().commit()
81 meta.Session().commit()
81 return gr
82 return gr
82
83
83
84
84 def make_repo_group(name=TEST_REPO_GROUP):
85 def make_repo_group(name=TEST_REPO_GROUP):
85 gr = fixture.create_repo_group(name, cur_user=base.TEST_USER_ADMIN_LOGIN)
86 gr = fixture.create_repo_group(name, cur_user=base.TEST_USER_ADMIN_LOGIN)
86 meta.Session().commit()
87 meta.Session().commit()
87 return gr
88 return gr
88
89
89
90
90 class _BaseTestApi(object):
91 class _BaseTestApi(object):
91 app: TestApp # assigned by app_fixture in subclass TestController mixin
92 app: TestApp # assigned by app_fixture in subclass TestController mixin
92 # assigned in subclass:
93 # assigned in subclass:
93 REPO: str
94 REPO: str
94 REPO_TYPE: str
95 REPO_TYPE: str
95 TEST_REVISION: str
96 TEST_REVISION: str
96 TEST_PR_SRC: str
97 TEST_PR_SRC: str
97 TEST_PR_DST: str
98 TEST_PR_DST: str
98 TEST_PR_REVISIONS: Sized
99 TEST_PR_REVISIONS: Sized
99
100
100 @classmethod
101 @classmethod
101 def setup_class(cls):
102 def setup_class(cls):
102 cls.usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
103 cls.usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
103 cls.apikey = cls.usr.api_key
104 cls.apikey = cls.usr.api_key
104 cls.test_user = UserModel().create_or_update(
105 cls.test_user = UserModel().create_or_update(
105 username='test-api',
106 username='test-api',
106 password='test',
107 password='test',
107 email='test@example.com',
108 email='test@example.com',
108 firstname='first',
109 firstname='first',
109 lastname='last'
110 lastname='last'
110 )
111 )
111 meta.Session().commit()
112 meta.Session().commit()
112 cls.TEST_USER_LOGIN = cls.test_user.username
113 cls.TEST_USER_LOGIN = cls.test_user.username
113 cls.apikey_regular = cls.test_user.api_key
114 cls.apikey_regular = cls.test_user.api_key
114
115
115 @classmethod
116 @classmethod
116 def teardown_class(cls):
117 def teardown_class(cls):
117 pass
118 pass
118
119
119 def setup_method(self, method):
120 def setup_method(self, method):
120 make_user_group()
121 make_user_group()
121 make_repo_group()
122 make_repo_group()
122
123
123 def teardown_method(self, method):
124 def teardown_method(self, method):
124 fixture.destroy_user_group(TEST_USER_GROUP)
125 fixture.destroy_user_group(TEST_USER_GROUP)
125 fixture.destroy_gists()
126 fixture.destroy_gists()
126 fixture.destroy_repo_group(TEST_REPO_GROUP)
127 fixture.destroy_repo_group(TEST_REPO_GROUP)
127
128
128 def _compare_ok(self, id_, expected, given):
129 def _compare_ok(self, id_, expected, given):
129 expected = jsonify({
130 expected = jsonify({
130 'id': id_,
131 'id': id_,
131 'error': None,
132 'error': None,
132 'result': expected
133 'result': expected
133 })
134 })
134 given = ext_json.loads(given)
135 given = ext_json.loads(given)
135 assert expected == given, (expected, given)
136 assert expected == given, (expected, given)
136
137
137 def _compare_error(self, id_, expected, given):
138 def _compare_error(self, id_, expected, given):
138 expected = jsonify({
139 expected = jsonify({
139 'id': id_,
140 'id': id_,
140 'error': expected,
141 'error': expected,
141 'result': None
142 'result': None
142 })
143 })
143 given = ext_json.loads(given)
144 given = ext_json.loads(given)
144 assert expected == given, (expected, given)
145 assert expected == given, (expected, given)
145
146
146 def test_api_wrong_key(self):
147 def test_api_wrong_key(self):
147 id_, params = _build_data('trololo', 'get_user')
148 id_, params = _build_data('trololo', 'get_user')
148 response = api_call(self, params)
149 response = api_call(self, params)
149
150
150 expected = 'Invalid API key'
151 expected = 'Invalid API key'
151 self._compare_error(id_, expected, given=response.body)
152 self._compare_error(id_, expected, given=response.body)
152
153
153 def test_api_missing_non_optional_param(self):
154 def test_api_missing_non_optional_param(self):
154 id_, params = _build_data(self.apikey, 'get_repo')
155 id_, params = _build_data(self.apikey, 'get_repo')
155 response = api_call(self, params)
156 response = api_call(self, params)
156
157
157 expected = 'Missing non optional `repoid` arg in JSON DATA'
158 expected = 'Missing non optional `repoid` arg in JSON DATA'
158 self._compare_error(id_, expected, given=response.body)
159 self._compare_error(id_, expected, given=response.body)
159
160
160 def test_api_missing_non_optional_param_args_null(self):
161 def test_api_missing_non_optional_param_args_null(self):
161 id_, params = _build_data(self.apikey, 'get_repo')
162 id_, params = _build_data(self.apikey, 'get_repo')
162 params = params.replace('"args": {}', '"args": null')
163 params = params.replace('"args": {}', '"args": null')
163 response = api_call(self, params)
164 response = api_call(self, params)
164
165
165 expected = 'Missing non optional `repoid` arg in JSON DATA'
166 expected = 'Missing non optional `repoid` arg in JSON DATA'
166 self._compare_error(id_, expected, given=response.body)
167 self._compare_error(id_, expected, given=response.body)
167
168
168 def test_api_missing_non_optional_param_args_bad(self):
169 def test_api_missing_non_optional_param_args_bad(self):
169 id_, params = _build_data(self.apikey, 'get_repo')
170 id_, params = _build_data(self.apikey, 'get_repo')
170 params = params.replace('"args": {}', '"args": 1')
171 params = params.replace('"args": {}', '"args": 1')
171 response = api_call(self, params)
172 response = api_call(self, params)
172
173
173 expected = 'Missing non optional `repoid` arg in JSON DATA'
174 expected = 'Missing non optional `repoid` arg in JSON DATA'
174 self._compare_error(id_, expected, given=response.body)
175 self._compare_error(id_, expected, given=response.body)
175
176
176 def test_api_args_is_null(self):
177 def test_api_args_is_null(self):
177 id_, params = _build_data(self.apikey, 'get_users', )
178 id_, params = _build_data(self.apikey, 'get_users', )
178 params = params.replace('"args": {}', '"args": null')
179 params = params.replace('"args": {}', '"args": null')
179 response = api_call(self, params)
180 response = api_call(self, params)
180 assert response.status == '200 OK'
181 assert response.status == '200 OK'
181
182
182 def test_api_args_is_bad(self):
183 def test_api_args_is_bad(self):
183 id_, params = _build_data(self.apikey, 'get_users', )
184 id_, params = _build_data(self.apikey, 'get_users', )
184 params = params.replace('"args": {}', '"args": 1')
185 params = params.replace('"args": {}', '"args": 1')
185 response = api_call(self, params)
186 response = api_call(self, params)
186 assert response.status == '200 OK'
187 assert response.status == '200 OK'
187
188
188 def test_api_args_different_args(self):
189 def test_api_args_different_args(self):
189 expected = {
190 expected = {
190 'ascii_letters': string.ascii_letters,
191 'ascii_letters': string.ascii_letters,
191 'ws': string.whitespace,
192 'ws': string.whitespace,
192 'printables': string.printable
193 'printables': string.printable
193 }
194 }
194 id_, params = _build_data(self.apikey, 'test', args=expected)
195 id_, params = _build_data(self.apikey, 'test', args=expected)
195 response = api_call(self, params)
196 response = api_call(self, params)
196 assert response.status == '200 OK'
197 assert response.status == '200 OK'
197 self._compare_ok(id_, expected, response.body)
198 self._compare_ok(id_, expected, response.body)
198
199
199 def test_api_get_users(self):
200 def test_api_get_users(self):
200 id_, params = _build_data(self.apikey, 'get_users', )
201 id_, params = _build_data(self.apikey, 'get_users', )
201 response = api_call(self, params)
202 response = api_call(self, params)
202 ret_all = []
203 ret_all = []
203 _users = db.User.query().filter_by(is_default_user=False) \
204 _users = db.User.query().filter_by(is_default_user=False) \
204 .order_by(db.User.username).all()
205 .order_by(db.User.username).all()
205 for usr in _users:
206 for usr in _users:
206 ret = usr.get_api_data()
207 ret = usr.get_api_data()
207 ret_all.append(jsonify(ret))
208 ret_all.append(jsonify(ret))
208 expected = ret_all
209 expected = ret_all
209 self._compare_ok(id_, expected, given=response.body)
210 self._compare_ok(id_, expected, given=response.body)
210
211
211 def test_api_get_user(self):
212 def test_api_get_user(self):
212 id_, params = _build_data(self.apikey, 'get_user',
213 id_, params = _build_data(self.apikey, 'get_user',
213 userid=base.TEST_USER_ADMIN_LOGIN)
214 userid=base.TEST_USER_ADMIN_LOGIN)
214 response = api_call(self, params)
215 response = api_call(self, params)
215
216
216 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
217 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
217 ret = usr.get_api_data()
218 ret = usr.get_api_data()
218 ret['permissions'] = AuthUser(dbuser=usr).permissions
219 ret['permissions'] = AuthUser(dbuser=usr).permissions
219
220
220 expected = ret
221 expected = ret
221 self._compare_ok(id_, expected, given=response.body)
222 self._compare_ok(id_, expected, given=response.body)
222
223
223 def test_api_get_user_that_does_not_exist(self):
224 def test_api_get_user_that_does_not_exist(self):
224 id_, params = _build_data(self.apikey, 'get_user',
225 id_, params = _build_data(self.apikey, 'get_user',
225 userid='trololo')
226 userid='trololo')
226 response = api_call(self, params)
227 response = api_call(self, params)
227
228
228 expected = "user `%s` does not exist" % 'trololo'
229 expected = "user `%s` does not exist" % 'trololo'
229 self._compare_error(id_, expected, given=response.body)
230 self._compare_error(id_, expected, given=response.body)
230
231
231 def test_api_get_user_without_giving_userid(self):
232 def test_api_get_user_without_giving_userid(self):
232 id_, params = _build_data(self.apikey, 'get_user')
233 id_, params = _build_data(self.apikey, 'get_user')
233 response = api_call(self, params)
234 response = api_call(self, params)
234
235
235 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
236 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
236 ret = usr.get_api_data()
237 ret = usr.get_api_data()
237 ret['permissions'] = AuthUser(dbuser=usr).permissions
238 ret['permissions'] = AuthUser(dbuser=usr).permissions
238
239
239 expected = ret
240 expected = ret
240 self._compare_ok(id_, expected, given=response.body)
241 self._compare_ok(id_, expected, given=response.body)
241
242
242 def test_api_get_user_without_giving_userid_non_admin(self):
243 def test_api_get_user_without_giving_userid_non_admin(self):
243 id_, params = _build_data(self.apikey_regular, 'get_user')
244 id_, params = _build_data(self.apikey_regular, 'get_user')
244 response = api_call(self, params)
245 response = api_call(self, params)
245
246
246 usr = db.User.get_by_username(self.TEST_USER_LOGIN)
247 usr = db.User.get_by_username(self.TEST_USER_LOGIN)
247 ret = usr.get_api_data()
248 ret = usr.get_api_data()
248 ret['permissions'] = AuthUser(dbuser=usr).permissions
249 ret['permissions'] = AuthUser(dbuser=usr).permissions
249
250
250 expected = ret
251 expected = ret
251 self._compare_ok(id_, expected, given=response.body)
252 self._compare_ok(id_, expected, given=response.body)
252
253
253 def test_api_get_user_with_giving_userid_non_admin(self):
254 def test_api_get_user_with_giving_userid_non_admin(self):
254 id_, params = _build_data(self.apikey_regular, 'get_user',
255 id_, params = _build_data(self.apikey_regular, 'get_user',
255 userid=self.TEST_USER_LOGIN)
256 userid=self.TEST_USER_LOGIN)
256 response = api_call(self, params)
257 response = api_call(self, params)
257
258
258 expected = 'userid is not the same as your user'
259 expected = 'userid is not the same as your user'
259 self._compare_error(id_, expected, given=response.body)
260 self._compare_error(id_, expected, given=response.body)
260
261
261 def test_api_pull_remote(self):
262 def test_api_pull_remote(self):
262 # Note: pulling from local repos is a mis-feature - it will bypass access control
263 # Note: pulling from local repos is a mis-feature - it will bypass access control
263 # ... but ok, if the path already has been set in the database
264 # ... but ok, if the path already has been set in the database
264 repo_name = 'test_pull'
265 repo_name = 'test_pull'
265 r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
266 r = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
266 # hack around that clone_uri can't be set to to a local path
267 # hack around that clone_uri can't be set to to a local path
267 # (as shown by test_api_create_repo_clone_uri_local)
268 # (as shown by test_api_create_repo_clone_uri_local)
268 r.clone_uri = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, self.REPO)
269 r.clone_uri = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, self.REPO)
269 meta.Session().commit()
270 meta.Session().commit()
270
271
271 pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == repo_name)]
272 pre_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == repo_name)]
272
273
273 id_, params = _build_data(self.apikey, 'pull',
274 id_, params = _build_data(self.apikey, 'pull',
274 repoid=repo_name,)
275 repoid=repo_name,)
275 response = api_call(self, params)
276 response = api_call(self, params)
276
277
277 expected = {'msg': 'Pulled from `%s`' % repo_name,
278 expected = {'msg': 'Pulled from `%s`' % repo_name,
278 'repository': repo_name}
279 'repository': repo_name}
279 self._compare_ok(id_, expected, given=response.body)
280 self._compare_ok(id_, expected, given=response.body)
280
281
281 post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == repo_name)]
282 post_cached_tip = [repo.get_api_data()['last_changeset']['short_id'] for repo in db.Repository.query().filter(db.Repository.repo_name == repo_name)]
282
283
283 fixture.destroy_repo(repo_name)
284 fixture.destroy_repo(repo_name)
284
285
285 assert pre_cached_tip != post_cached_tip
286 assert pre_cached_tip != post_cached_tip
286
287
287 def test_api_pull_fork(self):
288 def test_api_pull_fork(self):
288 fork_name = 'fork'
289 fork_name = 'fork'
289 fixture.create_fork(self.REPO, fork_name)
290 fixture.create_fork(self.REPO, fork_name)
290 id_, params = _build_data(self.apikey, 'pull',
291 id_, params = _build_data(self.apikey, 'pull',
291 repoid=fork_name,)
292 repoid=fork_name,)
292 response = api_call(self, params)
293 response = api_call(self, params)
293
294
294 expected = {'msg': 'Pulled from `%s`' % fork_name,
295 expected = {'msg': 'Pulled from `%s`' % fork_name,
295 'repository': fork_name}
296 'repository': fork_name}
296 self._compare_ok(id_, expected, given=response.body)
297 self._compare_ok(id_, expected, given=response.body)
297
298
298 fixture.destroy_repo(fork_name)
299 fixture.destroy_repo(fork_name)
299
300
300 def test_api_pull_error_no_remote_no_fork(self):
301 def test_api_pull_error_no_remote_no_fork(self):
301 # should fail because no clone_uri is set
302 # should fail because no clone_uri is set
302 id_, params = _build_data(self.apikey, 'pull',
303 id_, params = _build_data(self.apikey, 'pull',
303 repoid=self.REPO, )
304 repoid=self.REPO, )
304 response = api_call(self, params)
305 response = api_call(self, params)
305
306
306 expected = 'Unable to pull changes from `%s`' % self.REPO
307 expected = 'Unable to pull changes from `%s`' % self.REPO
307 self._compare_error(id_, expected, given=response.body)
308 self._compare_error(id_, expected, given=response.body)
308
309
309 def test_api_pull_custom_remote(self):
310 def test_api_pull_custom_remote(self):
310 repo_name = 'test_pull_custom_remote'
311 repo_name = 'test_pull_custom_remote'
311 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
312 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
312
313
313 custom_remote_path = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, self.REPO)
314 custom_remote_path = os.path.join(db.Ui.get_by_key('paths', '/').ui_value, self.REPO)
314
315
315 id_, params = _build_data(self.apikey, 'pull',
316 id_, params = _build_data(self.apikey, 'pull',
316 repoid=repo_name,
317 repoid=repo_name,
317 clone_uri=custom_remote_path)
318 clone_uri=custom_remote_path)
318 response = api_call(self, params)
319 response = api_call(self, params)
319
320
320 expected = {'msg': 'Pulled from `%s`' % repo_name,
321 expected = {'msg': 'Pulled from `%s`' % repo_name,
321 'repository': repo_name}
322 'repository': repo_name}
322 self._compare_ok(id_, expected, given=response.body)
323 self._compare_ok(id_, expected, given=response.body)
323
324
324 fixture.destroy_repo(repo_name)
325 fixture.destroy_repo(repo_name)
325
326
326 def test_api_rescan_repos(self):
327 def test_api_rescan_repos(self):
327 id_, params = _build_data(self.apikey, 'rescan_repos')
328 id_, params = _build_data(self.apikey, 'rescan_repos')
328 response = api_call(self, params)
329 response = api_call(self, params)
329
330
330 expected = {'added': [], 'removed': []}
331 expected = {'added': [], 'removed': []}
331 self._compare_ok(id_, expected, given=response.body)
332 self._compare_ok(id_, expected, given=response.body)
332
333
333 @mock.patch.object(ScmModel, 'repo_scan', raise_exception)
334 @mock.patch.object(ScmModel, 'repo_scan', raise_exception)
334 def test_api_rescann_error(self):
335 def test_api_rescann_error(self):
335 id_, params = _build_data(self.apikey, 'rescan_repos', )
336 id_, params = _build_data(self.apikey, 'rescan_repos', )
336 response = api_call(self, params)
337 response = api_call(self, params)
337
338
338 expected = 'Error occurred during rescan repositories action'
339 expected = 'Error occurred during rescan repositories action'
339 self._compare_error(id_, expected, given=response.body)
340 self._compare_error(id_, expected, given=response.body)
340
341
341 def test_api_create_existing_user(self):
342 def test_api_create_existing_user(self):
342 id_, params = _build_data(self.apikey, 'create_user',
343 id_, params = _build_data(self.apikey, 'create_user',
343 username=base.TEST_USER_ADMIN_LOGIN,
344 username=base.TEST_USER_ADMIN_LOGIN,
344 email='test@example.com',
345 email='test@example.com',
345 password='trololo')
346 password='trololo')
346 response = api_call(self, params)
347 response = api_call(self, params)
347
348
348 expected = "user `%s` already exist" % base.TEST_USER_ADMIN_LOGIN
349 expected = "user `%s` already exist" % base.TEST_USER_ADMIN_LOGIN
349 self._compare_error(id_, expected, given=response.body)
350 self._compare_error(id_, expected, given=response.body)
350
351
351 def test_api_create_user_with_existing_email(self):
352 def test_api_create_user_with_existing_email(self):
352 id_, params = _build_data(self.apikey, 'create_user',
353 id_, params = _build_data(self.apikey, 'create_user',
353 username=base.TEST_USER_ADMIN_LOGIN + 'new',
354 username=base.TEST_USER_ADMIN_LOGIN + 'new',
354 email=base.TEST_USER_REGULAR_EMAIL,
355 email=base.TEST_USER_REGULAR_EMAIL,
355 password='trololo')
356 password='trololo')
356 response = api_call(self, params)
357 response = api_call(self, params)
357
358
358 expected = "email `%s` already exist" % base.TEST_USER_REGULAR_EMAIL
359 expected = "email `%s` already exist" % base.TEST_USER_REGULAR_EMAIL
359 self._compare_error(id_, expected, given=response.body)
360 self._compare_error(id_, expected, given=response.body)
360
361
361 def test_api_create_user(self):
362 def test_api_create_user(self):
362 username = 'test_new_api_user'
363 username = 'test_new_api_user'
363 email = username + "@example.com"
364 email = username + "@example.com"
364
365
365 id_, params = _build_data(self.apikey, 'create_user',
366 id_, params = _build_data(self.apikey, 'create_user',
366 username=username,
367 username=username,
367 email=email,
368 email=email,
368 password='trololo')
369 password='trololo')
369 response = api_call(self, params)
370 response = api_call(self, params)
370
371
371 usr = db.User.get_by_username(username)
372 usr = db.User.get_by_username(username)
372 ret = dict(
373 ret = dict(
373 msg='created new user `%s`' % username,
374 msg='created new user `%s`' % username,
374 user=jsonify(usr.get_api_data())
375 user=jsonify(usr.get_api_data())
375 )
376 )
376
377
377 try:
378 try:
378 expected = ret
379 expected = ret
379 self._compare_ok(id_, expected, given=response.body)
380 self._compare_ok(id_, expected, given=response.body)
380 finally:
381 finally:
381 fixture.destroy_user(usr.user_id)
382 fixture.destroy_user(usr.user_id)
382
383
383 def test_api_create_user_without_password(self):
384 def test_api_create_user_without_password(self):
384 username = 'test_new_api_user_passwordless'
385 username = 'test_new_api_user_passwordless'
385 email = username + "@example.com"
386 email = username + "@example.com"
386
387
387 id_, params = _build_data(self.apikey, 'create_user',
388 id_, params = _build_data(self.apikey, 'create_user',
388 username=username,
389 username=username,
389 email=email)
390 email=email)
390 response = api_call(self, params)
391 response = api_call(self, params)
391
392
392 usr = db.User.get_by_username(username)
393 usr = db.User.get_by_username(username)
393 ret = dict(
394 ret = dict(
394 msg='created new user `%s`' % username,
395 msg='created new user `%s`' % username,
395 user=jsonify(usr.get_api_data())
396 user=jsonify(usr.get_api_data())
396 )
397 )
397 try:
398 try:
398 expected = ret
399 expected = ret
399 self._compare_ok(id_, expected, given=response.body)
400 self._compare_ok(id_, expected, given=response.body)
400 finally:
401 finally:
401 fixture.destroy_user(usr.user_id)
402 fixture.destroy_user(usr.user_id)
402
403
403 def test_api_create_user_with_extern_name(self):
404 def test_api_create_user_with_extern_name(self):
404 username = 'test_new_api_user_passwordless'
405 username = 'test_new_api_user_passwordless'
405 email = username + "@example.com"
406 email = username + "@example.com"
406
407
407 id_, params = _build_data(self.apikey, 'create_user',
408 id_, params = _build_data(self.apikey, 'create_user',
408 username=username,
409 username=username,
409 email=email, extern_name='internal')
410 email=email, extern_name='internal')
410 response = api_call(self, params)
411 response = api_call(self, params)
411
412
412 usr = db.User.get_by_username(username)
413 usr = db.User.get_by_username(username)
413 ret = dict(
414 ret = dict(
414 msg='created new user `%s`' % username,
415 msg='created new user `%s`' % username,
415 user=jsonify(usr.get_api_data())
416 user=jsonify(usr.get_api_data())
416 )
417 )
417 try:
418 try:
418 expected = ret
419 expected = ret
419 self._compare_ok(id_, expected, given=response.body)
420 self._compare_ok(id_, expected, given=response.body)
420 finally:
421 finally:
421 fixture.destroy_user(usr.user_id)
422 fixture.destroy_user(usr.user_id)
422
423
423 @mock.patch.object(UserModel, 'create_or_update', raise_exception)
424 @mock.patch.object(UserModel, 'create_or_update', raise_exception)
424 def test_api_create_user_when_exception_happened(self):
425 def test_api_create_user_when_exception_happened(self):
425
426
426 username = 'test_new_api_user'
427 username = 'test_new_api_user'
427 email = username + "@example.com"
428 email = username + "@example.com"
428
429
429 id_, params = _build_data(self.apikey, 'create_user',
430 id_, params = _build_data(self.apikey, 'create_user',
430 username=username,
431 username=username,
431 email=email,
432 email=email,
432 password='trololo')
433 password='trololo')
433 response = api_call(self, params)
434 response = api_call(self, params)
434 expected = 'failed to create user `%s`' % username
435 expected = 'failed to create user `%s`' % username
435 self._compare_error(id_, expected, given=response.body)
436 self._compare_error(id_, expected, given=response.body)
436
437
437 def test_api_delete_user(self):
438 def test_api_delete_user(self):
438 usr = UserModel().create_or_update(username='test_user',
439 usr = UserModel().create_or_update(username='test_user',
439 password='qweqwe',
440 password='qweqwe',
440 email='u232@example.com',
441 email='u232@example.com',
441 firstname='u1', lastname='u1')
442 firstname='u1', lastname='u1')
442 meta.Session().commit()
443 meta.Session().commit()
443 username = usr.username
444 username = usr.username
444 email = usr.email
445 email = usr.email
445 usr_id = usr.user_id
446 usr_id = usr.user_id
446 ## DELETE THIS USER NOW
447 ## DELETE THIS USER NOW
447
448
448 id_, params = _build_data(self.apikey, 'delete_user',
449 id_, params = _build_data(self.apikey, 'delete_user',
449 userid=username, )
450 userid=username, )
450 response = api_call(self, params)
451 response = api_call(self, params)
451
452
452 ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
453 ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username),
453 'user': None}
454 'user': None}
454 expected = ret
455 expected = ret
455 self._compare_ok(id_, expected, given=response.body)
456 self._compare_ok(id_, expected, given=response.body)
456
457
457 @mock.patch.object(UserModel, 'delete', raise_exception)
458 @mock.patch.object(UserModel, 'delete', raise_exception)
458 def test_api_delete_user_when_exception_happened(self):
459 def test_api_delete_user_when_exception_happened(self):
459 usr = UserModel().create_or_update(username='test_user',
460 usr = UserModel().create_or_update(username='test_user',
460 password='qweqwe',
461 password='qweqwe',
461 email='u232@example.com',
462 email='u232@example.com',
462 firstname='u1', lastname='u1')
463 firstname='u1', lastname='u1')
463 meta.Session().commit()
464 meta.Session().commit()
464 username = usr.username
465 username = usr.username
465
466
466 id_, params = _build_data(self.apikey, 'delete_user',
467 id_, params = _build_data(self.apikey, 'delete_user',
467 userid=username, )
468 userid=username, )
468 response = api_call(self, params)
469 response = api_call(self, params)
469 ret = 'failed to delete user ID:%s %s' % (usr.user_id,
470 ret = 'failed to delete user ID:%s %s' % (usr.user_id,
470 usr.username)
471 usr.username)
471 expected = ret
472 expected = ret
472 self._compare_error(id_, expected, given=response.body)
473 self._compare_error(id_, expected, given=response.body)
473
474
474 @base.parametrize('name,expected', [
475 @base.parametrize('name,expected', [
475 ('firstname', 'new_username'),
476 ('firstname', 'new_username'),
476 ('lastname', 'new_username'),
477 ('lastname', 'new_username'),
477 ('email', 'new_username'),
478 ('email', 'new_username'),
478 ('admin', True),
479 ('admin', True),
479 ('admin', False),
480 ('admin', False),
480 ('extern_type', 'ldap'),
481 ('extern_type', 'ldap'),
481 ('extern_type', None),
482 ('extern_type', None),
482 ('extern_name', 'test'),
483 ('extern_name', 'test'),
483 ('extern_name', None),
484 ('extern_name', None),
484 ('active', False),
485 ('active', False),
485 ('active', True),
486 ('active', True),
486 ('password', 'newpass'),
487 ('password', 'newpass'),
487 ])
488 ])
488 def test_api_update_user(self, name, expected):
489 def test_api_update_user(self, name, expected):
489 usr = db.User.get_by_username(self.TEST_USER_LOGIN)
490 usr = db.User.get_by_username(self.TEST_USER_LOGIN)
490 kw = {name: expected,
491 kw = {name: expected,
491 'userid': usr.user_id}
492 'userid': usr.user_id}
492 id_, params = _build_data(self.apikey, 'update_user', **kw)
493 id_, params = _build_data(self.apikey, 'update_user', **kw)
493 response = api_call(self, params)
494 response = api_call(self, params)
494
495
495 ret = {
496 ret = {
496 'msg': 'updated user ID:%s %s' % (
497 'msg': 'updated user ID:%s %s' % (
497 usr.user_id, self.TEST_USER_LOGIN),
498 usr.user_id, self.TEST_USER_LOGIN),
498 'user': jsonify(db.User \
499 'user': jsonify(db.User \
499 .get_by_username(self.TEST_USER_LOGIN) \
500 .get_by_username(self.TEST_USER_LOGIN) \
500 .get_api_data())
501 .get_api_data())
501 }
502 }
502
503
503 expected = ret
504 expected = ret
504 self._compare_ok(id_, expected, given=response.body)
505 self._compare_ok(id_, expected, given=response.body)
505
506
506 def test_api_update_user_no_changed_params(self):
507 def test_api_update_user_no_changed_params(self):
507 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
508 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
508 ret = jsonify(usr.get_api_data())
509 ret = jsonify(usr.get_api_data())
509 id_, params = _build_data(self.apikey, 'update_user',
510 id_, params = _build_data(self.apikey, 'update_user',
510 userid=base.TEST_USER_ADMIN_LOGIN)
511 userid=base.TEST_USER_ADMIN_LOGIN)
511
512
512 response = api_call(self, params)
513 response = api_call(self, params)
513 ret = {
514 ret = {
514 'msg': 'updated user ID:%s %s' % (
515 'msg': 'updated user ID:%s %s' % (
515 usr.user_id, base.TEST_USER_ADMIN_LOGIN),
516 usr.user_id, base.TEST_USER_ADMIN_LOGIN),
516 'user': ret
517 'user': ret
517 }
518 }
518 expected = ret
519 expected = ret
519 self._compare_ok(id_, expected, given=response.body)
520 self._compare_ok(id_, expected, given=response.body)
520
521
521 def test_api_update_user_by_user_id(self):
522 def test_api_update_user_by_user_id(self):
522 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
523 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
523 ret = jsonify(usr.get_api_data())
524 ret = jsonify(usr.get_api_data())
524 id_, params = _build_data(self.apikey, 'update_user',
525 id_, params = _build_data(self.apikey, 'update_user',
525 userid=usr.user_id)
526 userid=usr.user_id)
526
527
527 response = api_call(self, params)
528 response = api_call(self, params)
528 ret = {
529 ret = {
529 'msg': 'updated user ID:%s %s' % (
530 'msg': 'updated user ID:%s %s' % (
530 usr.user_id, base.TEST_USER_ADMIN_LOGIN),
531 usr.user_id, base.TEST_USER_ADMIN_LOGIN),
531 'user': ret
532 'user': ret
532 }
533 }
533 expected = ret
534 expected = ret
534 self._compare_ok(id_, expected, given=response.body)
535 self._compare_ok(id_, expected, given=response.body)
535
536
536 def test_api_update_user_default_user(self):
537 def test_api_update_user_default_user(self):
537 usr = db.User.get_default_user()
538 usr = db.User.get_default_user()
538 id_, params = _build_data(self.apikey, 'update_user',
539 id_, params = _build_data(self.apikey, 'update_user',
539 userid=usr.user_id)
540 userid=usr.user_id)
540
541
541 response = api_call(self, params)
542 response = api_call(self, params)
542 expected = 'editing default user is forbidden'
543 expected = 'editing default user is forbidden'
543 self._compare_error(id_, expected, given=response.body)
544 self._compare_error(id_, expected, given=response.body)
544
545
545 @mock.patch.object(UserModel, 'update_user', raise_exception)
546 @mock.patch.object(UserModel, 'update_user', raise_exception)
546 def test_api_update_user_when_exception_happens(self):
547 def test_api_update_user_when_exception_happens(self):
547 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
548 usr = db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN)
548 ret = jsonify(usr.get_api_data())
549 ret = jsonify(usr.get_api_data())
549 id_, params = _build_data(self.apikey, 'update_user',
550 id_, params = _build_data(self.apikey, 'update_user',
550 userid=usr.user_id)
551 userid=usr.user_id)
551
552
552 response = api_call(self, params)
553 response = api_call(self, params)
553 ret = 'failed to update user `%s`' % usr.user_id
554 ret = 'failed to update user `%s`' % usr.user_id
554
555
555 expected = ret
556 expected = ret
556 self._compare_error(id_, expected, given=response.body)
557 self._compare_error(id_, expected, given=response.body)
557
558
558 def test_api_get_repo(self):
559 def test_api_get_repo(self):
559 new_group = 'some_new_group'
560 new_group = 'some_new_group'
560 make_user_group(new_group)
561 make_user_group(new_group)
561 RepoModel().grant_user_group_permission(repo=self.REPO,
562 RepoModel().grant_user_group_permission(repo=self.REPO,
562 group_name=new_group,
563 group_name=new_group,
563 perm='repository.read')
564 perm='repository.read')
564 meta.Session().commit()
565 meta.Session().commit()
565 id_, params = _build_data(self.apikey, 'get_repo',
566 id_, params = _build_data(self.apikey, 'get_repo',
566 repoid=self.REPO)
567 repoid=self.REPO)
567 response = api_call(self, params)
568 response = api_call(self, params)
568 assert "tags" not in response.json['result']
569 assert "tags" not in response.json['result']
569 assert 'pull_requests' not in response.json['result']
570 assert 'pull_requests' not in response.json['result']
570
571
571 repo = RepoModel().get_by_repo_name(self.REPO)
572 repo = RepoModel().get_by_repo_name(self.REPO)
572 ret = repo.get_api_data()
573 ret = repo.get_api_data()
573
574
574 members = []
575 members = []
575 followers = []
576 followers = []
576 for user in repo.repo_to_perm:
577 for user in repo.repo_to_perm:
577 perm = user.permission.permission_name
578 perm = user.permission.permission_name
578 user = user.user
579 user = user.user
579 user_data = {'name': user.username, 'type': "user",
580 user_data = {'name': user.username, 'type': "user",
580 'permission': perm}
581 'permission': perm}
581 members.append(user_data)
582 members.append(user_data)
582
583
583 for user_group in repo.users_group_to_perm:
584 for user_group in repo.users_group_to_perm:
584 perm = user_group.permission.permission_name
585 perm = user_group.permission.permission_name
585 user_group = user_group.users_group
586 user_group = user_group.users_group
586 user_group_data = {'name': user_group.users_group_name,
587 user_group_data = {'name': user_group.users_group_name,
587 'type': "user_group", 'permission': perm}
588 'type': "user_group", 'permission': perm}
588 members.append(user_group_data)
589 members.append(user_group_data)
589
590
590 for user in repo.followers:
591 for user in repo.followers:
591 followers.append(user.user.get_api_data())
592 followers.append(user.user.get_api_data())
592
593
593 ret['members'] = members
594 ret['members'] = members
594 ret['followers'] = followers
595 ret['followers'] = followers
595
596
596 expected = ret
597 expected = ret
597 self._compare_ok(id_, expected, given=response.body)
598 self._compare_ok(id_, expected, given=response.body)
598 fixture.destroy_user_group(new_group)
599 fixture.destroy_user_group(new_group)
599
600
600 id_, params = _build_data(self.apikey, 'get_repo', repoid=self.REPO,
601 id_, params = _build_data(self.apikey, 'get_repo', repoid=self.REPO,
601 with_revision_names=True,
602 with_revision_names=True,
602 with_pullrequests=True)
603 with_pullrequests=True)
603 response = api_call(self, params)
604 response = api_call(self, params)
604 assert "v0.2.0" in response.json['result']['tags']
605 assert "v0.2.0" in response.json['result']['tags']
605 assert 'pull_requests' in response.json['result']
606 assert 'pull_requests' in response.json['result']
606
607
607 @base.parametrize('grant_perm', [
608 @base.parametrize('grant_perm', [
608 ('repository.admin'),
609 ('repository.admin'),
609 ('repository.write'),
610 ('repository.write'),
610 ('repository.read'),
611 ('repository.read'),
611 ])
612 ])
612 def test_api_get_repo_by_non_admin(self, grant_perm):
613 def test_api_get_repo_by_non_admin(self, grant_perm):
613 RepoModel().grant_user_permission(repo=self.REPO,
614 RepoModel().grant_user_permission(repo=self.REPO,
614 user=self.TEST_USER_LOGIN,
615 user=self.TEST_USER_LOGIN,
615 perm=grant_perm)
616 perm=grant_perm)
616 meta.Session().commit()
617 meta.Session().commit()
617 id_, params = _build_data(self.apikey_regular, 'get_repo',
618 id_, params = _build_data(self.apikey_regular, 'get_repo',
618 repoid=self.REPO)
619 repoid=self.REPO)
619 response = api_call(self, params)
620 response = api_call(self, params)
620
621
621 repo = RepoModel().get_by_repo_name(self.REPO)
622 repo = RepoModel().get_by_repo_name(self.REPO)
622 assert len(repo.repo_to_perm) >= 2 # make sure we actually are testing something - probably the default 2 permissions, possibly more
623 assert len(repo.repo_to_perm) >= 2 # make sure we actually are testing something - probably the default 2 permissions, possibly more
623
624
624 expected = repo.get_api_data()
625 expected = repo.get_api_data()
625
626
626 members = []
627 members = []
627 for user in repo.repo_to_perm:
628 for user in repo.repo_to_perm:
628 perm = user.permission.permission_name
629 perm = user.permission.permission_name
629 user_obj = user.user
630 user_obj = user.user
630 user_data = {'name': user_obj.username, 'type': "user",
631 user_data = {'name': user_obj.username, 'type': "user",
631 'permission': perm}
632 'permission': perm}
632 members.append(user_data)
633 members.append(user_data)
633 for user_group in repo.users_group_to_perm:
634 for user_group in repo.users_group_to_perm:
634 perm = user_group.permission.permission_name
635 perm = user_group.permission.permission_name
635 user_group_obj = user_group.users_group
636 user_group_obj = user_group.users_group
636 user_group_data = {'name': user_group_obj.users_group_name,
637 user_group_data = {'name': user_group_obj.users_group_name,
637 'type': "user_group", 'permission': perm}
638 'type': "user_group", 'permission': perm}
638 members.append(user_group_data)
639 members.append(user_group_data)
639 expected['members'] = members
640 expected['members'] = members
640
641
641 followers = []
642 followers = []
642
643
643 for user in repo.followers:
644 for user in repo.followers:
644 followers.append(user.user.get_api_data())
645 followers.append(user.user.get_api_data())
645
646
646 expected['followers'] = followers
647 expected['followers'] = followers
647
648
648 try:
649 try:
649 self._compare_ok(id_, expected, given=response.body)
650 self._compare_ok(id_, expected, given=response.body)
650 finally:
651 finally:
651 RepoModel().revoke_user_permission(self.REPO, self.TEST_USER_LOGIN)
652 RepoModel().revoke_user_permission(self.REPO, self.TEST_USER_LOGIN)
652
653
653 def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
654 def test_api_get_repo_by_non_admin_no_permission_to_repo(self):
654 RepoModel().grant_user_permission(repo=self.REPO,
655 RepoModel().grant_user_permission(repo=self.REPO,
655 user=db.User.DEFAULT_USER_NAME,
656 user=db.User.DEFAULT_USER_NAME,
656 perm='repository.none')
657 perm='repository.none')
657 try:
658 try:
658 RepoModel().grant_user_permission(repo=self.REPO,
659 RepoModel().grant_user_permission(repo=self.REPO,
659 user=self.TEST_USER_LOGIN,
660 user=self.TEST_USER_LOGIN,
660 perm='repository.none')
661 perm='repository.none')
661
662
662 id_, params = _build_data(self.apikey_regular, 'get_repo',
663 id_, params = _build_data(self.apikey_regular, 'get_repo',
663 repoid=self.REPO)
664 repoid=self.REPO)
664 response = api_call(self, params)
665 response = api_call(self, params)
665
666
666 expected = 'repository `%s` does not exist' % (self.REPO)
667 expected = 'repository `%s` does not exist' % (self.REPO)
667 self._compare_error(id_, expected, given=response.body)
668 self._compare_error(id_, expected, given=response.body)
668 finally:
669 finally:
669 RepoModel().grant_user_permission(repo=self.REPO,
670 RepoModel().grant_user_permission(repo=self.REPO,
670 user=db.User.DEFAULT_USER_NAME,
671 user=db.User.DEFAULT_USER_NAME,
671 perm='repository.read')
672 perm='repository.read')
672
673
673 def test_api_get_repo_that_doesn_not_exist(self):
674 def test_api_get_repo_that_doesn_not_exist(self):
674 id_, params = _build_data(self.apikey, 'get_repo',
675 id_, params = _build_data(self.apikey, 'get_repo',
675 repoid='no-such-repo')
676 repoid='no-such-repo')
676 response = api_call(self, params)
677 response = api_call(self, params)
677
678
678 ret = 'repository `%s` does not exist' % 'no-such-repo'
679 ret = 'repository `%s` does not exist' % 'no-such-repo'
679 expected = ret
680 expected = ret
680 self._compare_error(id_, expected, given=response.body)
681 self._compare_error(id_, expected, given=response.body)
681
682
682 def test_api_get_repos(self):
683 def test_api_get_repos(self):
683 id_, params = _build_data(self.apikey, 'get_repos')
684 id_, params = _build_data(self.apikey, 'get_repos')
684 response = api_call(self, params)
685 response = api_call(self, params)
685
686
686 expected = jsonify([
687 expected = jsonify([
687 repo.get_api_data()
688 repo.get_api_data()
688 for repo in db.Repository.query()
689 for repo in db.Repository.query()
689 ])
690 ])
690
691
691 self._compare_ok(id_, expected, given=response.body)
692 self._compare_ok(id_, expected, given=response.body)
692
693
693 def test_api_get_repos_non_admin(self):
694 def test_api_get_repos_non_admin(self):
694 id_, params = _build_data(self.apikey_regular, 'get_repos')
695 id_, params = _build_data(self.apikey_regular, 'get_repos')
695 response = api_call(self, params)
696 response = api_call(self, params)
696
697
697 expected = jsonify([
698 expected = jsonify([
698 repo.get_api_data()
699 repo.get_api_data()
699 for repo in AuthUser(dbuser=db.User.get_by_username(self.TEST_USER_LOGIN)).get_all_user_repos()
700 for repo in AuthUser(dbuser=db.User.get_by_username(self.TEST_USER_LOGIN)).get_all_user_repos()
700 ])
701 ])
701
702
702 self._compare_ok(id_, expected, given=response.body)
703 self._compare_ok(id_, expected, given=response.body)
703
704
704 @base.parametrize('name,ret_type', [
705 @base.parametrize('name,ret_type', [
705 ('all', 'all'),
706 ('all', 'all'),
706 ('dirs', 'dirs'),
707 ('dirs', 'dirs'),
707 ('files', 'files'),
708 ('files', 'files'),
708 ])
709 ])
709 def test_api_get_repo_nodes(self, name, ret_type):
710 def test_api_get_repo_nodes(self, name, ret_type):
710 rev = 'tip'
711 rev = 'tip'
711 path = '/'
712 path = '/'
712 id_, params = _build_data(self.apikey, 'get_repo_nodes',
713 id_, params = _build_data(self.apikey, 'get_repo_nodes',
713 repoid=self.REPO, revision=rev,
714 repoid=self.REPO, revision=rev,
714 root_path=path,
715 root_path=path,
715 ret_type=ret_type)
716 ret_type=ret_type)
716 response = api_call(self, params)
717 response = api_call(self, params)
717
718
718 # we don't the actual return types here since it's tested somewhere
719 # we don't the actual return types here since it's tested somewhere
719 # else
720 # else
720 expected = response.json['result']
721 expected = response.json['result']
721 self._compare_ok(id_, expected, given=response.body)
722 self._compare_ok(id_, expected, given=response.body)
722
723
723 def test_api_get_repo_nodes_bad_revisions(self):
724 def test_api_get_repo_nodes_bad_revisions(self):
724 rev = 'i-dont-exist'
725 rev = 'i-dont-exist'
725 path = '/'
726 path = '/'
726 id_, params = _build_data(self.apikey, 'get_repo_nodes',
727 id_, params = _build_data(self.apikey, 'get_repo_nodes',
727 repoid=self.REPO, revision=rev,
728 repoid=self.REPO, revision=rev,
728 root_path=path, )
729 root_path=path, )
729 response = api_call(self, params)
730 response = api_call(self, params)
730
731
731 expected = 'failed to get repo: `%s` nodes' % self.REPO
732 expected = 'failed to get repo: `%s` nodes' % self.REPO
732 self._compare_error(id_, expected, given=response.body)
733 self._compare_error(id_, expected, given=response.body)
733
734
734 def test_api_get_repo_nodes_bad_path(self):
735 def test_api_get_repo_nodes_bad_path(self):
735 rev = 'tip'
736 rev = 'tip'
736 path = '/idontexits'
737 path = '/idontexits'
737 id_, params = _build_data(self.apikey, 'get_repo_nodes',
738 id_, params = _build_data(self.apikey, 'get_repo_nodes',
738 repoid=self.REPO, revision=rev,
739 repoid=self.REPO, revision=rev,
739 root_path=path, )
740 root_path=path, )
740 response = api_call(self, params)
741 response = api_call(self, params)
741
742
742 expected = 'failed to get repo: `%s` nodes' % self.REPO
743 expected = 'failed to get repo: `%s` nodes' % self.REPO
743 self._compare_error(id_, expected, given=response.body)
744 self._compare_error(id_, expected, given=response.body)
744
745
745 def test_api_get_repo_nodes_bad_ret_type(self):
746 def test_api_get_repo_nodes_bad_ret_type(self):
746 rev = 'tip'
747 rev = 'tip'
747 path = '/'
748 path = '/'
748 ret_type = 'error'
749 ret_type = 'error'
749 id_, params = _build_data(self.apikey, 'get_repo_nodes',
750 id_, params = _build_data(self.apikey, 'get_repo_nodes',
750 repoid=self.REPO, revision=rev,
751 repoid=self.REPO, revision=rev,
751 root_path=path,
752 root_path=path,
752 ret_type=ret_type)
753 ret_type=ret_type)
753 response = api_call(self, params)
754 response = api_call(self, params)
754
755
755 expected = ('ret_type must be one of %s'
756 expected = ('ret_type must be one of %s'
756 % (','.join(sorted(['files', 'dirs', 'all']))))
757 % (','.join(sorted(['files', 'dirs', 'all']))))
757 self._compare_error(id_, expected, given=response.body)
758 self._compare_error(id_, expected, given=response.body)
758
759
759 @base.parametrize('name,ret_type,grant_perm', [
760 @base.parametrize('name,ret_type,grant_perm', [
760 ('all', 'all', 'repository.write'),
761 ('all', 'all', 'repository.write'),
761 ('dirs', 'dirs', 'repository.admin'),
762 ('dirs', 'dirs', 'repository.admin'),
762 ('files', 'files', 'repository.read'),
763 ('files', 'files', 'repository.read'),
763 ])
764 ])
764 def test_api_get_repo_nodes_by_regular_user(self, name, ret_type, grant_perm):
765 def test_api_get_repo_nodes_by_regular_user(self, name, ret_type, grant_perm):
765 RepoModel().grant_user_permission(repo=self.REPO,
766 RepoModel().grant_user_permission(repo=self.REPO,
766 user=self.TEST_USER_LOGIN,
767 user=self.TEST_USER_LOGIN,
767 perm=grant_perm)
768 perm=grant_perm)
768 meta.Session().commit()
769 meta.Session().commit()
769
770
770 rev = 'tip'
771 rev = 'tip'
771 path = '/'
772 path = '/'
772 id_, params = _build_data(self.apikey_regular, 'get_repo_nodes',
773 id_, params = _build_data(self.apikey_regular, 'get_repo_nodes',
773 repoid=self.REPO, revision=rev,
774 repoid=self.REPO, revision=rev,
774 root_path=path,
775 root_path=path,
775 ret_type=ret_type)
776 ret_type=ret_type)
776 response = api_call(self, params)
777 response = api_call(self, params)
777
778
778 # we don't the actual return types here since it's tested somewhere
779 # we don't the actual return types here since it's tested somewhere
779 # else
780 # else
780 expected = response.json['result']
781 expected = response.json['result']
781 try:
782 try:
782 self._compare_ok(id_, expected, given=response.body)
783 self._compare_ok(id_, expected, given=response.body)
783 finally:
784 finally:
784 RepoModel().revoke_user_permission(self.REPO, self.TEST_USER_LOGIN)
785 RepoModel().revoke_user_permission(self.REPO, self.TEST_USER_LOGIN)
785
786
786 def test_api_create_repo(self):
787 def test_api_create_repo(self):
787 repo_name = 'api-repo'
788 repo_name = 'api-repo'
788 id_, params = _build_data(self.apikey, 'create_repo',
789 id_, params = _build_data(self.apikey, 'create_repo',
789 repo_name=repo_name,
790 repo_name=repo_name,
790 owner=base.TEST_USER_ADMIN_LOGIN,
791 owner=base.TEST_USER_ADMIN_LOGIN,
791 repo_type=self.REPO_TYPE,
792 repo_type=self.REPO_TYPE,
792 )
793 )
793 response = api_call(self, params)
794 response = api_call(self, params)
794
795
795 repo = RepoModel().get_by_repo_name(repo_name)
796 repo = RepoModel().get_by_repo_name(repo_name)
796 assert repo is not None
797 assert repo is not None
797 ret = {
798 ret = {
798 'msg': 'Created new repository `%s`' % repo_name,
799 'msg': 'Created new repository `%s`' % repo_name,
799 'success': True,
800 'success': True,
800 }
801 }
801 expected = ret
802 expected = ret
802 self._compare_ok(id_, expected, given=response.body)
803 self._compare_ok(id_, expected, given=response.body)
803 fixture.destroy_repo(repo_name)
804 fixture.destroy_repo(repo_name)
804
805
805 @base.parametrize('repo_name', [
806 @base.parametrize('repo_name', [
806 '',
807 '',
807 '.',
808 '.',
808 '..',
809 '..',
809 ':',
810 ':',
810 '/',
811 '/',
811 '<test>',
812 '<test>',
812 ])
813 ])
813 def test_api_create_repo_bad_names(self, repo_name):
814 def test_api_create_repo_bad_names(self, repo_name):
814 id_, params = _build_data(self.apikey, 'create_repo',
815 id_, params = _build_data(self.apikey, 'create_repo',
815 repo_name=repo_name,
816 repo_name=repo_name,
816 owner=base.TEST_USER_ADMIN_LOGIN,
817 owner=base.TEST_USER_ADMIN_LOGIN,
817 repo_type=self.REPO_TYPE,
818 repo_type=self.REPO_TYPE,
818 )
819 )
819 response = api_call(self, params)
820 response = api_call(self, params)
820 if repo_name == '/':
821 if repo_name == '/':
821 expected = "repo group `` not found"
822 expected = "repo group `` not found"
822 self._compare_error(id_, expected, given=response.body)
823 self._compare_error(id_, expected, given=response.body)
823 else:
824 else:
824 expected = "failed to create repository `%s`" % repo_name
825 expected = "failed to create repository `%s`" % repo_name
825 self._compare_error(id_, expected, given=response.body)
826 self._compare_error(id_, expected, given=response.body)
826 fixture.destroy_repo(repo_name)
827 fixture.destroy_repo(repo_name)
827
828
828 def test_api_create_repo_clone_uri_local(self):
829 def test_api_create_repo_clone_uri_local(self):
829 # cloning from local repos was a mis-feature - it would bypass access control
830 # cloning from local repos was a mis-feature - it would bypass access control
830 # TODO: introduce other test coverage of actual remote cloning
831 # TODO: introduce other test coverage of actual remote cloning
831 clone_uri = os.path.join(base.TESTS_TMP_PATH, self.REPO)
832 clone_uri = os.path.join(base.TESTS_TMP_PATH, self.REPO)
832 repo_name = 'api-repo'
833 repo_name = 'api-repo'
833 id_, params = _build_data(self.apikey, 'create_repo',
834 id_, params = _build_data(self.apikey, 'create_repo',
834 repo_name=repo_name,
835 repo_name=repo_name,
835 owner=base.TEST_USER_ADMIN_LOGIN,
836 owner=base.TEST_USER_ADMIN_LOGIN,
836 repo_type=self.REPO_TYPE,
837 repo_type=self.REPO_TYPE,
837 clone_uri=clone_uri,
838 clone_uri=clone_uri,
838 )
839 )
839 response = api_call(self, params)
840 response = api_call(self, params)
840 expected = "failed to create repository `%s`" % repo_name
841 expected = "failed to create repository `%s`" % repo_name
841 self._compare_error(id_, expected, given=response.body)
842 self._compare_error(id_, expected, given=response.body)
842 fixture.destroy_repo(repo_name)
843 fixture.destroy_repo(repo_name)
843
844
844 def test_api_create_repo_and_repo_group(self):
845 def test_api_create_repo_and_repo_group(self):
845 repo_group_name = 'my_gr'
846 repo_group_name = 'my_gr'
846 repo_name = '%s/api-repo' % repo_group_name
847 repo_name = '%s/api-repo' % repo_group_name
847
848
848 # repo creation can no longer also create repo group
849 # repo creation can no longer also create repo group
849 id_, params = _build_data(self.apikey, 'create_repo',
850 id_, params = _build_data(self.apikey, 'create_repo',
850 repo_name=repo_name,
851 repo_name=repo_name,
851 owner=base.TEST_USER_ADMIN_LOGIN,
852 owner=base.TEST_USER_ADMIN_LOGIN,
852 repo_type=self.REPO_TYPE,)
853 repo_type=self.REPO_TYPE,)
853 response = api_call(self, params)
854 response = api_call(self, params)
854 expected = 'repo group `%s` not found' % repo_group_name
855 expected = 'repo group `%s` not found' % repo_group_name
855 self._compare_error(id_, expected, given=response.body)
856 self._compare_error(id_, expected, given=response.body)
856 assert RepoModel().get_by_repo_name(repo_name) is None
857 assert RepoModel().get_by_repo_name(repo_name) is None
857
858
858 # create group before creating repo
859 # create group before creating repo
859 rg = fixture.create_repo_group(repo_group_name)
860 rg = fixture.create_repo_group(repo_group_name)
860 meta.Session().commit()
861 meta.Session().commit()
861
862
862 id_, params = _build_data(self.apikey, 'create_repo',
863 id_, params = _build_data(self.apikey, 'create_repo',
863 repo_name=repo_name,
864 repo_name=repo_name,
864 owner=base.TEST_USER_ADMIN_LOGIN,
865 owner=base.TEST_USER_ADMIN_LOGIN,
865 repo_type=self.REPO_TYPE,)
866 repo_type=self.REPO_TYPE,)
866 response = api_call(self, params)
867 response = api_call(self, params)
867 expected = {
868 expected = {
868 'msg': 'Created new repository `%s`' % repo_name,
869 'msg': 'Created new repository `%s`' % repo_name,
869 'success': True,
870 'success': True,
870 }
871 }
871 self._compare_ok(id_, expected, given=response.body)
872 self._compare_ok(id_, expected, given=response.body)
872 repo = RepoModel().get_by_repo_name(repo_name)
873 repo = RepoModel().get_by_repo_name(repo_name)
873 assert repo is not None
874 assert repo is not None
874
875
875 fixture.destroy_repo(repo_name)
876 fixture.destroy_repo(repo_name)
876 fixture.destroy_repo_group(repo_group_name)
877 fixture.destroy_repo_group(repo_group_name)
877
878
878 def test_api_create_repo_in_repo_group_without_permission(self):
879 def test_api_create_repo_in_repo_group_without_permission(self):
879 repo_group_basename = 'api-repo-repo'
880 repo_group_basename = 'api-repo-repo'
880 repo_group_name = '%s/%s' % (TEST_REPO_GROUP, repo_group_basename)
881 repo_group_name = '%s/%s' % (TEST_REPO_GROUP, repo_group_basename)
881 repo_name = '%s/api-repo' % repo_group_name
882 repo_name = '%s/api-repo' % repo_group_name
882
883
883 top_group = db.RepoGroup.get_by_group_name(TEST_REPO_GROUP)
884 top_group = db.RepoGroup.get_by_group_name(TEST_REPO_GROUP)
884 assert top_group
885 assert top_group
885 rg = fixture.create_repo_group(repo_group_basename, parent_group_id=top_group)
886 rg = fixture.create_repo_group(repo_group_basename, parent_group_id=top_group)
886 meta.Session().commit()
887 meta.Session().commit()
887 RepoGroupModel().grant_user_permission(repo_group_name,
888 RepoGroupModel().grant_user_permission(repo_group_name,
888 self.TEST_USER_LOGIN,
889 self.TEST_USER_LOGIN,
889 'group.none')
890 'group.none')
890 meta.Session().commit()
891 meta.Session().commit()
891
892
892 id_, params = _build_data(self.apikey_regular, 'create_repo',
893 id_, params = _build_data(self.apikey_regular, 'create_repo',
893 repo_name=repo_name,
894 repo_name=repo_name,
894 repo_type=self.REPO_TYPE,
895 repo_type=self.REPO_TYPE,
895 )
896 )
896 response = api_call(self, params)
897 response = api_call(self, params)
897
898
898 # API access control match Web access control:
899 # API access control match Web access control:
899 expected = 'no permission to create repo in test_repo_group/api-repo-repo'
900 expected = 'no permission to create repo in test_repo_group/api-repo-repo'
900 self._compare_error(id_, expected, given=response.body)
901 self._compare_error(id_, expected, given=response.body)
901
902
902 fixture.destroy_repo(repo_name)
903 fixture.destroy_repo(repo_name)
903 fixture.destroy_repo_group(repo_group_name)
904 fixture.destroy_repo_group(repo_group_name)
904
905
905 def test_api_create_repo_unknown_owner(self):
906 def test_api_create_repo_unknown_owner(self):
906 repo_name = 'api-repo'
907 repo_name = 'api-repo'
907 owner = 'i-dont-exist'
908 owner = 'i-dont-exist'
908 id_, params = _build_data(self.apikey, 'create_repo',
909 id_, params = _build_data(self.apikey, 'create_repo',
909 repo_name=repo_name,
910 repo_name=repo_name,
910 owner=owner,
911 owner=owner,
911 repo_type=self.REPO_TYPE,
912 repo_type=self.REPO_TYPE,
912 )
913 )
913 response = api_call(self, params)
914 response = api_call(self, params)
914 expected = 'user `%s` does not exist' % owner
915 expected = 'user `%s` does not exist' % owner
915 self._compare_error(id_, expected, given=response.body)
916 self._compare_error(id_, expected, given=response.body)
916
917
917 def test_api_create_repo_dont_specify_owner(self):
918 def test_api_create_repo_dont_specify_owner(self):
918 repo_name = 'api-repo'
919 repo_name = 'api-repo'
919 owner = 'i-dont-exist'
920 owner = 'i-dont-exist'
920 id_, params = _build_data(self.apikey, 'create_repo',
921 id_, params = _build_data(self.apikey, 'create_repo',
921 repo_name=repo_name,
922 repo_name=repo_name,
922 repo_type=self.REPO_TYPE,
923 repo_type=self.REPO_TYPE,
923 )
924 )
924 response = api_call(self, params)
925 response = api_call(self, params)
925
926
926 repo = RepoModel().get_by_repo_name(repo_name)
927 repo = RepoModel().get_by_repo_name(repo_name)
927 assert repo is not None
928 assert repo is not None
928 ret = {
929 ret = {
929 'msg': 'Created new repository `%s`' % repo_name,
930 'msg': 'Created new repository `%s`' % repo_name,
930 'success': True,
931 'success': True,
931 }
932 }
932 expected = ret
933 expected = ret
933 self._compare_ok(id_, expected, given=response.body)
934 self._compare_ok(id_, expected, given=response.body)
934 fixture.destroy_repo(repo_name)
935 fixture.destroy_repo(repo_name)
935
936
936 def test_api_create_repo_by_non_admin(self):
937 def test_api_create_repo_by_non_admin(self):
937 repo_name = 'api-repo'
938 repo_name = 'api-repo'
938 owner = 'i-dont-exist'
939 owner = 'i-dont-exist'
939 id_, params = _build_data(self.apikey_regular, 'create_repo',
940 id_, params = _build_data(self.apikey_regular, 'create_repo',
940 repo_name=repo_name,
941 repo_name=repo_name,
941 repo_type=self.REPO_TYPE,
942 repo_type=self.REPO_TYPE,
942 )
943 )
943 response = api_call(self, params)
944 response = api_call(self, params)
944
945
945 repo = RepoModel().get_by_repo_name(repo_name)
946 repo = RepoModel().get_by_repo_name(repo_name)
946 assert repo is not None
947 assert repo is not None
947 ret = {
948 ret = {
948 'msg': 'Created new repository `%s`' % repo_name,
949 'msg': 'Created new repository `%s`' % repo_name,
949 'success': True,
950 'success': True,
950 }
951 }
951 expected = ret
952 expected = ret
952 self._compare_ok(id_, expected, given=response.body)
953 self._compare_ok(id_, expected, given=response.body)
953 fixture.destroy_repo(repo_name)
954 fixture.destroy_repo(repo_name)
954
955
955 def test_api_create_repo_by_non_admin_specify_owner(self):
956 def test_api_create_repo_by_non_admin_specify_owner(self):
956 repo_name = 'api-repo'
957 repo_name = 'api-repo'
957 owner = 'i-dont-exist'
958 owner = 'i-dont-exist'
958 id_, params = _build_data(self.apikey_regular, 'create_repo',
959 id_, params = _build_data(self.apikey_regular, 'create_repo',
959 repo_name=repo_name,
960 repo_name=repo_name,
960 repo_type=self.REPO_TYPE,
961 repo_type=self.REPO_TYPE,
961 owner=owner)
962 owner=owner)
962 response = api_call(self, params)
963 response = api_call(self, params)
963
964
964 expected = 'Only Kallithea admin can specify `owner` param'
965 expected = 'Only Kallithea admin can specify `owner` param'
965 self._compare_error(id_, expected, given=response.body)
966 self._compare_error(id_, expected, given=response.body)
966 fixture.destroy_repo(repo_name)
967 fixture.destroy_repo(repo_name)
967
968
968 def test_api_create_repo_exists(self):
969 def test_api_create_repo_exists(self):
969 repo_name = self.REPO
970 repo_name = self.REPO
970 id_, params = _build_data(self.apikey, 'create_repo',
971 id_, params = _build_data(self.apikey, 'create_repo',
971 repo_name=repo_name,
972 repo_name=repo_name,
972 owner=base.TEST_USER_ADMIN_LOGIN,
973 owner=base.TEST_USER_ADMIN_LOGIN,
973 repo_type=self.REPO_TYPE,)
974 repo_type=self.REPO_TYPE,)
974 response = api_call(self, params)
975 response = api_call(self, params)
975 expected = "repo `%s` already exist" % repo_name
976 expected = "repo `%s` already exist" % repo_name
976 self._compare_error(id_, expected, given=response.body)
977 self._compare_error(id_, expected, given=response.body)
977
978
978 def test_api_create_repo_dot_dot(self):
979 def test_api_create_repo_dot_dot(self):
979 # it is only possible to create repositories in existing repo groups - and '..' can't be used
980 # it is only possible to create repositories in existing repo groups - and '..' can't be used
980 group_name = '%s/..' % TEST_REPO_GROUP
981 group_name = '%s/..' % TEST_REPO_GROUP
981 repo_name = '%s/%s' % (group_name, 'could-be-outside')
982 repo_name = '%s/%s' % (group_name, 'could-be-outside')
982 id_, params = _build_data(self.apikey, 'create_repo',
983 id_, params = _build_data(self.apikey, 'create_repo',
983 repo_name=repo_name,
984 repo_name=repo_name,
984 owner=base.TEST_USER_ADMIN_LOGIN,
985 owner=base.TEST_USER_ADMIN_LOGIN,
985 repo_type=self.REPO_TYPE,)
986 repo_type=self.REPO_TYPE,)
986 response = api_call(self, params)
987 response = api_call(self, params)
987 expected = 'repo group `%s` not found' % group_name
988 expected = 'repo group `%s` not found' % group_name
988 self._compare_error(id_, expected, given=response.body)
989 self._compare_error(id_, expected, given=response.body)
989 fixture.destroy_repo(repo_name)
990 fixture.destroy_repo(repo_name)
990
991
991 @mock.patch.object(RepoModel, 'create', raise_exception)
992 @mock.patch.object(RepoModel, 'create', raise_exception)
992 def test_api_create_repo_exception_occurred(self):
993 def test_api_create_repo_exception_occurred(self):
993 repo_name = 'api-repo'
994 repo_name = 'api-repo'
994 id_, params = _build_data(self.apikey, 'create_repo',
995 id_, params = _build_data(self.apikey, 'create_repo',
995 repo_name=repo_name,
996 repo_name=repo_name,
996 owner=base.TEST_USER_ADMIN_LOGIN,
997 owner=base.TEST_USER_ADMIN_LOGIN,
997 repo_type=self.REPO_TYPE,)
998 repo_type=self.REPO_TYPE,)
998 response = api_call(self, params)
999 response = api_call(self, params)
999 expected = 'failed to create repository `%s`' % repo_name
1000 expected = 'failed to create repository `%s`' % repo_name
1000 self._compare_error(id_, expected, given=response.body)
1001 self._compare_error(id_, expected, given=response.body)
1001
1002
1002 @base.parametrize('changing_attr,updates', [
1003 @base.parametrize('changing_attr,updates', [
1003 ('owner', {'owner': base.TEST_USER_REGULAR_LOGIN}),
1004 ('owner', {'owner': base.TEST_USER_REGULAR_LOGIN}),
1004 ('description', {'description': 'new description'}),
1005 ('description', {'description': 'new description'}),
1005 ('clone_uri', {'clone_uri': 'http://example.com/repo'}), # will fail - pulling from non-existing repo should fail
1006 ('clone_uri', {'clone_uri': 'http://example.com/repo'}), # will fail - pulling from non-existing repo should fail
1006 ('clone_uri', {'clone_uri': '/repo'}), # will fail - pulling from local repo was a mis-feature - it would bypass access control
1007 ('clone_uri', {'clone_uri': '/repo'}), # will fail - pulling from local repo was a mis-feature - it would bypass access control
1007 ('clone_uri', {'clone_uri': None}),
1008 ('clone_uri', {'clone_uri': None}),
1008 ('landing_rev', {'landing_rev': 'branch:master'}),
1009 ('landing_rev', {'landing_rev': 'branch:master'}),
1009 ('enable_statistics', {'enable_statistics': True}),
1010 ('enable_statistics', {'enable_statistics': True}),
1010 ('enable_downloads', {'enable_downloads': True}),
1011 ('enable_downloads', {'enable_downloads': True}),
1011 ('name', {'name': 'new_repo_name'}),
1012 ('name', {'name': 'new_repo_name'}),
1012 ('repo_group', {'group': 'test_group_for_update'}),
1013 ('repo_group', {'group': 'test_group_for_update'}),
1013 ])
1014 ])
1014 def test_api_update_repo(self, changing_attr, updates):
1015 def test_api_update_repo(self, changing_attr, updates):
1015 repo_name = 'api_update_me'
1016 repo_name = 'api_update_me'
1016 repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1017 repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1017 if changing_attr == 'repo_group':
1018 if changing_attr == 'repo_group':
1018 fixture.create_repo_group(updates['group'])
1019 fixture.create_repo_group(updates['group'])
1019
1020
1020 id_, params = _build_data(self.apikey, 'update_repo',
1021 id_, params = _build_data(self.apikey, 'update_repo',
1021 repoid=repo_name, **updates)
1022 repoid=repo_name, **updates)
1022 response = api_call(self, params)
1023 response = api_call(self, params)
1023 if changing_attr == 'name':
1024 if changing_attr == 'name':
1024 repo_name = updates['name']
1025 repo_name = updates['name']
1025 if changing_attr == 'repo_group':
1026 if changing_attr == 'repo_group':
1026 repo_name = '/'.join([updates['group'], repo_name])
1027 repo_name = '/'.join([updates['group'], repo_name])
1027 try:
1028 try:
1028 if changing_attr == 'clone_uri' and updates['clone_uri']:
1029 if changing_attr == 'clone_uri' and updates['clone_uri']:
1029 expected = 'failed to update repo `%s`' % repo_name
1030 expected = 'failed to update repo `%s`' % repo_name
1030 self._compare_error(id_, expected, given=response.body)
1031 self._compare_error(id_, expected, given=response.body)
1031 else:
1032 else:
1032 expected = {
1033 expected = {
1033 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
1034 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
1034 'repository': repo.get_api_data()
1035 'repository': repo.get_api_data()
1035 }
1036 }
1036 self._compare_ok(id_, expected, given=response.body)
1037 self._compare_ok(id_, expected, given=response.body)
1037 finally:
1038 finally:
1038 fixture.destroy_repo(repo_name)
1039 fixture.destroy_repo(repo_name)
1039 if changing_attr == 'repo_group':
1040 if changing_attr == 'repo_group':
1040 fixture.destroy_repo_group(updates['group'])
1041 fixture.destroy_repo_group(updates['group'])
1041
1042
1042 @base.parametrize('changing_attr,updates', [
1043 @base.parametrize('changing_attr,updates', [
1043 ('owner', {'owner': base.TEST_USER_REGULAR_LOGIN}),
1044 ('owner', {'owner': base.TEST_USER_REGULAR_LOGIN}),
1044 ('description', {'description': 'new description'}),
1045 ('description', {'description': 'new description'}),
1045 ('clone_uri', {'clone_uri': 'http://example.com/repo'}), # will fail - pulling from non-existing repo should fail
1046 ('clone_uri', {'clone_uri': 'http://example.com/repo'}), # will fail - pulling from non-existing repo should fail
1046 ('clone_uri', {'clone_uri': '/repo'}), # will fail - pulling from local repo was a mis-feature - it would bypass access control
1047 ('clone_uri', {'clone_uri': '/repo'}), # will fail - pulling from local repo was a mis-feature - it would bypass access control
1047 ('clone_uri', {'clone_uri': None}),
1048 ('clone_uri', {'clone_uri': None}),
1048 ('landing_rev', {'landing_rev': 'branch:master'}),
1049 ('landing_rev', {'landing_rev': 'branch:master'}),
1049 ('enable_statistics', {'enable_statistics': True}),
1050 ('enable_statistics', {'enable_statistics': True}),
1050 ('enable_downloads', {'enable_downloads': True}),
1051 ('enable_downloads', {'enable_downloads': True}),
1051 ('name', {'name': 'new_repo_name'}),
1052 ('name', {'name': 'new_repo_name'}),
1052 ('repo_group', {'group': 'test_group_for_update'}),
1053 ('repo_group', {'group': 'test_group_for_update'}),
1053 ])
1054 ])
1054 def test_api_update_group_repo(self, changing_attr, updates):
1055 def test_api_update_group_repo(self, changing_attr, updates):
1055 group_name = 'lololo'
1056 group_name = 'lololo'
1056 fixture.create_repo_group(group_name)
1057 fixture.create_repo_group(group_name)
1057 repo_name = '%s/api_update_me' % group_name
1058 repo_name = '%s/api_update_me' % group_name
1058 repo = fixture.create_repo(repo_name, repo_group=group_name, repo_type=self.REPO_TYPE)
1059 repo = fixture.create_repo(repo_name, repo_group=group_name, repo_type=self.REPO_TYPE)
1059 if changing_attr == 'repo_group':
1060 if changing_attr == 'repo_group':
1060 fixture.create_repo_group(updates['group'])
1061 fixture.create_repo_group(updates['group'])
1061
1062
1062 id_, params = _build_data(self.apikey, 'update_repo',
1063 id_, params = _build_data(self.apikey, 'update_repo',
1063 repoid=repo_name, **updates)
1064 repoid=repo_name, **updates)
1064 response = api_call(self, params)
1065 response = api_call(self, params)
1065 if changing_attr == 'name':
1066 if changing_attr == 'name':
1066 repo_name = '%s/%s' % (group_name, updates['name'])
1067 repo_name = '%s/%s' % (group_name, updates['name'])
1067 if changing_attr == 'repo_group':
1068 if changing_attr == 'repo_group':
1068 repo_name = '/'.join([updates['group'], repo_name.rsplit('/', 1)[-1]])
1069 repo_name = '/'.join([updates['group'], repo_name.rsplit('/', 1)[-1]])
1069 try:
1070 try:
1070 if changing_attr == 'clone_uri' and updates['clone_uri']:
1071 if changing_attr == 'clone_uri' and updates['clone_uri']:
1071 expected = 'failed to update repo `%s`' % repo_name
1072 expected = 'failed to update repo `%s`' % repo_name
1072 self._compare_error(id_, expected, given=response.body)
1073 self._compare_error(id_, expected, given=response.body)
1073 else:
1074 else:
1074 expected = {
1075 expected = {
1075 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
1076 'msg': 'updated repo ID:%s %s' % (repo.repo_id, repo_name),
1076 'repository': repo.get_api_data()
1077 'repository': repo.get_api_data()
1077 }
1078 }
1078 self._compare_ok(id_, expected, given=response.body)
1079 self._compare_ok(id_, expected, given=response.body)
1079 finally:
1080 finally:
1080 fixture.destroy_repo(repo_name)
1081 fixture.destroy_repo(repo_name)
1081 if changing_attr == 'repo_group':
1082 if changing_attr == 'repo_group':
1082 fixture.destroy_repo_group(updates['group'])
1083 fixture.destroy_repo_group(updates['group'])
1083 fixture.destroy_repo_group(group_name)
1084 fixture.destroy_repo_group(group_name)
1084
1085
1085 def test_api_update_repo_repo_group_does_not_exist(self):
1086 def test_api_update_repo_repo_group_does_not_exist(self):
1086 repo_name = 'admin_owned'
1087 repo_name = 'admin_owned'
1087 fixture.create_repo(repo_name)
1088 fixture.create_repo(repo_name)
1088 updates = {'group': 'test_group_for_update'}
1089 updates = {'group': 'test_group_for_update'}
1089 id_, params = _build_data(self.apikey, 'update_repo',
1090 id_, params = _build_data(self.apikey, 'update_repo',
1090 repoid=repo_name, **updates)
1091 repoid=repo_name, **updates)
1091 response = api_call(self, params)
1092 response = api_call(self, params)
1092 try:
1093 try:
1093 expected = 'repository group `%s` does not exist' % updates['group']
1094 expected = 'repository group `%s` does not exist' % updates['group']
1094 self._compare_error(id_, expected, given=response.body)
1095 self._compare_error(id_, expected, given=response.body)
1095 finally:
1096 finally:
1096 fixture.destroy_repo(repo_name)
1097 fixture.destroy_repo(repo_name)
1097
1098
1098 def test_api_update_repo_regular_user_not_allowed(self):
1099 def test_api_update_repo_regular_user_not_allowed(self):
1099 repo_name = 'admin_owned'
1100 repo_name = 'admin_owned'
1100 fixture.create_repo(repo_name)
1101 fixture.create_repo(repo_name)
1101 updates = {'description': 'something else'}
1102 updates = {'description': 'something else'}
1102 id_, params = _build_data(self.apikey_regular, 'update_repo',
1103 id_, params = _build_data(self.apikey_regular, 'update_repo',
1103 repoid=repo_name, **updates)
1104 repoid=repo_name, **updates)
1104 response = api_call(self, params)
1105 response = api_call(self, params)
1105 try:
1106 try:
1106 expected = 'repository `%s` does not exist' % repo_name
1107 expected = 'repository `%s` does not exist' % repo_name
1107 self._compare_error(id_, expected, given=response.body)
1108 self._compare_error(id_, expected, given=response.body)
1108 finally:
1109 finally:
1109 fixture.destroy_repo(repo_name)
1110 fixture.destroy_repo(repo_name)
1110
1111
1111 @mock.patch.object(RepoModel, 'update', raise_exception)
1112 @mock.patch.object(RepoModel, 'update', raise_exception)
1112 def test_api_update_repo_exception_occurred(self):
1113 def test_api_update_repo_exception_occurred(self):
1113 repo_name = 'api_update_me'
1114 repo_name = 'api_update_me'
1114 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1115 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1115 id_, params = _build_data(self.apikey, 'update_repo',
1116 id_, params = _build_data(self.apikey, 'update_repo',
1116 repoid=repo_name, owner=base.TEST_USER_ADMIN_LOGIN,)
1117 repoid=repo_name, owner=base.TEST_USER_ADMIN_LOGIN,)
1117 response = api_call(self, params)
1118 response = api_call(self, params)
1118 try:
1119 try:
1119 expected = 'failed to update repo `%s`' % repo_name
1120 expected = 'failed to update repo `%s`' % repo_name
1120 self._compare_error(id_, expected, given=response.body)
1121 self._compare_error(id_, expected, given=response.body)
1121 finally:
1122 finally:
1122 fixture.destroy_repo(repo_name)
1123 fixture.destroy_repo(repo_name)
1123
1124
1124 def test_api_update_repo_regular_user_change_top_level_repo_name(self):
1125 def test_api_update_repo_regular_user_change_top_level_repo_name(self):
1125 repo_name = 'admin_owned'
1126 repo_name = 'admin_owned'
1126 new_repo_name = 'new_repo_name'
1127 new_repo_name = 'new_repo_name'
1127 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1128 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1128 RepoModel().grant_user_permission(repo=repo_name,
1129 RepoModel().grant_user_permission(repo=repo_name,
1129 user=self.TEST_USER_LOGIN,
1130 user=self.TEST_USER_LOGIN,
1130 perm='repository.admin')
1131 perm='repository.admin')
1131 UserModel().revoke_perm('default', 'hg.create.repository')
1132 UserModel().revoke_perm('default', 'hg.create.repository')
1132 UserModel().grant_perm('default', 'hg.create.none')
1133 UserModel().grant_perm('default', 'hg.create.none')
1133 updates = {'name': new_repo_name}
1134 updates = {'name': new_repo_name}
1134 id_, params = _build_data(self.apikey_regular, 'update_repo',
1135 id_, params = _build_data(self.apikey_regular, 'update_repo',
1135 repoid=repo_name, **updates)
1136 repoid=repo_name, **updates)
1136 response = api_call(self, params)
1137 response = api_call(self, params)
1137 try:
1138 try:
1138 expected = 'no permission to create (or move) top level repositories'
1139 expected = 'no permission to create (or move) top level repositories'
1139 self._compare_error(id_, expected, given=response.body)
1140 self._compare_error(id_, expected, given=response.body)
1140 finally:
1141 finally:
1141 fixture.destroy_repo(repo_name)
1142 fixture.destroy_repo(repo_name)
1142 fixture.destroy_repo(new_repo_name)
1143 fixture.destroy_repo(new_repo_name)
1143
1144
1144 def test_api_update_repo_regular_user_change_repo_name_allowed(self):
1145 def test_api_update_repo_regular_user_change_repo_name_allowed(self):
1145 repo_name = 'admin_owned'
1146 repo_name = 'admin_owned'
1146 new_repo_name = 'new_repo_name'
1147 new_repo_name = 'new_repo_name'
1147 repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1148 repo = fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1148 RepoModel().grant_user_permission(repo=repo_name,
1149 RepoModel().grant_user_permission(repo=repo_name,
1149 user=self.TEST_USER_LOGIN,
1150 user=self.TEST_USER_LOGIN,
1150 perm='repository.admin')
1151 perm='repository.admin')
1151 UserModel().revoke_perm('default', 'hg.create.none')
1152 UserModel().revoke_perm('default', 'hg.create.none')
1152 UserModel().grant_perm('default', 'hg.create.repository')
1153 UserModel().grant_perm('default', 'hg.create.repository')
1153 updates = {'name': new_repo_name}
1154 updates = {'name': new_repo_name}
1154 id_, params = _build_data(self.apikey_regular, 'update_repo',
1155 id_, params = _build_data(self.apikey_regular, 'update_repo',
1155 repoid=repo_name, **updates)
1156 repoid=repo_name, **updates)
1156 response = api_call(self, params)
1157 response = api_call(self, params)
1157 try:
1158 try:
1158 expected = {
1159 expected = {
1159 'msg': 'updated repo ID:%s %s' % (repo.repo_id, new_repo_name),
1160 'msg': 'updated repo ID:%s %s' % (repo.repo_id, new_repo_name),
1160 'repository': repo.get_api_data()
1161 'repository': repo.get_api_data()
1161 }
1162 }
1162 self._compare_ok(id_, expected, given=response.body)
1163 self._compare_ok(id_, expected, given=response.body)
1163 finally:
1164 finally:
1164 fixture.destroy_repo(repo_name)
1165 fixture.destroy_repo(repo_name)
1165 fixture.destroy_repo(new_repo_name)
1166 fixture.destroy_repo(new_repo_name)
1166
1167
1167 def test_api_update_repo_regular_user_change_owner(self):
1168 def test_api_update_repo_regular_user_change_owner(self):
1168 repo_name = 'admin_owned'
1169 repo_name = 'admin_owned'
1169 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1170 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1170 RepoModel().grant_user_permission(repo=repo_name,
1171 RepoModel().grant_user_permission(repo=repo_name,
1171 user=self.TEST_USER_LOGIN,
1172 user=self.TEST_USER_LOGIN,
1172 perm='repository.admin')
1173 perm='repository.admin')
1173 updates = {'owner': base.TEST_USER_ADMIN_LOGIN}
1174 updates = {'owner': base.TEST_USER_ADMIN_LOGIN}
1174 id_, params = _build_data(self.apikey_regular, 'update_repo',
1175 id_, params = _build_data(self.apikey_regular, 'update_repo',
1175 repoid=repo_name, **updates)
1176 repoid=repo_name, **updates)
1176 response = api_call(self, params)
1177 response = api_call(self, params)
1177 try:
1178 try:
1178 expected = 'Only Kallithea admin can specify `owner` param'
1179 expected = 'Only Kallithea admin can specify `owner` param'
1179 self._compare_error(id_, expected, given=response.body)
1180 self._compare_error(id_, expected, given=response.body)
1180 finally:
1181 finally:
1181 fixture.destroy_repo(repo_name)
1182 fixture.destroy_repo(repo_name)
1182
1183
1183 def test_api_delete_repo(self):
1184 def test_api_delete_repo(self):
1184 repo_name = 'api_delete_me'
1185 repo_name = 'api_delete_me'
1185 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1186 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1186
1187
1187 id_, params = _build_data(self.apikey, 'delete_repo',
1188 id_, params = _build_data(self.apikey, 'delete_repo',
1188 repoid=repo_name, )
1189 repoid=repo_name, )
1189 response = api_call(self, params)
1190 response = api_call(self, params)
1190
1191
1191 ret = {
1192 ret = {
1192 'msg': 'Deleted repository `%s`' % repo_name,
1193 'msg': 'Deleted repository `%s`' % repo_name,
1193 'success': True
1194 'success': True
1194 }
1195 }
1195 try:
1196 try:
1196 expected = ret
1197 expected = ret
1197 self._compare_ok(id_, expected, given=response.body)
1198 self._compare_ok(id_, expected, given=response.body)
1198 finally:
1199 finally:
1199 fixture.destroy_repo(repo_name)
1200 fixture.destroy_repo(repo_name)
1200
1201
1201 def test_api_delete_repo_by_non_admin(self):
1202 def test_api_delete_repo_by_non_admin(self):
1202 repo_name = 'api_delete_me'
1203 repo_name = 'api_delete_me'
1203 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
1204 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE,
1204 cur_user=self.TEST_USER_LOGIN)
1205 cur_user=self.TEST_USER_LOGIN)
1205 id_, params = _build_data(self.apikey_regular, 'delete_repo',
1206 id_, params = _build_data(self.apikey_regular, 'delete_repo',
1206 repoid=repo_name, )
1207 repoid=repo_name, )
1207 response = api_call(self, params)
1208 response = api_call(self, params)
1208
1209
1209 ret = {
1210 ret = {
1210 'msg': 'Deleted repository `%s`' % repo_name,
1211 'msg': 'Deleted repository `%s`' % repo_name,
1211 'success': True
1212 'success': True
1212 }
1213 }
1213 try:
1214 try:
1214 expected = ret
1215 expected = ret
1215 self._compare_ok(id_, expected, given=response.body)
1216 self._compare_ok(id_, expected, given=response.body)
1216 finally:
1217 finally:
1217 fixture.destroy_repo(repo_name)
1218 fixture.destroy_repo(repo_name)
1218
1219
1219 def test_api_delete_repo_by_non_admin_no_permission(self):
1220 def test_api_delete_repo_by_non_admin_no_permission(self):
1220 repo_name = 'api_delete_me'
1221 repo_name = 'api_delete_me'
1221 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1222 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1222 try:
1223 try:
1223 id_, params = _build_data(self.apikey_regular, 'delete_repo',
1224 id_, params = _build_data(self.apikey_regular, 'delete_repo',
1224 repoid=repo_name, )
1225 repoid=repo_name, )
1225 response = api_call(self, params)
1226 response = api_call(self, params)
1226 expected = 'repository `%s` does not exist' % (repo_name)
1227 expected = 'repository `%s` does not exist' % (repo_name)
1227 self._compare_error(id_, expected, given=response.body)
1228 self._compare_error(id_, expected, given=response.body)
1228 finally:
1229 finally:
1229 fixture.destroy_repo(repo_name)
1230 fixture.destroy_repo(repo_name)
1230
1231
1231 def test_api_delete_repo_exception_occurred(self):
1232 def test_api_delete_repo_exception_occurred(self):
1232 repo_name = 'api_delete_me'
1233 repo_name = 'api_delete_me'
1233 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1234 fixture.create_repo(repo_name, repo_type=self.REPO_TYPE)
1234 try:
1235 try:
1235 with mock.patch.object(RepoModel, 'delete', raise_exception):
1236 with mock.patch.object(RepoModel, 'delete', raise_exception):
1236 id_, params = _build_data(self.apikey, 'delete_repo',
1237 id_, params = _build_data(self.apikey, 'delete_repo',
1237 repoid=repo_name, )
1238 repoid=repo_name, )
1238 response = api_call(self, params)
1239 response = api_call(self, params)
1239
1240
1240 expected = 'failed to delete repository `%s`' % repo_name
1241 expected = 'failed to delete repository `%s`' % repo_name
1241 self._compare_error(id_, expected, given=response.body)
1242 self._compare_error(id_, expected, given=response.body)
1242 finally:
1243 finally:
1243 fixture.destroy_repo(repo_name)
1244 fixture.destroy_repo(repo_name)
1244
1245
1245 def test_api_fork_repo(self):
1246 def test_api_fork_repo(self):
1246 fork_name = 'api-repo-fork'
1247 fork_name = 'api-repo-fork'
1247 id_, params = _build_data(self.apikey, 'fork_repo',
1248 id_, params = _build_data(self.apikey, 'fork_repo',
1248 repoid=self.REPO,
1249 repoid=self.REPO,
1249 fork_name=fork_name,
1250 fork_name=fork_name,
1250 owner=base.TEST_USER_ADMIN_LOGIN,
1251 owner=base.TEST_USER_ADMIN_LOGIN,
1251 )
1252 )
1252 response = api_call(self, params)
1253 response = api_call(self, params)
1253
1254
1254 ret = {
1255 ret = {
1255 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
1256 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
1256 fork_name),
1257 fork_name),
1257 'success': True,
1258 'success': True,
1258 }
1259 }
1259 expected = ret
1260 expected = ret
1260 self._compare_ok(id_, expected, given=response.body)
1261 self._compare_ok(id_, expected, given=response.body)
1261 fixture.destroy_repo(fork_name)
1262 fixture.destroy_repo(fork_name)
1262
1263
1263 @base.parametrize('fork_name', [
1264 @base.parametrize('fork_name', [
1264 'api-repo-fork',
1265 'api-repo-fork',
1265 '%s/api-repo-fork' % TEST_REPO_GROUP,
1266 '%s/api-repo-fork' % TEST_REPO_GROUP,
1266 ])
1267 ])
1267 def test_api_fork_repo_non_admin(self, fork_name):
1268 def test_api_fork_repo_non_admin(self, fork_name):
1268 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
1269 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
1269 self.TEST_USER_LOGIN,
1270 self.TEST_USER_LOGIN,
1270 'group.write')
1271 'group.write')
1271 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1272 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1272 repoid=self.REPO,
1273 repoid=self.REPO,
1273 fork_name=fork_name,
1274 fork_name=fork_name,
1274 )
1275 )
1275 response = api_call(self, params)
1276 response = api_call(self, params)
1276
1277
1277 ret = {
1278 ret = {
1278 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
1279 'msg': 'Created fork of `%s` as `%s`' % (self.REPO,
1279 fork_name),
1280 fork_name),
1280 'success': True,
1281 'success': True,
1281 }
1282 }
1282 expected = ret
1283 expected = ret
1283 self._compare_ok(id_, expected, given=response.body)
1284 self._compare_ok(id_, expected, given=response.body)
1284 fixture.destroy_repo(fork_name)
1285 fixture.destroy_repo(fork_name)
1285
1286
1286 def test_api_fork_repo_non_admin_specify_owner(self):
1287 def test_api_fork_repo_non_admin_specify_owner(self):
1287 fork_name = 'api-repo-fork'
1288 fork_name = 'api-repo-fork'
1288 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1289 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1289 repoid=self.REPO,
1290 repoid=self.REPO,
1290 fork_name=fork_name,
1291 fork_name=fork_name,
1291 owner=base.TEST_USER_ADMIN_LOGIN,
1292 owner=base.TEST_USER_ADMIN_LOGIN,
1292 )
1293 )
1293 response = api_call(self, params)
1294 response = api_call(self, params)
1294 expected = 'Only Kallithea admin can specify `owner` param'
1295 expected = 'Only Kallithea admin can specify `owner` param'
1295 self._compare_error(id_, expected, given=response.body)
1296 self._compare_error(id_, expected, given=response.body)
1296 fixture.destroy_repo(fork_name)
1297 fixture.destroy_repo(fork_name)
1297
1298
1298 def test_api_fork_repo_non_admin_no_permission_to_fork(self):
1299 def test_api_fork_repo_non_admin_no_permission_to_fork(self):
1299 RepoModel().grant_user_permission(repo=self.REPO,
1300 RepoModel().grant_user_permission(repo=self.REPO,
1300 user=db.User.DEFAULT_USER_NAME,
1301 user=db.User.DEFAULT_USER_NAME,
1301 perm='repository.none')
1302 perm='repository.none')
1302 fork_name = 'api-repo-fork'
1303 fork_name = 'api-repo-fork'
1303 try:
1304 try:
1304 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1305 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1305 repoid=self.REPO,
1306 repoid=self.REPO,
1306 fork_name=fork_name,
1307 fork_name=fork_name,
1307 )
1308 )
1308 response = api_call(self, params)
1309 response = api_call(self, params)
1309 expected = 'repository `%s` does not exist' % (self.REPO)
1310 expected = 'repository `%s` does not exist' % (self.REPO)
1310 self._compare_error(id_, expected, given=response.body)
1311 self._compare_error(id_, expected, given=response.body)
1311 finally:
1312 finally:
1312 RepoModel().grant_user_permission(repo=self.REPO,
1313 RepoModel().grant_user_permission(repo=self.REPO,
1313 user=db.User.DEFAULT_USER_NAME,
1314 user=db.User.DEFAULT_USER_NAME,
1314 perm='repository.read')
1315 perm='repository.read')
1315 fixture.destroy_repo(fork_name)
1316 fixture.destroy_repo(fork_name)
1316
1317
1317 @base.parametrize('name,perm', [
1318 @base.parametrize('name,perm', [
1318 ('read', 'repository.read'),
1319 ('read', 'repository.read'),
1319 ('write', 'repository.write'),
1320 ('write', 'repository.write'),
1320 ('admin', 'repository.admin'),
1321 ('admin', 'repository.admin'),
1321 ])
1322 ])
1322 def test_api_fork_repo_non_admin_no_create_repo_permission(self, name, perm):
1323 def test_api_fork_repo_non_admin_no_create_repo_permission(self, name, perm):
1323 fork_name = 'api-repo-fork'
1324 fork_name = 'api-repo-fork'
1324 # regardless of base repository permission, forking is disallowed
1325 # regardless of base repository permission, forking is disallowed
1325 # when repository creation is disabled
1326 # when repository creation is disabled
1326 RepoModel().grant_user_permission(repo=self.REPO,
1327 RepoModel().grant_user_permission(repo=self.REPO,
1327 user=self.TEST_USER_LOGIN,
1328 user=self.TEST_USER_LOGIN,
1328 perm=perm)
1329 perm=perm)
1329 UserModel().revoke_perm('default', 'hg.create.repository')
1330 UserModel().revoke_perm('default', 'hg.create.repository')
1330 UserModel().grant_perm('default', 'hg.create.none')
1331 UserModel().grant_perm('default', 'hg.create.none')
1331 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1332 id_, params = _build_data(self.apikey_regular, 'fork_repo',
1332 repoid=self.REPO,
1333 repoid=self.REPO,
1333 fork_name=fork_name,
1334 fork_name=fork_name,
1334 )
1335 )
1335 response = api_call(self, params)
1336 response = api_call(self, params)
1336 expected = 'no permission to create top level repo'
1337 expected = 'no permission to create top level repo'
1337 self._compare_error(id_, expected, given=response.body)
1338 self._compare_error(id_, expected, given=response.body)
1338 fixture.destroy_repo(fork_name)
1339 fixture.destroy_repo(fork_name)
1339
1340
1340 def test_api_fork_repo_unknown_owner(self):
1341 def test_api_fork_repo_unknown_owner(self):
1341 fork_name = 'api-repo-fork'
1342 fork_name = 'api-repo-fork'
1342 owner = 'i-dont-exist'
1343 owner = 'i-dont-exist'
1343 id_, params = _build_data(self.apikey, 'fork_repo',
1344 id_, params = _build_data(self.apikey, 'fork_repo',
1344 repoid=self.REPO,
1345 repoid=self.REPO,
1345 fork_name=fork_name,
1346 fork_name=fork_name,
1346 owner=owner,
1347 owner=owner,
1347 )
1348 )
1348 response = api_call(self, params)
1349 response = api_call(self, params)
1349 expected = 'user `%s` does not exist' % owner
1350 expected = 'user `%s` does not exist' % owner
1350 self._compare_error(id_, expected, given=response.body)
1351 self._compare_error(id_, expected, given=response.body)
1351
1352
1352 def test_api_fork_repo_fork_exists(self):
1353 def test_api_fork_repo_fork_exists(self):
1353 fork_name = 'api-repo-fork'
1354 fork_name = 'api-repo-fork'
1354 fixture.create_fork(self.REPO, fork_name)
1355 fixture.create_fork(self.REPO, fork_name)
1355
1356
1356 try:
1357 try:
1357 fork_name = 'api-repo-fork'
1358 fork_name = 'api-repo-fork'
1358
1359
1359 id_, params = _build_data(self.apikey, 'fork_repo',
1360 id_, params = _build_data(self.apikey, 'fork_repo',
1360 repoid=self.REPO,
1361 repoid=self.REPO,
1361 fork_name=fork_name,
1362 fork_name=fork_name,
1362 owner=base.TEST_USER_ADMIN_LOGIN,
1363 owner=base.TEST_USER_ADMIN_LOGIN,
1363 )
1364 )
1364 response = api_call(self, params)
1365 response = api_call(self, params)
1365
1366
1366 expected = "fork `%s` already exist" % fork_name
1367 expected = "fork `%s` already exist" % fork_name
1367 self._compare_error(id_, expected, given=response.body)
1368 self._compare_error(id_, expected, given=response.body)
1368 finally:
1369 finally:
1369 fixture.destroy_repo(fork_name)
1370 fixture.destroy_repo(fork_name)
1370
1371
1371 def test_api_fork_repo_repo_exists(self):
1372 def test_api_fork_repo_repo_exists(self):
1372 fork_name = self.REPO
1373 fork_name = self.REPO
1373
1374
1374 id_, params = _build_data(self.apikey, 'fork_repo',
1375 id_, params = _build_data(self.apikey, 'fork_repo',
1375 repoid=self.REPO,
1376 repoid=self.REPO,
1376 fork_name=fork_name,
1377 fork_name=fork_name,
1377 owner=base.TEST_USER_ADMIN_LOGIN,
1378 owner=base.TEST_USER_ADMIN_LOGIN,
1378 )
1379 )
1379 response = api_call(self, params)
1380 response = api_call(self, params)
1380
1381
1381 expected = "repo `%s` already exist" % fork_name
1382 expected = "repo `%s` already exist" % fork_name
1382 self._compare_error(id_, expected, given=response.body)
1383 self._compare_error(id_, expected, given=response.body)
1383
1384
1384 @mock.patch.object(RepoModel, 'create_fork', raise_exception)
1385 @mock.patch.object(RepoModel, 'create_fork', raise_exception)
1385 def test_api_fork_repo_exception_occurred(self):
1386 def test_api_fork_repo_exception_occurred(self):
1386 fork_name = 'api-repo-fork'
1387 fork_name = 'api-repo-fork'
1387 id_, params = _build_data(self.apikey, 'fork_repo',
1388 id_, params = _build_data(self.apikey, 'fork_repo',
1388 repoid=self.REPO,
1389 repoid=self.REPO,
1389 fork_name=fork_name,
1390 fork_name=fork_name,
1390 owner=base.TEST_USER_ADMIN_LOGIN,
1391 owner=base.TEST_USER_ADMIN_LOGIN,
1391 )
1392 )
1392 response = api_call(self, params)
1393 response = api_call(self, params)
1393
1394
1394 expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
1395 expected = 'failed to fork repository `%s` as `%s`' % (self.REPO,
1395 fork_name)
1396 fork_name)
1396 self._compare_error(id_, expected, given=response.body)
1397 self._compare_error(id_, expected, given=response.body)
1397
1398
1398 def test_api_get_user_group(self):
1399 def test_api_get_user_group(self):
1399 id_, params = _build_data(self.apikey, 'get_user_group',
1400 id_, params = _build_data(self.apikey, 'get_user_group',
1400 usergroupid=TEST_USER_GROUP)
1401 usergroupid=TEST_USER_GROUP)
1401 response = api_call(self, params)
1402 response = api_call(self, params)
1402
1403
1403 user_group = UserGroupModel().get_group(TEST_USER_GROUP)
1404 user_group = UserGroupModel().get_group(TEST_USER_GROUP)
1404 members = []
1405 members = []
1405 for user in user_group.members:
1406 for user in user_group.members:
1406 user = user.user
1407 user = user.user
1407 members.append(user.get_api_data())
1408 members.append(user.get_api_data())
1408
1409
1409 ret = user_group.get_api_data()
1410 ret = user_group.get_api_data()
1410 ret['members'] = members
1411 ret['members'] = members
1411 expected = ret
1412 expected = ret
1412 self._compare_ok(id_, expected, given=response.body)
1413 self._compare_ok(id_, expected, given=response.body)
1413
1414
1414 def test_api_get_user_groups(self):
1415 def test_api_get_user_groups(self):
1415 gr_name = 'test_user_group2'
1416 gr_name = 'test_user_group2'
1416 make_user_group(gr_name)
1417 make_user_group(gr_name)
1417
1418
1418 try:
1419 try:
1419 id_, params = _build_data(self.apikey, 'get_user_groups', )
1420 id_, params = _build_data(self.apikey, 'get_user_groups', )
1420 response = api_call(self, params)
1421 response = api_call(self, params)
1421
1422
1422 expected = []
1423 expected = []
1423 for gr_name in [TEST_USER_GROUP, 'test_user_group2']:
1424 for gr_name in [TEST_USER_GROUP, 'test_user_group2']:
1424 user_group = UserGroupModel().get_group(gr_name)
1425 user_group = UserGroupModel().get_group(gr_name)
1425 ret = user_group.get_api_data()
1426 ret = user_group.get_api_data()
1426 expected.append(ret)
1427 expected.append(ret)
1427 self._compare_ok(id_, expected, given=response.body)
1428 self._compare_ok(id_, expected, given=response.body)
1428 finally:
1429 finally:
1429 fixture.destroy_user_group(gr_name)
1430 fixture.destroy_user_group(gr_name)
1430
1431
1431 def test_api_create_user_group(self):
1432 def test_api_create_user_group(self):
1432 group_name = 'some_new_group'
1433 group_name = 'some_new_group'
1433 id_, params = _build_data(self.apikey, 'create_user_group',
1434 id_, params = _build_data(self.apikey, 'create_user_group',
1434 group_name=group_name)
1435 group_name=group_name)
1435 response = api_call(self, params)
1436 response = api_call(self, params)
1436
1437
1437 ret = {
1438 ret = {
1438 'msg': 'created new user group `%s`' % group_name,
1439 'msg': 'created new user group `%s`' % group_name,
1439 'user_group': jsonify(UserGroupModel() \
1440 'user_group': jsonify(UserGroupModel() \
1440 .get_by_name(group_name) \
1441 .get_by_name(group_name) \
1441 .get_api_data())
1442 .get_api_data())
1442 }
1443 }
1443 expected = ret
1444 expected = ret
1444 self._compare_ok(id_, expected, given=response.body)
1445 self._compare_ok(id_, expected, given=response.body)
1445
1446
1446 fixture.destroy_user_group(group_name)
1447 fixture.destroy_user_group(group_name)
1447
1448
1448 def test_api_get_user_group_that_exist(self):
1449 def test_api_get_user_group_that_exist(self):
1449 id_, params = _build_data(self.apikey, 'create_user_group',
1450 id_, params = _build_data(self.apikey, 'create_user_group',
1450 group_name=TEST_USER_GROUP)
1451 group_name=TEST_USER_GROUP)
1451 response = api_call(self, params)
1452 response = api_call(self, params)
1452
1453
1453 expected = "user group `%s` already exist" % TEST_USER_GROUP
1454 expected = "user group `%s` already exist" % TEST_USER_GROUP
1454 self._compare_error(id_, expected, given=response.body)
1455 self._compare_error(id_, expected, given=response.body)
1455
1456
1456 @mock.patch.object(UserGroupModel, 'create', raise_exception)
1457 @mock.patch.object(UserGroupModel, 'create', raise_exception)
1457 def test_api_get_user_group_exception_occurred(self):
1458 def test_api_get_user_group_exception_occurred(self):
1458 group_name = 'exception_happens'
1459 group_name = 'exception_happens'
1459 id_, params = _build_data(self.apikey, 'create_user_group',
1460 id_, params = _build_data(self.apikey, 'create_user_group',
1460 group_name=group_name)
1461 group_name=group_name)
1461 response = api_call(self, params)
1462 response = api_call(self, params)
1462
1463
1463 expected = 'failed to create group `%s`' % group_name
1464 expected = 'failed to create group `%s`' % group_name
1464 self._compare_error(id_, expected, given=response.body)
1465 self._compare_error(id_, expected, given=response.body)
1465
1466
1466 @base.parametrize('changing_attr,updates', [
1467 @base.parametrize('changing_attr,updates', [
1467 ('group_name', {'group_name': 'new_group_name'}),
1468 ('group_name', {'group_name': 'new_group_name'}),
1468 ('group_name', {'group_name': 'test_group_for_update'}),
1469 ('group_name', {'group_name': 'test_group_for_update'}),
1469 ('owner', {'owner': base.TEST_USER_REGULAR_LOGIN}),
1470 ('owner', {'owner': base.TEST_USER_REGULAR_LOGIN}),
1470 ('active', {'active': False}),
1471 ('active', {'active': False}),
1471 ('active', {'active': True}),
1472 ('active', {'active': True}),
1472 ])
1473 ])
1473 def test_api_update_user_group(self, changing_attr, updates):
1474 def test_api_update_user_group(self, changing_attr, updates):
1474 gr_name = 'test_group_for_update'
1475 gr_name = 'test_group_for_update'
1475 user_group = fixture.create_user_group(gr_name)
1476 user_group = fixture.create_user_group(gr_name)
1476 try:
1477 try:
1477 id_, params = _build_data(self.apikey, 'update_user_group',
1478 id_, params = _build_data(self.apikey, 'update_user_group',
1478 usergroupid=gr_name, **updates)
1479 usergroupid=gr_name, **updates)
1479 response = api_call(self, params)
1480 response = api_call(self, params)
1480 expected = {
1481 expected = {
1481 'msg': 'updated user group ID:%s %s' % (user_group.users_group_id,
1482 'msg': 'updated user group ID:%s %s' % (user_group.users_group_id,
1482 user_group.users_group_name),
1483 user_group.users_group_name),
1483 'user_group': user_group.get_api_data()
1484 'user_group': user_group.get_api_data()
1484 }
1485 }
1485 self._compare_ok(id_, expected, given=response.body)
1486 self._compare_ok(id_, expected, given=response.body)
1486 finally:
1487 finally:
1487 if changing_attr == 'group_name':
1488 if changing_attr == 'group_name':
1488 # switch to updated name for proper cleanup
1489 # switch to updated name for proper cleanup
1489 gr_name = updates['group_name']
1490 gr_name = updates['group_name']
1490 fixture.destroy_user_group(gr_name)
1491 fixture.destroy_user_group(gr_name)
1491
1492
1492 @mock.patch.object(UserGroupModel, 'update', raise_exception)
1493 @mock.patch.object(UserGroupModel, 'update', raise_exception)
1493 def test_api_update_user_group_exception_occurred(self):
1494 def test_api_update_user_group_exception_occurred(self):
1494 gr_name = 'test_group'
1495 gr_name = 'test_group'
1495 fixture.create_user_group(gr_name)
1496 fixture.create_user_group(gr_name)
1496 try:
1497 try:
1497 id_, params = _build_data(self.apikey, 'update_user_group',
1498 id_, params = _build_data(self.apikey, 'update_user_group',
1498 usergroupid=gr_name)
1499 usergroupid=gr_name)
1499 response = api_call(self, params)
1500 response = api_call(self, params)
1500 expected = 'failed to update user group `%s`' % gr_name
1501 expected = 'failed to update user group `%s`' % gr_name
1501 self._compare_error(id_, expected, given=response.body)
1502 self._compare_error(id_, expected, given=response.body)
1502 finally:
1503 finally:
1503 fixture.destroy_user_group(gr_name)
1504 fixture.destroy_user_group(gr_name)
1504
1505
1505 def test_api_add_user_to_user_group(self):
1506 def test_api_add_user_to_user_group(self):
1506 gr_name = 'test_group'
1507 gr_name = 'test_group'
1507 fixture.create_user_group(gr_name)
1508 fixture.create_user_group(gr_name)
1508 try:
1509 try:
1509 id_, params = _build_data(self.apikey, 'add_user_to_user_group',
1510 id_, params = _build_data(self.apikey, 'add_user_to_user_group',
1510 usergroupid=gr_name,
1511 usergroupid=gr_name,
1511 userid=base.TEST_USER_ADMIN_LOGIN)
1512 userid=base.TEST_USER_ADMIN_LOGIN)
1512 response = api_call(self, params)
1513 response = api_call(self, params)
1513 expected = {
1514 expected = {
1514 'msg': 'added member `%s` to user group `%s`' % (
1515 'msg': 'added member `%s` to user group `%s`' % (
1515 base.TEST_USER_ADMIN_LOGIN, gr_name),
1516 base.TEST_USER_ADMIN_LOGIN, gr_name),
1516 'success': True
1517 'success': True
1517 }
1518 }
1518 self._compare_ok(id_, expected, given=response.body)
1519 self._compare_ok(id_, expected, given=response.body)
1519 finally:
1520 finally:
1520 fixture.destroy_user_group(gr_name)
1521 fixture.destroy_user_group(gr_name)
1521
1522
1522 def test_api_add_user_to_user_group_that_doesnt_exist(self):
1523 def test_api_add_user_to_user_group_that_doesnt_exist(self):
1523 id_, params = _build_data(self.apikey, 'add_user_to_user_group',
1524 id_, params = _build_data(self.apikey, 'add_user_to_user_group',
1524 usergroupid='false-group',
1525 usergroupid='false-group',
1525 userid=base.TEST_USER_ADMIN_LOGIN)
1526 userid=base.TEST_USER_ADMIN_LOGIN)
1526 response = api_call(self, params)
1527 response = api_call(self, params)
1527
1528
1528 expected = 'user group `%s` does not exist' % 'false-group'
1529 expected = 'user group `%s` does not exist' % 'false-group'
1529 self._compare_error(id_, expected, given=response.body)
1530 self._compare_error(id_, expected, given=response.body)
1530
1531
1531 @mock.patch.object(UserGroupModel, 'add_user_to_group', raise_exception)
1532 @mock.patch.object(UserGroupModel, 'add_user_to_group', raise_exception)
1532 def test_api_add_user_to_user_group_exception_occurred(self):
1533 def test_api_add_user_to_user_group_exception_occurred(self):
1533 gr_name = 'test_group'
1534 gr_name = 'test_group'
1534 fixture.create_user_group(gr_name)
1535 fixture.create_user_group(gr_name)
1535 try:
1536 try:
1536 id_, params = _build_data(self.apikey, 'add_user_to_user_group',
1537 id_, params = _build_data(self.apikey, 'add_user_to_user_group',
1537 usergroupid=gr_name,
1538 usergroupid=gr_name,
1538 userid=base.TEST_USER_ADMIN_LOGIN)
1539 userid=base.TEST_USER_ADMIN_LOGIN)
1539 response = api_call(self, params)
1540 response = api_call(self, params)
1540 expected = 'failed to add member to user group `%s`' % gr_name
1541 expected = 'failed to add member to user group `%s`' % gr_name
1541 self._compare_error(id_, expected, given=response.body)
1542 self._compare_error(id_, expected, given=response.body)
1542 finally:
1543 finally:
1543 fixture.destroy_user_group(gr_name)
1544 fixture.destroy_user_group(gr_name)
1544
1545
1545 def test_api_remove_user_from_user_group(self):
1546 def test_api_remove_user_from_user_group(self):
1546 gr_name = 'test_group_3'
1547 gr_name = 'test_group_3'
1547 gr = fixture.create_user_group(gr_name)
1548 gr = fixture.create_user_group(gr_name)
1548 UserGroupModel().add_user_to_group(gr, user=base.TEST_USER_ADMIN_LOGIN)
1549 UserGroupModel().add_user_to_group(gr, user=base.TEST_USER_ADMIN_LOGIN)
1549 meta.Session().commit()
1550 meta.Session().commit()
1550 try:
1551 try:
1551 id_, params = _build_data(self.apikey, 'remove_user_from_user_group',
1552 id_, params = _build_data(self.apikey, 'remove_user_from_user_group',
1552 usergroupid=gr_name,
1553 usergroupid=gr_name,
1553 userid=base.TEST_USER_ADMIN_LOGIN)
1554 userid=base.TEST_USER_ADMIN_LOGIN)
1554 response = api_call(self, params)
1555 response = api_call(self, params)
1555 expected = {
1556 expected = {
1556 'msg': 'removed member `%s` from user group `%s`' % (
1557 'msg': 'removed member `%s` from user group `%s`' % (
1557 base.TEST_USER_ADMIN_LOGIN, gr_name
1558 base.TEST_USER_ADMIN_LOGIN, gr_name
1558 ),
1559 ),
1559 'success': True}
1560 'success': True}
1560 self._compare_ok(id_, expected, given=response.body)
1561 self._compare_ok(id_, expected, given=response.body)
1561 finally:
1562 finally:
1562 fixture.destroy_user_group(gr_name)
1563 fixture.destroy_user_group(gr_name)
1563
1564
1564 @mock.patch.object(UserGroupModel, 'remove_user_from_group', raise_exception)
1565 @mock.patch.object(UserGroupModel, 'remove_user_from_group', raise_exception)
1565 def test_api_remove_user_from_user_group_exception_occurred(self):
1566 def test_api_remove_user_from_user_group_exception_occurred(self):
1566 gr_name = 'test_group_3'
1567 gr_name = 'test_group_3'
1567 gr = fixture.create_user_group(gr_name)
1568 gr = fixture.create_user_group(gr_name)
1568 UserGroupModel().add_user_to_group(gr, user=base.TEST_USER_ADMIN_LOGIN)
1569 UserGroupModel().add_user_to_group(gr, user=base.TEST_USER_ADMIN_LOGIN)
1569 meta.Session().commit()
1570 meta.Session().commit()
1570 try:
1571 try:
1571 id_, params = _build_data(self.apikey, 'remove_user_from_user_group',
1572 id_, params = _build_data(self.apikey, 'remove_user_from_user_group',
1572 usergroupid=gr_name,
1573 usergroupid=gr_name,
1573 userid=base.TEST_USER_ADMIN_LOGIN)
1574 userid=base.TEST_USER_ADMIN_LOGIN)
1574 response = api_call(self, params)
1575 response = api_call(self, params)
1575 expected = 'failed to remove member from user group `%s`' % gr_name
1576 expected = 'failed to remove member from user group `%s`' % gr_name
1576 self._compare_error(id_, expected, given=response.body)
1577 self._compare_error(id_, expected, given=response.body)
1577 finally:
1578 finally:
1578 fixture.destroy_user_group(gr_name)
1579 fixture.destroy_user_group(gr_name)
1579
1580
1580 def test_api_delete_user_group(self):
1581 def test_api_delete_user_group(self):
1581 gr_name = 'test_group'
1582 gr_name = 'test_group'
1582 ugroup = fixture.create_user_group(gr_name)
1583 ugroup = fixture.create_user_group(gr_name)
1583 gr_id = ugroup.users_group_id
1584 gr_id = ugroup.users_group_id
1584 try:
1585 try:
1585 id_, params = _build_data(self.apikey, 'delete_user_group',
1586 id_, params = _build_data(self.apikey, 'delete_user_group',
1586 usergroupid=gr_name)
1587 usergroupid=gr_name)
1587 response = api_call(self, params)
1588 response = api_call(self, params)
1588 expected = {
1589 expected = {
1589 'user_group': None,
1590 'user_group': None,
1590 'msg': 'deleted user group ID:%s %s' % (gr_id, gr_name)
1591 'msg': 'deleted user group ID:%s %s' % (gr_id, gr_name)
1591 }
1592 }
1592 self._compare_ok(id_, expected, given=response.body)
1593 self._compare_ok(id_, expected, given=response.body)
1593 finally:
1594 finally:
1594 if UserGroupModel().get_by_name(gr_name):
1595 if UserGroupModel().get_by_name(gr_name):
1595 fixture.destroy_user_group(gr_name)
1596 fixture.destroy_user_group(gr_name)
1596
1597
1597 def test_api_delete_user_group_that_is_assigned(self):
1598 def test_api_delete_user_group_that_is_assigned(self):
1598 gr_name = 'test_group'
1599 gr_name = 'test_group'
1599 ugroup = fixture.create_user_group(gr_name)
1600 ugroup = fixture.create_user_group(gr_name)
1600 gr_id = ugroup.users_group_id
1601 gr_id = ugroup.users_group_id
1601
1602
1602 ugr_to_perm = RepoModel().grant_user_group_permission(self.REPO, gr_name, 'repository.write')
1603 ugr_to_perm = RepoModel().grant_user_group_permission(self.REPO, gr_name, 'repository.write')
1603 msg = 'User Group assigned to %s' % ugr_to_perm.repository.repo_name
1604 msg = 'User Group assigned to %s' % ugr_to_perm.repository.repo_name
1604
1605
1605 try:
1606 try:
1606 id_, params = _build_data(self.apikey, 'delete_user_group',
1607 id_, params = _build_data(self.apikey, 'delete_user_group',
1607 usergroupid=gr_name)
1608 usergroupid=gr_name)
1608 response = api_call(self, params)
1609 response = api_call(self, params)
1609 expected = msg
1610 expected = msg
1610 self._compare_error(id_, expected, given=response.body)
1611 self._compare_error(id_, expected, given=response.body)
1611 finally:
1612 finally:
1612 if UserGroupModel().get_by_name(gr_name):
1613 if UserGroupModel().get_by_name(gr_name):
1613 fixture.destroy_user_group(gr_name)
1614 fixture.destroy_user_group(gr_name)
1614
1615
1615 def test_api_delete_user_group_exception_occurred(self):
1616 def test_api_delete_user_group_exception_occurred(self):
1616 gr_name = 'test_group'
1617 gr_name = 'test_group'
1617 ugroup = fixture.create_user_group(gr_name)
1618 ugroup = fixture.create_user_group(gr_name)
1618 gr_id = ugroup.users_group_id
1619 gr_id = ugroup.users_group_id
1619 id_, params = _build_data(self.apikey, 'delete_user_group',
1620 id_, params = _build_data(self.apikey, 'delete_user_group',
1620 usergroupid=gr_name)
1621 usergroupid=gr_name)
1621
1622
1622 try:
1623 try:
1623 with mock.patch.object(UserGroupModel, 'delete', raise_exception):
1624 with mock.patch.object(UserGroupModel, 'delete', raise_exception):
1624 response = api_call(self, params)
1625 response = api_call(self, params)
1625 expected = 'failed to delete user group ID:%s %s' % (gr_id, gr_name)
1626 expected = 'failed to delete user group ID:%s %s' % (gr_id, gr_name)
1626 self._compare_error(id_, expected, given=response.body)
1627 self._compare_error(id_, expected, given=response.body)
1627 finally:
1628 finally:
1628 fixture.destroy_user_group(gr_name)
1629 fixture.destroy_user_group(gr_name)
1629
1630
1630 @base.parametrize('name,perm', [
1631 @base.parametrize('name,perm', [
1631 ('none', 'repository.none'),
1632 ('none', 'repository.none'),
1632 ('read', 'repository.read'),
1633 ('read', 'repository.read'),
1633 ('write', 'repository.write'),
1634 ('write', 'repository.write'),
1634 ('admin', 'repository.admin'),
1635 ('admin', 'repository.admin'),
1635 ])
1636 ])
1636 def test_api_grant_user_permission(self, name, perm):
1637 def test_api_grant_user_permission(self, name, perm):
1637 id_, params = _build_data(self.apikey,
1638 id_, params = _build_data(self.apikey,
1638 'grant_user_permission',
1639 'grant_user_permission',
1639 repoid=self.REPO,
1640 repoid=self.REPO,
1640 userid=base.TEST_USER_ADMIN_LOGIN,
1641 userid=base.TEST_USER_ADMIN_LOGIN,
1641 perm=perm)
1642 perm=perm)
1642 response = api_call(self, params)
1643 response = api_call(self, params)
1643
1644
1644 ret = {
1645 ret = {
1645 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1646 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1646 perm, base.TEST_USER_ADMIN_LOGIN, self.REPO
1647 perm, base.TEST_USER_ADMIN_LOGIN, self.REPO
1647 ),
1648 ),
1648 'success': True
1649 'success': True
1649 }
1650 }
1650 expected = ret
1651 expected = ret
1651 self._compare_ok(id_, expected, given=response.body)
1652 self._compare_ok(id_, expected, given=response.body)
1652
1653
1653 def test_api_grant_user_permission_wrong_permission(self):
1654 def test_api_grant_user_permission_wrong_permission(self):
1654 perm = 'haha.no.permission'
1655 perm = 'haha.no.permission'
1655 id_, params = _build_data(self.apikey,
1656 id_, params = _build_data(self.apikey,
1656 'grant_user_permission',
1657 'grant_user_permission',
1657 repoid=self.REPO,
1658 repoid=self.REPO,
1658 userid=base.TEST_USER_ADMIN_LOGIN,
1659 userid=base.TEST_USER_ADMIN_LOGIN,
1659 perm=perm)
1660 perm=perm)
1660 response = api_call(self, params)
1661 response = api_call(self, params)
1661
1662
1662 expected = 'permission `%s` does not exist' % perm
1663 expected = 'permission `%s` does not exist' % perm
1663 self._compare_error(id_, expected, given=response.body)
1664 self._compare_error(id_, expected, given=response.body)
1664
1665
1665 @mock.patch.object(RepoModel, 'grant_user_permission', raise_exception)
1666 @mock.patch.object(RepoModel, 'grant_user_permission', raise_exception)
1666 def test_api_grant_user_permission_exception_when_adding(self):
1667 def test_api_grant_user_permission_exception_when_adding(self):
1667 perm = 'repository.read'
1668 perm = 'repository.read'
1668 id_, params = _build_data(self.apikey,
1669 id_, params = _build_data(self.apikey,
1669 'grant_user_permission',
1670 'grant_user_permission',
1670 repoid=self.REPO,
1671 repoid=self.REPO,
1671 userid=base.TEST_USER_ADMIN_LOGIN,
1672 userid=base.TEST_USER_ADMIN_LOGIN,
1672 perm=perm)
1673 perm=perm)
1673 response = api_call(self, params)
1674 response = api_call(self, params)
1674
1675
1675 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1676 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1676 base.TEST_USER_ADMIN_LOGIN, self.REPO
1677 base.TEST_USER_ADMIN_LOGIN, self.REPO
1677 )
1678 )
1678 self._compare_error(id_, expected, given=response.body)
1679 self._compare_error(id_, expected, given=response.body)
1679
1680
1680 def test_api_revoke_user_permission(self):
1681 def test_api_revoke_user_permission(self):
1681 id_, params = _build_data(self.apikey,
1682 id_, params = _build_data(self.apikey,
1682 'revoke_user_permission',
1683 'revoke_user_permission',
1683 repoid=self.REPO,
1684 repoid=self.REPO,
1684 userid=base.TEST_USER_ADMIN_LOGIN, )
1685 userid=base.TEST_USER_ADMIN_LOGIN, )
1685 response = api_call(self, params)
1686 response = api_call(self, params)
1686
1687
1687 expected = {
1688 expected = {
1688 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1689 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1689 base.TEST_USER_ADMIN_LOGIN, self.REPO
1690 base.TEST_USER_ADMIN_LOGIN, self.REPO
1690 ),
1691 ),
1691 'success': True
1692 'success': True
1692 }
1693 }
1693 self._compare_ok(id_, expected, given=response.body)
1694 self._compare_ok(id_, expected, given=response.body)
1694
1695
1695 @mock.patch.object(RepoModel, 'revoke_user_permission', raise_exception)
1696 @mock.patch.object(RepoModel, 'revoke_user_permission', raise_exception)
1696 def test_api_revoke_user_permission_exception_when_adding(self):
1697 def test_api_revoke_user_permission_exception_when_adding(self):
1697 id_, params = _build_data(self.apikey,
1698 id_, params = _build_data(self.apikey,
1698 'revoke_user_permission',
1699 'revoke_user_permission',
1699 repoid=self.REPO,
1700 repoid=self.REPO,
1700 userid=base.TEST_USER_ADMIN_LOGIN, )
1701 userid=base.TEST_USER_ADMIN_LOGIN, )
1701 response = api_call(self, params)
1702 response = api_call(self, params)
1702
1703
1703 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1704 expected = 'failed to edit permission for user: `%s` in repo: `%s`' % (
1704 base.TEST_USER_ADMIN_LOGIN, self.REPO
1705 base.TEST_USER_ADMIN_LOGIN, self.REPO
1705 )
1706 )
1706 self._compare_error(id_, expected, given=response.body)
1707 self._compare_error(id_, expected, given=response.body)
1707
1708
1708 @base.parametrize('name,perm', [
1709 @base.parametrize('name,perm', [
1709 ('none', 'repository.none'),
1710 ('none', 'repository.none'),
1710 ('read', 'repository.read'),
1711 ('read', 'repository.read'),
1711 ('write', 'repository.write'),
1712 ('write', 'repository.write'),
1712 ('admin', 'repository.admin'),
1713 ('admin', 'repository.admin'),
1713 ])
1714 ])
1714 def test_api_grant_user_group_permission(self, name, perm):
1715 def test_api_grant_user_group_permission(self, name, perm):
1715 id_, params = _build_data(self.apikey,
1716 id_, params = _build_data(self.apikey,
1716 'grant_user_group_permission',
1717 'grant_user_group_permission',
1717 repoid=self.REPO,
1718 repoid=self.REPO,
1718 usergroupid=TEST_USER_GROUP,
1719 usergroupid=TEST_USER_GROUP,
1719 perm=perm)
1720 perm=perm)
1720 response = api_call(self, params)
1721 response = api_call(self, params)
1721
1722
1722 ret = {
1723 ret = {
1723 'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % (
1724 'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % (
1724 perm, TEST_USER_GROUP, self.REPO
1725 perm, TEST_USER_GROUP, self.REPO
1725 ),
1726 ),
1726 'success': True
1727 'success': True
1727 }
1728 }
1728 expected = ret
1729 expected = ret
1729 self._compare_ok(id_, expected, given=response.body)
1730 self._compare_ok(id_, expected, given=response.body)
1730
1731
1731 def test_api_grant_user_group_permission_wrong_permission(self):
1732 def test_api_grant_user_group_permission_wrong_permission(self):
1732 perm = 'haha.no.permission'
1733 perm = 'haha.no.permission'
1733 id_, params = _build_data(self.apikey,
1734 id_, params = _build_data(self.apikey,
1734 'grant_user_group_permission',
1735 'grant_user_group_permission',
1735 repoid=self.REPO,
1736 repoid=self.REPO,
1736 usergroupid=TEST_USER_GROUP,
1737 usergroupid=TEST_USER_GROUP,
1737 perm=perm)
1738 perm=perm)
1738 response = api_call(self, params)
1739 response = api_call(self, params)
1739
1740
1740 expected = 'permission `%s` does not exist' % perm
1741 expected = 'permission `%s` does not exist' % perm
1741 self._compare_error(id_, expected, given=response.body)
1742 self._compare_error(id_, expected, given=response.body)
1742
1743
1743 @mock.patch.object(RepoModel, 'grant_user_group_permission', raise_exception)
1744 @mock.patch.object(RepoModel, 'grant_user_group_permission', raise_exception)
1744 def test_api_grant_user_group_permission_exception_when_adding(self):
1745 def test_api_grant_user_group_permission_exception_when_adding(self):
1745 perm = 'repository.read'
1746 perm = 'repository.read'
1746 id_, params = _build_data(self.apikey,
1747 id_, params = _build_data(self.apikey,
1747 'grant_user_group_permission',
1748 'grant_user_group_permission',
1748 repoid=self.REPO,
1749 repoid=self.REPO,
1749 usergroupid=TEST_USER_GROUP,
1750 usergroupid=TEST_USER_GROUP,
1750 perm=perm)
1751 perm=perm)
1751 response = api_call(self, params)
1752 response = api_call(self, params)
1752
1753
1753 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1754 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1754 TEST_USER_GROUP, self.REPO
1755 TEST_USER_GROUP, self.REPO
1755 )
1756 )
1756 self._compare_error(id_, expected, given=response.body)
1757 self._compare_error(id_, expected, given=response.body)
1757
1758
1758 def test_api_revoke_user_group_permission(self):
1759 def test_api_revoke_user_group_permission(self):
1759 RepoModel().grant_user_group_permission(repo=self.REPO,
1760 RepoModel().grant_user_group_permission(repo=self.REPO,
1760 group_name=TEST_USER_GROUP,
1761 group_name=TEST_USER_GROUP,
1761 perm='repository.read')
1762 perm='repository.read')
1762 meta.Session().commit()
1763 meta.Session().commit()
1763 id_, params = _build_data(self.apikey,
1764 id_, params = _build_data(self.apikey,
1764 'revoke_user_group_permission',
1765 'revoke_user_group_permission',
1765 repoid=self.REPO,
1766 repoid=self.REPO,
1766 usergroupid=TEST_USER_GROUP, )
1767 usergroupid=TEST_USER_GROUP, )
1767 response = api_call(self, params)
1768 response = api_call(self, params)
1768
1769
1769 expected = {
1770 expected = {
1770 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1771 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1771 TEST_USER_GROUP, self.REPO
1772 TEST_USER_GROUP, self.REPO
1772 ),
1773 ),
1773 'success': True
1774 'success': True
1774 }
1775 }
1775 self._compare_ok(id_, expected, given=response.body)
1776 self._compare_ok(id_, expected, given=response.body)
1776
1777
1777 @mock.patch.object(RepoModel, 'revoke_user_group_permission', raise_exception)
1778 @mock.patch.object(RepoModel, 'revoke_user_group_permission', raise_exception)
1778 def test_api_revoke_user_group_permission_exception_when_adding(self):
1779 def test_api_revoke_user_group_permission_exception_when_adding(self):
1779 id_, params = _build_data(self.apikey,
1780 id_, params = _build_data(self.apikey,
1780 'revoke_user_group_permission',
1781 'revoke_user_group_permission',
1781 repoid=self.REPO,
1782 repoid=self.REPO,
1782 usergroupid=TEST_USER_GROUP, )
1783 usergroupid=TEST_USER_GROUP, )
1783 response = api_call(self, params)
1784 response = api_call(self, params)
1784
1785
1785 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1786 expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % (
1786 TEST_USER_GROUP, self.REPO
1787 TEST_USER_GROUP, self.REPO
1787 )
1788 )
1788 self._compare_error(id_, expected, given=response.body)
1789 self._compare_error(id_, expected, given=response.body)
1789
1790
1790 @base.parametrize('name,perm,apply_to_children', [
1791 @base.parametrize('name,perm,apply_to_children', [
1791 ('none', 'group.none', 'none'),
1792 ('none', 'group.none', 'none'),
1792 ('read', 'group.read', 'none'),
1793 ('read', 'group.read', 'none'),
1793 ('write', 'group.write', 'none'),
1794 ('write', 'group.write', 'none'),
1794 ('admin', 'group.admin', 'none'),
1795 ('admin', 'group.admin', 'none'),
1795
1796
1796 ('none', 'group.none', 'all'),
1797 ('none', 'group.none', 'all'),
1797 ('read', 'group.read', 'all'),
1798 ('read', 'group.read', 'all'),
1798 ('write', 'group.write', 'all'),
1799 ('write', 'group.write', 'all'),
1799 ('admin', 'group.admin', 'all'),
1800 ('admin', 'group.admin', 'all'),
1800
1801
1801 ('none', 'group.none', 'repos'),
1802 ('none', 'group.none', 'repos'),
1802 ('read', 'group.read', 'repos'),
1803 ('read', 'group.read', 'repos'),
1803 ('write', 'group.write', 'repos'),
1804 ('write', 'group.write', 'repos'),
1804 ('admin', 'group.admin', 'repos'),
1805 ('admin', 'group.admin', 'repos'),
1805
1806
1806 ('none', 'group.none', 'groups'),
1807 ('none', 'group.none', 'groups'),
1807 ('read', 'group.read', 'groups'),
1808 ('read', 'group.read', 'groups'),
1808 ('write', 'group.write', 'groups'),
1809 ('write', 'group.write', 'groups'),
1809 ('admin', 'group.admin', 'groups'),
1810 ('admin', 'group.admin', 'groups'),
1810 ])
1811 ])
1811 def test_api_grant_user_permission_to_repo_group(self, name, perm, apply_to_children):
1812 def test_api_grant_user_permission_to_repo_group(self, name, perm, apply_to_children):
1812 id_, params = _build_data(self.apikey,
1813 id_, params = _build_data(self.apikey,
1813 'grant_user_permission_to_repo_group',
1814 'grant_user_permission_to_repo_group',
1814 repogroupid=TEST_REPO_GROUP,
1815 repogroupid=TEST_REPO_GROUP,
1815 userid=base.TEST_USER_ADMIN_LOGIN,
1816 userid=base.TEST_USER_ADMIN_LOGIN,
1816 perm=perm, apply_to_children=apply_to_children)
1817 perm=perm, apply_to_children=apply_to_children)
1817 response = api_call(self, params)
1818 response = api_call(self, params)
1818
1819
1819 ret = {
1820 ret = {
1820 'msg': 'Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
1821 'msg': 'Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
1821 perm, apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1822 perm, apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1822 ),
1823 ),
1823 'success': True
1824 'success': True
1824 }
1825 }
1825 expected = ret
1826 expected = ret
1826 self._compare_ok(id_, expected, given=response.body)
1827 self._compare_ok(id_, expected, given=response.body)
1827
1828
1828 @base.parametrize('name,perm,apply_to_children,grant_admin,access_ok', [
1829 @base.parametrize('name,perm,apply_to_children,grant_admin,access_ok', [
1829 ('none_fails', 'group.none', 'none', False, False),
1830 ('none_fails', 'group.none', 'none', False, False),
1830 ('read_fails', 'group.read', 'none', False, False),
1831 ('read_fails', 'group.read', 'none', False, False),
1831 ('write_fails', 'group.write', 'none', False, False),
1832 ('write_fails', 'group.write', 'none', False, False),
1832 ('admin_fails', 'group.admin', 'none', False, False),
1833 ('admin_fails', 'group.admin', 'none', False, False),
1833
1834
1834 # with granted perms
1835 # with granted perms
1835 ('none_ok', 'group.none', 'none', True, True),
1836 ('none_ok', 'group.none', 'none', True, True),
1836 ('read_ok', 'group.read', 'none', True, True),
1837 ('read_ok', 'group.read', 'none', True, True),
1837 ('write_ok', 'group.write', 'none', True, True),
1838 ('write_ok', 'group.write', 'none', True, True),
1838 ('admin_ok', 'group.admin', 'none', True, True),
1839 ('admin_ok', 'group.admin', 'none', True, True),
1839 ])
1840 ])
1840 def test_api_grant_user_permission_to_repo_group_by_regular_user(
1841 def test_api_grant_user_permission_to_repo_group_by_regular_user(
1841 self, name, perm, apply_to_children, grant_admin, access_ok):
1842 self, name, perm, apply_to_children, grant_admin, access_ok):
1842 if grant_admin:
1843 if grant_admin:
1843 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
1844 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
1844 self.TEST_USER_LOGIN,
1845 self.TEST_USER_LOGIN,
1845 'group.admin')
1846 'group.admin')
1846 meta.Session().commit()
1847 meta.Session().commit()
1847
1848
1848 id_, params = _build_data(self.apikey_regular,
1849 id_, params = _build_data(self.apikey_regular,
1849 'grant_user_permission_to_repo_group',
1850 'grant_user_permission_to_repo_group',
1850 repogroupid=TEST_REPO_GROUP,
1851 repogroupid=TEST_REPO_GROUP,
1851 userid=base.TEST_USER_ADMIN_LOGIN,
1852 userid=base.TEST_USER_ADMIN_LOGIN,
1852 perm=perm, apply_to_children=apply_to_children)
1853 perm=perm, apply_to_children=apply_to_children)
1853 response = api_call(self, params)
1854 response = api_call(self, params)
1854 if access_ok:
1855 if access_ok:
1855 ret = {
1856 ret = {
1856 'msg': 'Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
1857 'msg': 'Granted perm: `%s` (recursive:%s) for user: `%s` in repo group: `%s`' % (
1857 perm, apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1858 perm, apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1858 ),
1859 ),
1859 'success': True
1860 'success': True
1860 }
1861 }
1861 expected = ret
1862 expected = ret
1862 self._compare_ok(id_, expected, given=response.body)
1863 self._compare_ok(id_, expected, given=response.body)
1863 else:
1864 else:
1864 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
1865 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
1865 self._compare_error(id_, expected, given=response.body)
1866 self._compare_error(id_, expected, given=response.body)
1866
1867
1867 def test_api_grant_user_permission_to_repo_group_wrong_permission(self):
1868 def test_api_grant_user_permission_to_repo_group_wrong_permission(self):
1868 perm = 'haha.no.permission'
1869 perm = 'haha.no.permission'
1869 id_, params = _build_data(self.apikey,
1870 id_, params = _build_data(self.apikey,
1870 'grant_user_permission_to_repo_group',
1871 'grant_user_permission_to_repo_group',
1871 repogroupid=TEST_REPO_GROUP,
1872 repogroupid=TEST_REPO_GROUP,
1872 userid=base.TEST_USER_ADMIN_LOGIN,
1873 userid=base.TEST_USER_ADMIN_LOGIN,
1873 perm=perm)
1874 perm=perm)
1874 response = api_call(self, params)
1875 response = api_call(self, params)
1875
1876
1876 expected = 'permission `%s` does not exist' % perm
1877 expected = 'permission `%s` does not exist' % perm
1877 self._compare_error(id_, expected, given=response.body)
1878 self._compare_error(id_, expected, given=response.body)
1878
1879
1879 @mock.patch.object(RepoGroupModel, 'grant_user_permission', raise_exception)
1880 @mock.patch.object(RepoGroupModel, 'grant_user_permission', raise_exception)
1880 def test_api_grant_user_permission_to_repo_group_exception_when_adding(self):
1881 def test_api_grant_user_permission_to_repo_group_exception_when_adding(self):
1881 perm = 'group.read'
1882 perm = 'group.read'
1882 id_, params = _build_data(self.apikey,
1883 id_, params = _build_data(self.apikey,
1883 'grant_user_permission_to_repo_group',
1884 'grant_user_permission_to_repo_group',
1884 repogroupid=TEST_REPO_GROUP,
1885 repogroupid=TEST_REPO_GROUP,
1885 userid=base.TEST_USER_ADMIN_LOGIN,
1886 userid=base.TEST_USER_ADMIN_LOGIN,
1886 perm=perm)
1887 perm=perm)
1887 response = api_call(self, params)
1888 response = api_call(self, params)
1888
1889
1889 expected = 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1890 expected = 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1890 base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1891 base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1891 )
1892 )
1892 self._compare_error(id_, expected, given=response.body)
1893 self._compare_error(id_, expected, given=response.body)
1893
1894
1894 @base.parametrize('name,apply_to_children', [
1895 @base.parametrize('name,apply_to_children', [
1895 ('none', 'none'),
1896 ('none', 'none'),
1896 ('all', 'all'),
1897 ('all', 'all'),
1897 ('repos', 'repos'),
1898 ('repos', 'repos'),
1898 ('groups', 'groups'),
1899 ('groups', 'groups'),
1899 ])
1900 ])
1900 def test_api_revoke_user_permission_from_repo_group(self, name, apply_to_children):
1901 def test_api_revoke_user_permission_from_repo_group(self, name, apply_to_children):
1901 RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
1902 RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
1902 user=base.TEST_USER_ADMIN_LOGIN,
1903 user=base.TEST_USER_ADMIN_LOGIN,
1903 perm='group.read',)
1904 perm='group.read',)
1904 meta.Session().commit()
1905 meta.Session().commit()
1905
1906
1906 id_, params = _build_data(self.apikey,
1907 id_, params = _build_data(self.apikey,
1907 'revoke_user_permission_from_repo_group',
1908 'revoke_user_permission_from_repo_group',
1908 repogroupid=TEST_REPO_GROUP,
1909 repogroupid=TEST_REPO_GROUP,
1909 userid=base.TEST_USER_ADMIN_LOGIN,
1910 userid=base.TEST_USER_ADMIN_LOGIN,
1910 apply_to_children=apply_to_children,)
1911 apply_to_children=apply_to_children,)
1911 response = api_call(self, params)
1912 response = api_call(self, params)
1912
1913
1913 expected = {
1914 expected = {
1914 'msg': 'Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
1915 'msg': 'Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
1915 apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1916 apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1916 ),
1917 ),
1917 'success': True
1918 'success': True
1918 }
1919 }
1919 self._compare_ok(id_, expected, given=response.body)
1920 self._compare_ok(id_, expected, given=response.body)
1920
1921
1921 @base.parametrize('name,apply_to_children,grant_admin,access_ok', [
1922 @base.parametrize('name,apply_to_children,grant_admin,access_ok', [
1922 ('none', 'none', False, False),
1923 ('none', 'none', False, False),
1923 ('all', 'all', False, False),
1924 ('all', 'all', False, False),
1924 ('repos', 'repos', False, False),
1925 ('repos', 'repos', False, False),
1925 ('groups', 'groups', False, False),
1926 ('groups', 'groups', False, False),
1926
1927
1927 # after granting admin rights
1928 # after granting admin rights
1928 ('none', 'none', False, False),
1929 ('none', 'none', False, False),
1929 ('all', 'all', False, False),
1930 ('all', 'all', False, False),
1930 ('repos', 'repos', False, False),
1931 ('repos', 'repos', False, False),
1931 ('groups', 'groups', False, False),
1932 ('groups', 'groups', False, False),
1932 ])
1933 ])
1933 def test_api_revoke_user_permission_from_repo_group_by_regular_user(
1934 def test_api_revoke_user_permission_from_repo_group_by_regular_user(
1934 self, name, apply_to_children, grant_admin, access_ok):
1935 self, name, apply_to_children, grant_admin, access_ok):
1935 RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
1936 RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
1936 user=base.TEST_USER_ADMIN_LOGIN,
1937 user=base.TEST_USER_ADMIN_LOGIN,
1937 perm='group.read',)
1938 perm='group.read',)
1938 meta.Session().commit()
1939 meta.Session().commit()
1939
1940
1940 if grant_admin:
1941 if grant_admin:
1941 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
1942 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
1942 self.TEST_USER_LOGIN,
1943 self.TEST_USER_LOGIN,
1943 'group.admin')
1944 'group.admin')
1944 meta.Session().commit()
1945 meta.Session().commit()
1945
1946
1946 id_, params = _build_data(self.apikey_regular,
1947 id_, params = _build_data(self.apikey_regular,
1947 'revoke_user_permission_from_repo_group',
1948 'revoke_user_permission_from_repo_group',
1948 repogroupid=TEST_REPO_GROUP,
1949 repogroupid=TEST_REPO_GROUP,
1949 userid=base.TEST_USER_ADMIN_LOGIN,
1950 userid=base.TEST_USER_ADMIN_LOGIN,
1950 apply_to_children=apply_to_children,)
1951 apply_to_children=apply_to_children,)
1951 response = api_call(self, params)
1952 response = api_call(self, params)
1952 if access_ok:
1953 if access_ok:
1953 expected = {
1954 expected = {
1954 'msg': 'Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
1955 'msg': 'Revoked perm (recursive:%s) for user: `%s` in repo group: `%s`' % (
1955 apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1956 apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1956 ),
1957 ),
1957 'success': True
1958 'success': True
1958 }
1959 }
1959 self._compare_ok(id_, expected, given=response.body)
1960 self._compare_ok(id_, expected, given=response.body)
1960 else:
1961 else:
1961 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
1962 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
1962 self._compare_error(id_, expected, given=response.body)
1963 self._compare_error(id_, expected, given=response.body)
1963
1964
1964 @mock.patch.object(RepoGroupModel, 'revoke_user_permission', raise_exception)
1965 @mock.patch.object(RepoGroupModel, 'revoke_user_permission', raise_exception)
1965 def test_api_revoke_user_permission_from_repo_group_exception_when_adding(self):
1966 def test_api_revoke_user_permission_from_repo_group_exception_when_adding(self):
1966 id_, params = _build_data(self.apikey,
1967 id_, params = _build_data(self.apikey,
1967 'revoke_user_permission_from_repo_group',
1968 'revoke_user_permission_from_repo_group',
1968 repogroupid=TEST_REPO_GROUP,
1969 repogroupid=TEST_REPO_GROUP,
1969 userid=base.TEST_USER_ADMIN_LOGIN, )
1970 userid=base.TEST_USER_ADMIN_LOGIN, )
1970 response = api_call(self, params)
1971 response = api_call(self, params)
1971
1972
1972 expected = 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1973 expected = 'failed to edit permission for user: `%s` in repo group: `%s`' % (
1973 base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1974 base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
1974 )
1975 )
1975 self._compare_error(id_, expected, given=response.body)
1976 self._compare_error(id_, expected, given=response.body)
1976
1977
1977 @base.parametrize('name,perm,apply_to_children', [
1978 @base.parametrize('name,perm,apply_to_children', [
1978 ('none', 'group.none', 'none'),
1979 ('none', 'group.none', 'none'),
1979 ('read', 'group.read', 'none'),
1980 ('read', 'group.read', 'none'),
1980 ('write', 'group.write', 'none'),
1981 ('write', 'group.write', 'none'),
1981 ('admin', 'group.admin', 'none'),
1982 ('admin', 'group.admin', 'none'),
1982
1983
1983 ('none', 'group.none', 'all'),
1984 ('none', 'group.none', 'all'),
1984 ('read', 'group.read', 'all'),
1985 ('read', 'group.read', 'all'),
1985 ('write', 'group.write', 'all'),
1986 ('write', 'group.write', 'all'),
1986 ('admin', 'group.admin', 'all'),
1987 ('admin', 'group.admin', 'all'),
1987
1988
1988 ('none', 'group.none', 'repos'),
1989 ('none', 'group.none', 'repos'),
1989 ('read', 'group.read', 'repos'),
1990 ('read', 'group.read', 'repos'),
1990 ('write', 'group.write', 'repos'),
1991 ('write', 'group.write', 'repos'),
1991 ('admin', 'group.admin', 'repos'),
1992 ('admin', 'group.admin', 'repos'),
1992
1993
1993 ('none', 'group.none', 'groups'),
1994 ('none', 'group.none', 'groups'),
1994 ('read', 'group.read', 'groups'),
1995 ('read', 'group.read', 'groups'),
1995 ('write', 'group.write', 'groups'),
1996 ('write', 'group.write', 'groups'),
1996 ('admin', 'group.admin', 'groups'),
1997 ('admin', 'group.admin', 'groups'),
1997 ])
1998 ])
1998 def test_api_grant_user_group_permission_to_repo_group(self, name, perm, apply_to_children):
1999 def test_api_grant_user_group_permission_to_repo_group(self, name, perm, apply_to_children):
1999 id_, params = _build_data(self.apikey,
2000 id_, params = _build_data(self.apikey,
2000 'grant_user_group_permission_to_repo_group',
2001 'grant_user_group_permission_to_repo_group',
2001 repogroupid=TEST_REPO_GROUP,
2002 repogroupid=TEST_REPO_GROUP,
2002 usergroupid=TEST_USER_GROUP,
2003 usergroupid=TEST_USER_GROUP,
2003 perm=perm,
2004 perm=perm,
2004 apply_to_children=apply_to_children,)
2005 apply_to_children=apply_to_children,)
2005 response = api_call(self, params)
2006 response = api_call(self, params)
2006
2007
2007 ret = {
2008 ret = {
2008 'msg': 'Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2009 'msg': 'Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2009 perm, apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
2010 perm, apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
2010 ),
2011 ),
2011 'success': True
2012 'success': True
2012 }
2013 }
2013 expected = ret
2014 expected = ret
2014 self._compare_ok(id_, expected, given=response.body)
2015 self._compare_ok(id_, expected, given=response.body)
2015
2016
2016 @base.parametrize('name,perm,apply_to_children,grant_admin,access_ok', [
2017 @base.parametrize('name,perm,apply_to_children,grant_admin,access_ok', [
2017 ('none_fails', 'group.none', 'none', False, False),
2018 ('none_fails', 'group.none', 'none', False, False),
2018 ('read_fails', 'group.read', 'none', False, False),
2019 ('read_fails', 'group.read', 'none', False, False),
2019 ('write_fails', 'group.write', 'none', False, False),
2020 ('write_fails', 'group.write', 'none', False, False),
2020 ('admin_fails', 'group.admin', 'none', False, False),
2021 ('admin_fails', 'group.admin', 'none', False, False),
2021
2022
2022 # with granted perms
2023 # with granted perms
2023 ('none_ok', 'group.none', 'none', True, True),
2024 ('none_ok', 'group.none', 'none', True, True),
2024 ('read_ok', 'group.read', 'none', True, True),
2025 ('read_ok', 'group.read', 'none', True, True),
2025 ('write_ok', 'group.write', 'none', True, True),
2026 ('write_ok', 'group.write', 'none', True, True),
2026 ('admin_ok', 'group.admin', 'none', True, True),
2027 ('admin_ok', 'group.admin', 'none', True, True),
2027 ])
2028 ])
2028 def test_api_grant_user_group_permission_to_repo_group_by_regular_user(
2029 def test_api_grant_user_group_permission_to_repo_group_by_regular_user(
2029 self, name, perm, apply_to_children, grant_admin, access_ok):
2030 self, name, perm, apply_to_children, grant_admin, access_ok):
2030 if grant_admin:
2031 if grant_admin:
2031 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
2032 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
2032 self.TEST_USER_LOGIN,
2033 self.TEST_USER_LOGIN,
2033 'group.admin')
2034 'group.admin')
2034 meta.Session().commit()
2035 meta.Session().commit()
2035
2036
2036 id_, params = _build_data(self.apikey_regular,
2037 id_, params = _build_data(self.apikey_regular,
2037 'grant_user_group_permission_to_repo_group',
2038 'grant_user_group_permission_to_repo_group',
2038 repogroupid=TEST_REPO_GROUP,
2039 repogroupid=TEST_REPO_GROUP,
2039 usergroupid=TEST_USER_GROUP,
2040 usergroupid=TEST_USER_GROUP,
2040 perm=perm,
2041 perm=perm,
2041 apply_to_children=apply_to_children,)
2042 apply_to_children=apply_to_children,)
2042 response = api_call(self, params)
2043 response = api_call(self, params)
2043 if access_ok:
2044 if access_ok:
2044 ret = {
2045 ret = {
2045 'msg': 'Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2046 'msg': 'Granted perm: `%s` (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2046 perm, apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
2047 perm, apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
2047 ),
2048 ),
2048 'success': True
2049 'success': True
2049 }
2050 }
2050 expected = ret
2051 expected = ret
2051 self._compare_ok(id_, expected, given=response.body)
2052 self._compare_ok(id_, expected, given=response.body)
2052 else:
2053 else:
2053 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
2054 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
2054 self._compare_error(id_, expected, given=response.body)
2055 self._compare_error(id_, expected, given=response.body)
2055
2056
2056 def test_api_grant_user_group_permission_to_repo_group_wrong_permission(self):
2057 def test_api_grant_user_group_permission_to_repo_group_wrong_permission(self):
2057 perm = 'haha.no.permission'
2058 perm = 'haha.no.permission'
2058 id_, params = _build_data(self.apikey,
2059 id_, params = _build_data(self.apikey,
2059 'grant_user_group_permission_to_repo_group',
2060 'grant_user_group_permission_to_repo_group',
2060 repogroupid=TEST_REPO_GROUP,
2061 repogroupid=TEST_REPO_GROUP,
2061 usergroupid=TEST_USER_GROUP,
2062 usergroupid=TEST_USER_GROUP,
2062 perm=perm)
2063 perm=perm)
2063 response = api_call(self, params)
2064 response = api_call(self, params)
2064
2065
2065 expected = 'permission `%s` does not exist' % perm
2066 expected = 'permission `%s` does not exist' % perm
2066 self._compare_error(id_, expected, given=response.body)
2067 self._compare_error(id_, expected, given=response.body)
2067
2068
2068 @mock.patch.object(RepoGroupModel, 'grant_user_group_permission', raise_exception)
2069 @mock.patch.object(RepoGroupModel, 'grant_user_group_permission', raise_exception)
2069 def test_api_grant_user_group_permission_exception_when_adding_to_repo_group(self):
2070 def test_api_grant_user_group_permission_exception_when_adding_to_repo_group(self):
2070 perm = 'group.read'
2071 perm = 'group.read'
2071 id_, params = _build_data(self.apikey,
2072 id_, params = _build_data(self.apikey,
2072 'grant_user_group_permission_to_repo_group',
2073 'grant_user_group_permission_to_repo_group',
2073 repogroupid=TEST_REPO_GROUP,
2074 repogroupid=TEST_REPO_GROUP,
2074 usergroupid=TEST_USER_GROUP,
2075 usergroupid=TEST_USER_GROUP,
2075 perm=perm)
2076 perm=perm)
2076 response = api_call(self, params)
2077 response = api_call(self, params)
2077
2078
2078 expected = 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
2079 expected = 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
2079 TEST_USER_GROUP, TEST_REPO_GROUP
2080 TEST_USER_GROUP, TEST_REPO_GROUP
2080 )
2081 )
2081 self._compare_error(id_, expected, given=response.body)
2082 self._compare_error(id_, expected, given=response.body)
2082
2083
2083 @base.parametrize('name,apply_to_children', [
2084 @base.parametrize('name,apply_to_children', [
2084 ('none', 'none'),
2085 ('none', 'none'),
2085 ('all', 'all'),
2086 ('all', 'all'),
2086 ('repos', 'repos'),
2087 ('repos', 'repos'),
2087 ('groups', 'groups'),
2088 ('groups', 'groups'),
2088 ])
2089 ])
2089 def test_api_revoke_user_group_permission_from_repo_group(self, name, apply_to_children):
2090 def test_api_revoke_user_group_permission_from_repo_group(self, name, apply_to_children):
2090 RepoGroupModel().grant_user_group_permission(repo_group=TEST_REPO_GROUP,
2091 RepoGroupModel().grant_user_group_permission(repo_group=TEST_REPO_GROUP,
2091 group_name=TEST_USER_GROUP,
2092 group_name=TEST_USER_GROUP,
2092 perm='group.read',)
2093 perm='group.read',)
2093 meta.Session().commit()
2094 meta.Session().commit()
2094 id_, params = _build_data(self.apikey,
2095 id_, params = _build_data(self.apikey,
2095 'revoke_user_group_permission_from_repo_group',
2096 'revoke_user_group_permission_from_repo_group',
2096 repogroupid=TEST_REPO_GROUP,
2097 repogroupid=TEST_REPO_GROUP,
2097 usergroupid=TEST_USER_GROUP,
2098 usergroupid=TEST_USER_GROUP,
2098 apply_to_children=apply_to_children,)
2099 apply_to_children=apply_to_children,)
2099 response = api_call(self, params)
2100 response = api_call(self, params)
2100
2101
2101 expected = {
2102 expected = {
2102 'msg': 'Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2103 'msg': 'Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2103 apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
2104 apply_to_children, TEST_USER_GROUP, TEST_REPO_GROUP
2104 ),
2105 ),
2105 'success': True
2106 'success': True
2106 }
2107 }
2107 self._compare_ok(id_, expected, given=response.body)
2108 self._compare_ok(id_, expected, given=response.body)
2108
2109
2109 @base.parametrize('name,apply_to_children,grant_admin,access_ok', [
2110 @base.parametrize('name,apply_to_children,grant_admin,access_ok', [
2110 ('none', 'none', False, False),
2111 ('none', 'none', False, False),
2111 ('all', 'all', False, False),
2112 ('all', 'all', False, False),
2112 ('repos', 'repos', False, False),
2113 ('repos', 'repos', False, False),
2113 ('groups', 'groups', False, False),
2114 ('groups', 'groups', False, False),
2114
2115
2115 # after granting admin rights
2116 # after granting admin rights
2116 ('none', 'none', False, False),
2117 ('none', 'none', False, False),
2117 ('all', 'all', False, False),
2118 ('all', 'all', False, False),
2118 ('repos', 'repos', False, False),
2119 ('repos', 'repos', False, False),
2119 ('groups', 'groups', False, False),
2120 ('groups', 'groups', False, False),
2120 ])
2121 ])
2121 def test_api_revoke_user_group_permission_from_repo_group_by_regular_user(
2122 def test_api_revoke_user_group_permission_from_repo_group_by_regular_user(
2122 self, name, apply_to_children, grant_admin, access_ok):
2123 self, name, apply_to_children, grant_admin, access_ok):
2123 RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
2124 RepoGroupModel().grant_user_permission(repo_group=TEST_REPO_GROUP,
2124 user=base.TEST_USER_ADMIN_LOGIN,
2125 user=base.TEST_USER_ADMIN_LOGIN,
2125 perm='group.read',)
2126 perm='group.read',)
2126 meta.Session().commit()
2127 meta.Session().commit()
2127
2128
2128 if grant_admin:
2129 if grant_admin:
2129 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
2130 RepoGroupModel().grant_user_permission(TEST_REPO_GROUP,
2130 self.TEST_USER_LOGIN,
2131 self.TEST_USER_LOGIN,
2131 'group.admin')
2132 'group.admin')
2132 meta.Session().commit()
2133 meta.Session().commit()
2133
2134
2134 id_, params = _build_data(self.apikey_regular,
2135 id_, params = _build_data(self.apikey_regular,
2135 'revoke_user_group_permission_from_repo_group',
2136 'revoke_user_group_permission_from_repo_group',
2136 repogroupid=TEST_REPO_GROUP,
2137 repogroupid=TEST_REPO_GROUP,
2137 usergroupid=TEST_USER_GROUP,
2138 usergroupid=TEST_USER_GROUP,
2138 apply_to_children=apply_to_children,)
2139 apply_to_children=apply_to_children,)
2139 response = api_call(self, params)
2140 response = api_call(self, params)
2140 if access_ok:
2141 if access_ok:
2141 expected = {
2142 expected = {
2142 'msg': 'Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2143 'msg': 'Revoked perm (recursive:%s) for user group: `%s` in repo group: `%s`' % (
2143 apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
2144 apply_to_children, base.TEST_USER_ADMIN_LOGIN, TEST_REPO_GROUP
2144 ),
2145 ),
2145 'success': True
2146 'success': True
2146 }
2147 }
2147 self._compare_ok(id_, expected, given=response.body)
2148 self._compare_ok(id_, expected, given=response.body)
2148 else:
2149 else:
2149 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
2150 expected = 'repository group `%s` does not exist' % TEST_REPO_GROUP
2150 self._compare_error(id_, expected, given=response.body)
2151 self._compare_error(id_, expected, given=response.body)
2151
2152
2152 @mock.patch.object(RepoGroupModel, 'revoke_user_group_permission', raise_exception)
2153 @mock.patch.object(RepoGroupModel, 'revoke_user_group_permission', raise_exception)
2153 def test_api_revoke_user_group_permission_from_repo_group_exception_when_adding(self):
2154 def test_api_revoke_user_group_permission_from_repo_group_exception_when_adding(self):
2154 id_, params = _build_data(self.apikey, 'revoke_user_group_permission_from_repo_group',
2155 id_, params = _build_data(self.apikey, 'revoke_user_group_permission_from_repo_group',
2155 repogroupid=TEST_REPO_GROUP,
2156 repogroupid=TEST_REPO_GROUP,
2156 usergroupid=TEST_USER_GROUP,)
2157 usergroupid=TEST_USER_GROUP,)
2157 response = api_call(self, params)
2158 response = api_call(self, params)
2158
2159
2159 expected = 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
2160 expected = 'failed to edit permission for user group: `%s` in repo group: `%s`' % (
2160 TEST_USER_GROUP, TEST_REPO_GROUP
2161 TEST_USER_GROUP, TEST_REPO_GROUP
2161 )
2162 )
2162 self._compare_error(id_, expected, given=response.body)
2163 self._compare_error(id_, expected, given=response.body)
2163
2164
2164 def test_api_get_gist(self):
2165 def test_api_get_gist(self):
2165 gist = fixture.create_gist()
2166 gist = fixture.create_gist()
2166 gist_id = gist.gist_access_id
2167 gist_id = gist.gist_access_id
2167 gist_created_on = gist.created_on
2168 gist_created_on = gist.created_on
2168 id_, params = _build_data(self.apikey, 'get_gist',
2169 id_, params = _build_data(self.apikey, 'get_gist',
2169 gistid=gist_id, )
2170 gistid=gist_id, )
2170 response = api_call(self, params)
2171 response = api_call(self, params)
2171
2172
2172 expected = {
2173 expected = {
2173 'access_id': gist_id,
2174 'access_id': gist_id,
2174 'created_on': gist_created_on,
2175 'created_on': gist_created_on,
2175 'description': 'new-gist',
2176 'description': 'new-gist',
2176 'expires': -1.0,
2177 'expires': -1.0,
2177 'gist_id': int(gist_id),
2178 'gist_id': int(gist_id),
2178 'type': 'public',
2179 'type': 'public',
2179 'url': 'http://localhost:80/_admin/gists/%s' % gist_id
2180 'url': 'http://localhost:80/_admin/gists/%s' % gist_id
2180 }
2181 }
2181
2182
2182 self._compare_ok(id_, expected, given=response.body)
2183 self._compare_ok(id_, expected, given=response.body)
2183
2184
2184 def test_api_get_gist_that_does_not_exist(self):
2185 def test_api_get_gist_that_does_not_exist(self):
2185 id_, params = _build_data(self.apikey_regular, 'get_gist',
2186 id_, params = _build_data(self.apikey_regular, 'get_gist',
2186 gistid='12345', )
2187 gistid='12345', )
2187 response = api_call(self, params)
2188 response = api_call(self, params)
2188 expected = 'gist `%s` does not exist' % ('12345',)
2189 expected = 'gist `%s` does not exist' % ('12345',)
2189 self._compare_error(id_, expected, given=response.body)
2190 self._compare_error(id_, expected, given=response.body)
2190
2191
2191 def test_api_get_gist_private_gist_without_permission(self):
2192 def test_api_get_gist_private_gist_without_permission(self):
2192 gist = fixture.create_gist()
2193 gist = fixture.create_gist()
2193 gist_id = gist.gist_access_id
2194 gist_id = gist.gist_access_id
2194 gist_created_on = gist.created_on
2195 gist_created_on = gist.created_on
2195 id_, params = _build_data(self.apikey_regular, 'get_gist',
2196 id_, params = _build_data(self.apikey_regular, 'get_gist',
2196 gistid=gist_id, )
2197 gistid=gist_id, )
2197 response = api_call(self, params)
2198 response = api_call(self, params)
2198
2199
2199 expected = 'gist `%s` does not exist' % gist_id
2200 expected = 'gist `%s` does not exist' % gist_id
2200 self._compare_error(id_, expected, given=response.body)
2201 self._compare_error(id_, expected, given=response.body)
2201
2202
2202 def test_api_get_gists(self):
2203 def test_api_get_gists(self):
2203 fixture.create_gist()
2204 fixture.create_gist()
2204 fixture.create_gist()
2205 fixture.create_gist()
2205
2206
2206 id_, params = _build_data(self.apikey, 'get_gists')
2207 id_, params = _build_data(self.apikey, 'get_gists')
2207 response = api_call(self, params)
2208 response = api_call(self, params)
2208 expected = response.json
2209 expected = response.json
2209 assert len(response.json['result']) == 2
2210 assert len(response.json['result']) == 2
2210 #self._compare_ok(id_, expected, given=response.body)
2211 #self._compare_ok(id_, expected, given=response.body)
2211
2212
2212 def test_api_get_gists_regular_user(self):
2213 def test_api_get_gists_regular_user(self):
2213 # by admin
2214 # by admin
2214 fixture.create_gist()
2215 fixture.create_gist()
2215 fixture.create_gist()
2216 fixture.create_gist()
2216
2217
2217 # by reg user
2218 # by reg user
2218 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2219 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2219 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2220 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2220 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2221 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2221
2222
2222 id_, params = _build_data(self.apikey_regular, 'get_gists')
2223 id_, params = _build_data(self.apikey_regular, 'get_gists')
2223 response = api_call(self, params)
2224 response = api_call(self, params)
2224 expected = response.json
2225 expected = response.json
2225 assert len(response.json['result']) == 3
2226 assert len(response.json['result']) == 3
2226 #self._compare_ok(id_, expected, given=response.body)
2227 #self._compare_ok(id_, expected, given=response.body)
2227
2228
2228 def test_api_get_gists_only_for_regular_user(self):
2229 def test_api_get_gists_only_for_regular_user(self):
2229 # by admin
2230 # by admin
2230 fixture.create_gist()
2231 fixture.create_gist()
2231 fixture.create_gist()
2232 fixture.create_gist()
2232
2233
2233 # by reg user
2234 # by reg user
2234 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2235 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2235 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2236 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2236 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2237 fixture.create_gist(owner=self.TEST_USER_LOGIN)
2237
2238
2238 id_, params = _build_data(self.apikey, 'get_gists',
2239 id_, params = _build_data(self.apikey, 'get_gists',
2239 userid=self.TEST_USER_LOGIN)
2240 userid=self.TEST_USER_LOGIN)
2240 response = api_call(self, params)
2241 response = api_call(self, params)
2241 expected = response.json
2242 expected = response.json
2242 assert len(response.json['result']) == 3
2243 assert len(response.json['result']) == 3
2243 #self._compare_ok(id_, expected, given=response.body)
2244 #self._compare_ok(id_, expected, given=response.body)
2244
2245
2245 def test_api_get_gists_regular_user_with_different_userid(self):
2246 def test_api_get_gists_regular_user_with_different_userid(self):
2246 id_, params = _build_data(self.apikey_regular, 'get_gists',
2247 id_, params = _build_data(self.apikey_regular, 'get_gists',
2247 userid=base.TEST_USER_ADMIN_LOGIN)
2248 userid=base.TEST_USER_ADMIN_LOGIN)
2248 response = api_call(self, params)
2249 response = api_call(self, params)
2249 expected = 'userid is not the same as your user'
2250 expected = 'userid is not the same as your user'
2250 self._compare_error(id_, expected, given=response.body)
2251 self._compare_error(id_, expected, given=response.body)
2251
2252
2252 def test_api_create_gist(self):
2253 def test_api_create_gist(self):
2253 id_, params = _build_data(self.apikey_regular, 'create_gist',
2254 id_, params = _build_data(self.apikey_regular, 'create_gist',
2254 lifetime=10,
2255 lifetime=10,
2255 description='foobar-gist',
2256 description='foobar-gist',
2256 gist_type='public',
2257 gist_type='public',
2257 files={'foobar': {'content': 'foo'}})
2258 files={'foobar': {'content': 'foo'}})
2258 response = api_call(self, params)
2259 response = api_call(self, params)
2259 expected = {
2260 expected = {
2260 'gist': {
2261 'gist': {
2261 'access_id': response.json['result']['gist']['access_id'],
2262 'access_id': response.json['result']['gist']['access_id'],
2262 'created_on': response.json['result']['gist']['created_on'],
2263 'created_on': response.json['result']['gist']['created_on'],
2263 'description': 'foobar-gist',
2264 'description': 'foobar-gist',
2264 'expires': response.json['result']['gist']['expires'],
2265 'expires': response.json['result']['gist']['expires'],
2265 'gist_id': response.json['result']['gist']['gist_id'],
2266 'gist_id': response.json['result']['gist']['gist_id'],
2266 'type': 'public',
2267 'type': 'public',
2267 'url': response.json['result']['gist']['url']
2268 'url': response.json['result']['gist']['url']
2268 },
2269 },
2269 'msg': 'created new gist'
2270 'msg': 'created new gist'
2270 }
2271 }
2271 self._compare_ok(id_, expected, given=response.body)
2272 self._compare_ok(id_, expected, given=response.body)
2272
2273
2273 @mock.patch.object(GistModel, 'create', raise_exception)
2274 @mock.patch.object(GistModel, 'create', raise_exception)
2274 def test_api_create_gist_exception_occurred(self):
2275 def test_api_create_gist_exception_occurred(self):
2275 id_, params = _build_data(self.apikey_regular, 'create_gist',
2276 id_, params = _build_data(self.apikey_regular, 'create_gist',
2276 files={})
2277 files={})
2277 response = api_call(self, params)
2278 response = api_call(self, params)
2278 expected = 'failed to create gist'
2279 expected = 'failed to create gist'
2279 self._compare_error(id_, expected, given=response.body)
2280 self._compare_error(id_, expected, given=response.body)
2280
2281
2281 def test_api_delete_gist(self):
2282 def test_api_delete_gist(self):
2282 gist_id = fixture.create_gist().gist_access_id
2283 gist_id = fixture.create_gist().gist_access_id
2283 id_, params = _build_data(self.apikey, 'delete_gist',
2284 id_, params = _build_data(self.apikey, 'delete_gist',
2284 gistid=gist_id)
2285 gistid=gist_id)
2285 response = api_call(self, params)
2286 response = api_call(self, params)
2286 expected = {'gist': None, 'msg': 'deleted gist ID:%s' % gist_id}
2287 expected = {'gist': None, 'msg': 'deleted gist ID:%s' % gist_id}
2287 self._compare_ok(id_, expected, given=response.body)
2288 self._compare_ok(id_, expected, given=response.body)
2288
2289
2289 def test_api_delete_gist_regular_user(self):
2290 def test_api_delete_gist_regular_user(self):
2290 gist_id = fixture.create_gist(owner=self.TEST_USER_LOGIN).gist_access_id
2291 gist_id = fixture.create_gist(owner=self.TEST_USER_LOGIN).gist_access_id
2291 id_, params = _build_data(self.apikey_regular, 'delete_gist',
2292 id_, params = _build_data(self.apikey_regular, 'delete_gist',
2292 gistid=gist_id)
2293 gistid=gist_id)
2293 response = api_call(self, params)
2294 response = api_call(self, params)
2294 expected = {'gist': None, 'msg': 'deleted gist ID:%s' % gist_id}
2295 expected = {'gist': None, 'msg': 'deleted gist ID:%s' % gist_id}
2295 self._compare_ok(id_, expected, given=response.body)
2296 self._compare_ok(id_, expected, given=response.body)
2296
2297
2297 def test_api_delete_gist_regular_user_no_permission(self):
2298 def test_api_delete_gist_regular_user_no_permission(self):
2298 gist_id = fixture.create_gist().gist_access_id
2299 gist_id = fixture.create_gist().gist_access_id
2299 id_, params = _build_data(self.apikey_regular, 'delete_gist',
2300 id_, params = _build_data(self.apikey_regular, 'delete_gist',
2300 gistid=gist_id)
2301 gistid=gist_id)
2301 response = api_call(self, params)
2302 response = api_call(self, params)
2302 expected = 'gist `%s` does not exist' % (gist_id,)
2303 expected = 'gist `%s` does not exist' % (gist_id,)
2303 self._compare_error(id_, expected, given=response.body)
2304 self._compare_error(id_, expected, given=response.body)
2304
2305
2305 @mock.patch.object(GistModel, 'delete', raise_exception)
2306 @mock.patch.object(GistModel, 'delete', raise_exception)
2306 def test_api_delete_gist_exception_occurred(self):
2307 def test_api_delete_gist_exception_occurred(self):
2307 gist_id = fixture.create_gist().gist_access_id
2308 gist_id = fixture.create_gist().gist_access_id
2308 id_, params = _build_data(self.apikey, 'delete_gist',
2309 id_, params = _build_data(self.apikey, 'delete_gist',
2309 gistid=gist_id)
2310 gistid=gist_id)
2310 response = api_call(self, params)
2311 response = api_call(self, params)
2311 expected = 'failed to delete gist ID:%s' % (gist_id,)
2312 expected = 'failed to delete gist ID:%s' % (gist_id,)
2312 self._compare_error(id_, expected, given=response.body)
2313 self._compare_error(id_, expected, given=response.body)
2313
2314
2314 def test_api_get_ip(self):
2315 def test_api_get_ip(self):
2315 id_, params = _build_data(self.apikey, 'get_ip')
2316 id_, params = _build_data(self.apikey, 'get_ip')
2316 response = api_call(self, params)
2317 response = api_call(self, params)
2317 expected = {
2318 expected = {
2318 'server_ip_addr': '0.0.0.0',
2319 'server_ip_addr': '0.0.0.0',
2319 'user_ips': []
2320 'user_ips': []
2320 }
2321 }
2321 self._compare_ok(id_, expected, given=response.body)
2322 self._compare_ok(id_, expected, given=response.body)
2322
2323
2323 def test_api_get_server_info(self):
2324 def test_api_get_server_info(self):
2324 id_, params = _build_data(self.apikey, 'get_server_info')
2325 id_, params = _build_data(self.apikey, 'get_server_info')
2325 response = api_call(self, params)
2326 response = api_call(self, params)
2326 expected = db.Setting.get_server_info()
2327 expected = db.Setting.get_server_info()
2327 self._compare_ok(id_, expected, given=response.body)
2328 self._compare_ok(id_, expected, given=response.body)
2328
2329
2329 def test_api_get_changesets(self):
2330 def test_api_get_changesets(self):
2330 id_, params = _build_data(self.apikey, 'get_changesets',
2331 id_, params = _build_data(self.apikey, 'get_changesets',
2331 repoid=self.REPO, start=0, end=2)
2332 repoid=self.REPO, start=0, end=2)
2332 response = api_call(self, params)
2333 response = api_call(self, params)
2333 result = ext_json.loads(response.body)["result"]
2334 result = ext_json.loads(response.body)["result"]
2334 assert len(result) == 3
2335 assert len(result) == 3
2335 assert 'message' in result[0]
2336 assert 'message' in result[0]
2336 assert 'added' not in result[0]
2337 assert 'added' not in result[0]
2337
2338
2338 def test_api_get_changesets_with_max_revisions(self):
2339 def test_api_get_changesets_with_max_revisions(self):
2339 id_, params = _build_data(self.apikey, 'get_changesets',
2340 id_, params = _build_data(self.apikey, 'get_changesets',
2340 repoid=self.REPO, start_date="2011-02-24T00:00:00", max_revisions=10)
2341 repoid=self.REPO, start_date="2011-02-24T00:00:00", max_revisions=10)
2341 response = api_call(self, params)
2342 response = api_call(self, params)
2342 result = ext_json.loads(response.body)["result"]
2343 result = ext_json.loads(response.body)["result"]
2343 assert len(result) == 10
2344 assert len(result) == 10
2344 assert 'message' in result[0]
2345 assert 'message' in result[0]
2345 assert 'added' not in result[0]
2346 assert 'added' not in result[0]
2346
2347
2347 def test_api_get_changesets_with_branch(self):
2348 def test_api_get_changesets_with_branch(self):
2348 if self.REPO == 'vcs_test_hg':
2349 if self.REPO == 'vcs_test_hg':
2349 branch = 'stable'
2350 branch = 'stable'
2350 else:
2351 else:
2351 pytest.skip("skipping due to missing branches in git test repo")
2352 pytest.skip("skipping due to missing branches in git test repo")
2352 id_, params = _build_data(self.apikey, 'get_changesets',
2353 id_, params = _build_data(self.apikey, 'get_changesets',
2353 repoid=self.REPO, branch_name=branch, start_date="2011-02-24T00:00:00")
2354 repoid=self.REPO, branch_name=branch, start_date="2011-02-24T00:00:00")
2354 response = api_call(self, params)
2355 response = api_call(self, params)
2355 result = ext_json.loads(response.body)["result"]
2356 result = ext_json.loads(response.body)["result"]
2356 assert len(result) == 5
2357 assert len(result) == 5
2357 assert 'message' in result[0]
2358 assert 'message' in result[0]
2358 assert 'added' not in result[0]
2359 assert 'added' not in result[0]
2359
2360
2360 def test_api_get_changesets_with_file_list(self):
2361 def test_api_get_changesets_with_file_list(self):
2361 id_, params = _build_data(self.apikey, 'get_changesets',
2362 id_, params = _build_data(self.apikey, 'get_changesets',
2362 repoid=self.REPO, start_date="2010-04-07T23:30:30", end_date="2010-04-08T00:31:14", with_file_list=True)
2363 repoid=self.REPO, start_date="2010-04-07T23:30:30", end_date="2010-04-08T00:31:14", with_file_list=True)
2363 response = api_call(self, params)
2364 response = api_call(self, params)
2364 result = ext_json.loads(response.body)["result"]
2365 result = ext_json.loads(response.body)["result"]
2365 assert len(result) == 3
2366 assert len(result) == 3
2366 assert 'message' in result[0]
2367 assert 'message' in result[0]
2367 assert 'added' in result[0]
2368 assert 'added' in result[0]
2368
2369
2369 def test_api_get_changeset(self):
2370 def test_api_get_changeset(self):
2370 review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2371 review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2371 id_, params = _build_data(self.apikey, 'get_changeset',
2372 id_, params = _build_data(self.apikey, 'get_changeset',
2372 repoid=self.REPO, raw_id=self.TEST_REVISION)
2373 repoid=self.REPO, raw_id=self.TEST_REVISION)
2373 response = api_call(self, params)
2374 response = api_call(self, params)
2374 result = ext_json.loads(response.body)["result"]
2375 result = ext_json.loads(response.body)["result"]
2375 assert result["raw_id"] == self.TEST_REVISION
2376 assert result["raw_id"] == self.TEST_REVISION
2376 assert "reviews" not in result
2377 assert "reviews" not in result
2377
2378
2378 def test_api_get_changeset_with_reviews(self):
2379 def test_api_get_changeset_with_reviews(self):
2379 reviewobjs = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2380 reviewobjs = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2380 id_, params = _build_data(self.apikey, 'get_changeset',
2381 id_, params = _build_data(self.apikey, 'get_changeset',
2381 repoid=self.REPO, raw_id=self.TEST_REVISION,
2382 repoid=self.REPO, raw_id=self.TEST_REVISION,
2382 with_reviews=True)
2383 with_reviews=True)
2383 response = api_call(self, params)
2384 response = api_call(self, params)
2384 result = ext_json.loads(response.body)["result"]
2385 result = ext_json.loads(response.body)["result"]
2385 assert result["raw_id"] == self.TEST_REVISION
2386 assert result["raw_id"] == self.TEST_REVISION
2386 assert "reviews" in result
2387 assert "reviews" in result
2387 assert len(result["reviews"]) == 1
2388 assert len(result["reviews"]) == 1
2388 review = result["reviews"][0]
2389 review = result["reviews"][0]
2389 expected = {
2390 expected = {
2390 'status': 'approved',
2391 'status': 'approved',
2391 'modified_at': reviewobjs[0].modified_at.replace(microsecond=0).isoformat(),
2392 'modified_at': reviewobjs[0].modified_at.replace(microsecond=0).isoformat(),
2392 'reviewer': 'test_admin',
2393 'reviewer': 'test_admin',
2393 }
2394 }
2394 assert review == expected
2395 assert review == expected
2395
2396
2396 def test_api_get_changeset_that_does_not_exist(self):
2397 def test_api_get_changeset_that_does_not_exist(self):
2397 """ Fetch changeset status for non-existant changeset.
2398 """ Fetch changeset status for non-existant changeset.
2398 revision id is the above git hash used in the test above with the
2399 revision id is the above git hash used in the test above with the
2399 last 3 nibbles replaced with 0xf. Should not exist for git _or_ hg.
2400 last 3 nibbles replaced with 0xf. Should not exist for git _or_ hg.
2400 """
2401 """
2401 id_, params = _build_data(self.apikey, 'get_changeset',
2402 id_, params = _build_data(self.apikey, 'get_changeset',
2402 repoid=self.REPO, raw_id = '7ab37bc680b4aa72c34d07b230c866c28e9fcfff')
2403 repoid=self.REPO, raw_id = '7ab37bc680b4aa72c34d07b230c866c28e9fcfff')
2403 response = api_call(self, params)
2404 response = api_call(self, params)
2404 expected = 'Changeset %s does not exist' % ('7ab37bc680b4aa72c34d07b230c866c28e9fcfff',)
2405 expected = 'Changeset %s does not exist' % ('7ab37bc680b4aa72c34d07b230c866c28e9fcfff',)
2405 self._compare_error(id_, expected, given=response.body)
2406 self._compare_error(id_, expected, given=response.body)
2406
2407
2407 def test_api_get_changeset_without_permission(self):
2408 def test_api_get_changeset_without_permission(self):
2408 review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2409 review = fixture.review_changeset(self.REPO, self.TEST_REVISION, "approved")
2409 RepoModel().revoke_user_permission(repo=self.REPO, user=self.TEST_USER_LOGIN)
2410 RepoModel().revoke_user_permission(repo=self.REPO, user=self.TEST_USER_LOGIN)
2410 RepoModel().revoke_user_permission(repo=self.REPO, user="default")
2411 RepoModel().revoke_user_permission(repo=self.REPO, user="default")
2411 id_, params = _build_data(self.apikey_regular, 'get_changeset',
2412 id_, params = _build_data(self.apikey_regular, 'get_changeset',
2412 repoid=self.REPO, raw_id=self.TEST_REVISION)
2413 repoid=self.REPO, raw_id=self.TEST_REVISION)
2413 response = api_call(self, params)
2414 response = api_call(self, params)
2414 expected = 'Access denied to repo %s' % self.REPO
2415 expected = 'Access denied to repo %s' % self.REPO
2415 self._compare_error(id_, expected, given=response.body)
2416 self._compare_error(id_, expected, given=response.body)
2416
2417
2417 def test_api_get_pullrequest(self):
2418 def test_api_get_pullrequest(self):
2418 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'get test')
2419 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'get test')
2419 random_id = random.randrange(1, 9999)
2420 random_id = random.randrange(1, 9999)
2420 params = ascii_bytes(ext_json.dumps({
2421 params = ascii_bytes(ext_json.dumps({
2421 "id": random_id,
2422 "id": random_id,
2422 "api_key": self.apikey,
2423 "api_key": self.apikey,
2423 "method": 'get_pullrequest',
2424 "method": 'get_pullrequest',
2424 "args": {"pullrequest_id": pull_request_id},
2425 "args": {"pullrequest_id": pull_request_id},
2425 }))
2426 }))
2426 response = api_call(self, params)
2427 response = api_call(self, params)
2427 pullrequest = db.PullRequest().get(pull_request_id)
2428 pullrequest = db.PullRequest().get(pull_request_id)
2428 expected = {
2429 expected = {
2429 "status": "new",
2430 "status": "new",
2430 "pull_request_id": pull_request_id,
2431 "pull_request_id": pull_request_id,
2431 "description": "No description",
2432 "description": "No description",
2432 "url": "/%s/pull-request/%s/_/%s" % (self.REPO, pull_request_id, "stable"),
2433 "url": "/%s/pull-request/%s/_/%s" % (self.REPO, pull_request_id, "stable"),
2433 "reviewers": [{"username": "test_regular"}],
2434 "reviewers": [{"username": "test_regular"}],
2434 "org_repo_url": "http://localhost:80/%s" % self.REPO,
2435 "org_repo_url": "http://localhost:80/%s" % self.REPO,
2435 "org_ref_parts": ["branch", "stable", self.TEST_PR_SRC],
2436 "org_ref_parts": ["branch", "stable", self.TEST_PR_SRC],
2436 "other_ref_parts": ["branch", "default", self.TEST_PR_DST],
2437 "other_ref_parts": ["branch", "default", self.TEST_PR_DST],
2437 "comments": [{"username": base.TEST_USER_ADMIN_LOGIN, "text": "",
2438 "comments": [{"username": base.TEST_USER_ADMIN_LOGIN, "text": "",
2438 "comment_id": pullrequest.comments[0].comment_id}],
2439 "comment_id": pullrequest.comments[0].comment_id}],
2439 "owner": base.TEST_USER_ADMIN_LOGIN,
2440 "owner": base.TEST_USER_ADMIN_LOGIN,
2440 "statuses": [{"status": "under_review", "reviewer": base.TEST_USER_ADMIN_LOGIN, "modified_at": "2000-01-01T00:00:00"} for i in range(0, len(self.TEST_PR_REVISIONS))],
2441 "statuses": [{"status": "under_review", "reviewer": base.TEST_USER_ADMIN_LOGIN, "modified_at": "2000-01-01T00:00:00"} for i in range(0, len(self.TEST_PR_REVISIONS))],
2441 "title": "get test",
2442 "title": "get test",
2442 "revisions": self.TEST_PR_REVISIONS,
2443 "revisions": self.TEST_PR_REVISIONS,
2443 "created_on": "2000-01-01T00:00:00",
2444 "created_on": "2000-01-01T00:00:00",
2444 "updated_on": "2000-01-01T00:00:00",
2445 "updated_on": "2000-01-01T00:00:00",
2445 }
2446 }
2446 self._compare_ok(random_id, expected,
2447 self._compare_ok(random_id, expected,
2447 given=re.sub(br"\d\d\d\d\-\d\d\-\d\dT\d\d\:\d\d\:\d\d",
2448 given=re.sub(br"\d\d\d\d\-\d\d\-\d\dT\d\d\:\d\d\:\d\d",
2448 b"2000-01-01T00:00:00", response.body))
2449 b"2000-01-01T00:00:00", response.body))
2449
2450
2450 def test_api_close_pullrequest(self):
2451 def test_api_close_pullrequest(self):
2451 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'close test')
2452 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'close test')
2452 random_id = random.randrange(1, 9999)
2453 random_id = random.randrange(1, 9999)
2453 params = ascii_bytes(ext_json.dumps({
2454 params = ascii_bytes(ext_json.dumps({
2454 "id": random_id,
2455 "id": random_id,
2455 "api_key": self.apikey,
2456 "api_key": self.apikey,
2456 "method": "comment_pullrequest",
2457 "method": "comment_pullrequest",
2457 "args": {"pull_request_id": pull_request_id, "close_pr": True},
2458 "args": {"pull_request_id": pull_request_id, "close_pr": True},
2458 }))
2459 }))
2459 response = api_call(self, params)
2460 response = api_call(self, params)
2460 self._compare_ok(random_id, True, given=response.body)
2461 self._compare_ok(random_id, True, given=response.body)
2461 pullrequest = db.PullRequest().get(pull_request_id)
2462 pullrequest = db.PullRequest().get(pull_request_id)
2462 assert pullrequest.comments[-1].text == ''
2463 assert pullrequest.comments[-1].text == ''
2463 assert pullrequest.status == db.PullRequest.STATUS_CLOSED
2464 assert pullrequest.status == db.PullRequest.STATUS_CLOSED
2464 assert pullrequest.is_closed() == True
2465 assert pullrequest.is_closed() == True
2465
2466
2466 def test_api_status_pullrequest(self):
2467 def test_api_status_pullrequest(self):
2467 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, "status test")
2468 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, "status test")
2468
2469
2469 random_id = random.randrange(1, 9999)
2470 random_id = random.randrange(1, 9999)
2470 params = ascii_bytes(ext_json.dumps({
2471 params = ascii_bytes(ext_json.dumps({
2471 "id": random_id,
2472 "id": random_id,
2472 "api_key": db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN).api_key,
2473 "api_key": db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN).api_key,
2473 "method": "comment_pullrequest",
2474 "method": "comment_pullrequest",
2474 "args": {"pull_request_id": pull_request_id, "status": db.ChangesetStatus.STATUS_APPROVED},
2475 "args": {"pull_request_id": pull_request_id, "status": db.ChangesetStatus.STATUS_APPROVED},
2475 }))
2476 }))
2476 response = api_call(self, params)
2477 response = api_call(self, params)
2477 pullrequest = db.PullRequest().get(pull_request_id)
2478 pullrequest = db.PullRequest().get(pull_request_id)
2478 self._compare_error(random_id, "No permission to change pull request status. User needs to be admin, owner or reviewer.", given=response.body)
2479 self._compare_error(random_id, "No permission to change pull request status. User needs to be admin, owner or reviewer.", given=response.body)
2479 assert db.ChangesetStatus.STATUS_UNDER_REVIEW == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
2480 assert db.ChangesetStatus.STATUS_UNDER_REVIEW == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
2480 params = ascii_bytes(ext_json.dumps({
2481 params = ascii_bytes(ext_json.dumps({
2481 "id": random_id,
2482 "id": random_id,
2482 "api_key": db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN).api_key,
2483 "api_key": db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN).api_key,
2483 "method": "comment_pullrequest",
2484 "method": "comment_pullrequest",
2484 "args": {"pull_request_id": pull_request_id, "status": db.ChangesetStatus.STATUS_APPROVED},
2485 "args": {"pull_request_id": pull_request_id, "status": db.ChangesetStatus.STATUS_APPROVED},
2485 }))
2486 }))
2486 response = api_call(self, params)
2487 response = api_call(self, params)
2487 self._compare_ok(random_id, True, given=response.body)
2488 self._compare_ok(random_id, True, given=response.body)
2488 pullrequest = db.PullRequest().get(pull_request_id)
2489 pullrequest = db.PullRequest().get(pull_request_id)
2489 assert db.ChangesetStatus.STATUS_APPROVED == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
2490 assert db.ChangesetStatus.STATUS_APPROVED == ChangesetStatusModel().calculate_pull_request_result(pullrequest)[2]
2490
2491
2491 def test_api_comment_pullrequest(self):
2492 def test_api_comment_pullrequest(self):
2492 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, "comment test")
2493 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, "comment test")
2493 random_id = random.randrange(1, 9999)
2494 random_id = random.randrange(1, 9999)
2494 params = ascii_bytes(ext_json.dumps({
2495 params = ascii_bytes(ext_json.dumps({
2495 "id": random_id,
2496 "id": random_id,
2496 "api_key": self.apikey,
2497 "api_key": self.apikey,
2497 "method": "comment_pullrequest",
2498 "method": "comment_pullrequest",
2498 "args": {"pull_request_id": pull_request_id, "comment_msg": "Looks good to me"},
2499 "args": {"pull_request_id": pull_request_id, "comment_msg": "Looks good to me"},
2499 }))
2500 }))
2500 response = api_call(self, params)
2501 response = api_call(self, params)
2501 self._compare_ok(random_id, True, given=response.body)
2502 self._compare_ok(random_id, True, given=response.body)
2502 pullrequest = db.PullRequest().get(pull_request_id)
2503 pullrequest = db.PullRequest().get(pull_request_id)
2503 assert pullrequest.comments[-1].text == 'Looks good to me'
2504 assert pullrequest.comments[-1].text == 'Looks good to me'
2504
2505
2505 def test_api_edit_reviewers_add_single(self):
2506 def test_api_edit_reviewers_add_single(self):
2506 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2507 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2507 pullrequest = db.PullRequest().get(pull_request_id)
2508 pullrequest = db.PullRequest().get(pull_request_id)
2508 pullrequest.owner = self.test_user
2509 pullrequest.owner = self.test_user
2509 random_id = random.randrange(1, 9999)
2510 random_id = random.randrange(1, 9999)
2510 params = ascii_bytes(ext_json.dumps({
2511 params = ascii_bytes(ext_json.dumps({
2511 "id": random_id,
2512 "id": random_id,
2512 "api_key": self.apikey_regular,
2513 "api_key": self.apikey_regular,
2513 "method": "edit_reviewers",
2514 "method": "edit_reviewers",
2514 "args": {"pull_request_id": pull_request_id, "add": base.TEST_USER_REGULAR2_LOGIN},
2515 "args": {"pull_request_id": pull_request_id, "add": base.TEST_USER_REGULAR2_LOGIN},
2515 }))
2516 }))
2516 response = api_call(self, params)
2517 response = api_call(self, params)
2517 expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN], 'already_present': [], 'removed': [] }
2518 expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN], 'already_present': [], 'removed': [] }
2518
2519
2519 self._compare_ok(random_id, expected, given=response.body)
2520 self._compare_ok(random_id, expected, given=response.body)
2520 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2521 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2521
2522
2522 def test_api_edit_reviewers_add_nonexistent(self):
2523 def test_api_edit_reviewers_add_nonexistent(self):
2523 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2524 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2524 pullrequest = db.PullRequest().get(pull_request_id)
2525 pullrequest = db.PullRequest().get(pull_request_id)
2525 pullrequest.owner = self.test_user
2526 pullrequest.owner = self.test_user
2526 random_id = random.randrange(1, 9999)
2527 random_id = random.randrange(1, 9999)
2527 params = ascii_bytes(ext_json.dumps({
2528 params = ascii_bytes(ext_json.dumps({
2528 "id": random_id,
2529 "id": random_id,
2529 "api_key": self.apikey_regular,
2530 "api_key": self.apikey_regular,
2530 "method": "edit_reviewers",
2531 "method": "edit_reviewers",
2531 "args": {"pull_request_id": pull_request_id, "add": 999},
2532 "args": {"pull_request_id": pull_request_id, "add": 999},
2532 }))
2533 }))
2533 response = api_call(self, params)
2534 response = api_call(self, params)
2534
2535
2535 self._compare_error(random_id, "user `999` does not exist", given=response.body)
2536 self._compare_error(random_id, "user `999` does not exist", given=response.body)
2536
2537
2537 def test_api_edit_reviewers_add_multiple(self):
2538 def test_api_edit_reviewers_add_multiple(self):
2538 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2539 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2539 pullrequest = db.PullRequest().get(pull_request_id)
2540 pullrequest = db.PullRequest().get(pull_request_id)
2540 pullrequest.owner = self.test_user
2541 pullrequest.owner = self.test_user
2541 random_id = random.randrange(1, 9999)
2542 random_id = random.randrange(1, 9999)
2542 params = ascii_bytes(ext_json.dumps({
2543 params = ascii_bytes(ext_json.dumps({
2543 "id": random_id,
2544 "id": random_id,
2544 "api_key": self.apikey_regular,
2545 "api_key": self.apikey_regular,
2545 "method": "edit_reviewers",
2546 "method": "edit_reviewers",
2546 "args": {
2547 "args": {
2547 "pull_request_id": pull_request_id,
2548 "pull_request_id": pull_request_id,
2548 "add": [ self.TEST_USER_LOGIN, base.TEST_USER_REGULAR2_LOGIN ]
2549 "add": [ self.TEST_USER_LOGIN, base.TEST_USER_REGULAR2_LOGIN ]
2549 },
2550 },
2550 }))
2551 }))
2551 response = api_call(self, params)
2552 response = api_call(self, params)
2552 # list order depends on python sorting hash, which is randomized
2553 # list order depends on python sorting hash, which is randomized
2553 assert set(ext_json.loads(response.body)['result']['added']) == set([base.TEST_USER_REGULAR2_LOGIN, self.TEST_USER_LOGIN])
2554 assert set(ext_json.loads(response.body)['result']['added']) == set([base.TEST_USER_REGULAR2_LOGIN, self.TEST_USER_LOGIN])
2554 assert set(ext_json.loads(response.body)['result']['already_present']) == set()
2555 assert set(ext_json.loads(response.body)['result']['already_present']) == set()
2555 assert set(ext_json.loads(response.body)['result']['removed']) == set()
2556 assert set(ext_json.loads(response.body)['result']['removed']) == set()
2556
2557
2557 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2558 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2558 assert db.User.get_by_username(self.TEST_USER_LOGIN) in pullrequest.get_reviewer_users()
2559 assert db.User.get_by_username(self.TEST_USER_LOGIN) in pullrequest.get_reviewer_users()
2559
2560
2560 def test_api_edit_reviewers_add_already_present(self):
2561 def test_api_edit_reviewers_add_already_present(self):
2561 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2562 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2562 pullrequest = db.PullRequest().get(pull_request_id)
2563 pullrequest = db.PullRequest().get(pull_request_id)
2563 pullrequest.owner = self.test_user
2564 pullrequest.owner = self.test_user
2564 random_id = random.randrange(1, 9999)
2565 random_id = random.randrange(1, 9999)
2565 params = ascii_bytes(ext_json.dumps({
2566 params = ascii_bytes(ext_json.dumps({
2566 "id": random_id,
2567 "id": random_id,
2567 "api_key": self.apikey_regular,
2568 "api_key": self.apikey_regular,
2568 "method": "edit_reviewers",
2569 "method": "edit_reviewers",
2569 "args": {
2570 "args": {
2570 "pull_request_id": pull_request_id,
2571 "pull_request_id": pull_request_id,
2571 "add": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN ]
2572 "add": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN ]
2572 },
2573 },
2573 }))
2574 }))
2574 response = api_call(self, params)
2575 response = api_call(self, params)
2575 expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN],
2576 expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN],
2576 'already_present': [base.TEST_USER_REGULAR_LOGIN],
2577 'already_present': [base.TEST_USER_REGULAR_LOGIN],
2577 'removed': [],
2578 'removed': [],
2578 }
2579 }
2579
2580
2580 self._compare_ok(random_id, expected, given=response.body)
2581 self._compare_ok(random_id, expected, given=response.body)
2581 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2582 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2582 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2583 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2583
2584
2584 def test_api_edit_reviewers_add_closed(self):
2585 def test_api_edit_reviewers_add_closed(self):
2585 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2586 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2586 pullrequest = db.PullRequest().get(pull_request_id)
2587 pullrequest = db.PullRequest().get(pull_request_id)
2587 pullrequest.owner = self.test_user
2588 pullrequest.owner = self.test_user
2588 PullRequestModel().close_pull_request(pull_request_id)
2589 PullRequestModel().close_pull_request(pull_request_id)
2589 random_id = random.randrange(1, 9999)
2590 random_id = random.randrange(1, 9999)
2590 params = ascii_bytes(ext_json.dumps({
2591 params = ascii_bytes(ext_json.dumps({
2591 "id": random_id,
2592 "id": random_id,
2592 "api_key": self.apikey_regular,
2593 "api_key": self.apikey_regular,
2593 "method": "edit_reviewers",
2594 "method": "edit_reviewers",
2594 "args": {"pull_request_id": pull_request_id, "add": base.TEST_USER_REGULAR2_LOGIN},
2595 "args": {"pull_request_id": pull_request_id, "add": base.TEST_USER_REGULAR2_LOGIN},
2595 }))
2596 }))
2596 response = api_call(self, params)
2597 response = api_call(self, params)
2597 self._compare_error(random_id, "Cannot edit reviewers of a closed pull request.", given=response.body)
2598 self._compare_error(random_id, "Cannot edit reviewers of a closed pull request.", given=response.body)
2598
2599
2599 def test_api_edit_reviewers_add_not_owner(self):
2600 def test_api_edit_reviewers_add_not_owner(self):
2600 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2601 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2601 pullrequest = db.PullRequest().get(pull_request_id)
2602 pullrequest = db.PullRequest().get(pull_request_id)
2602 pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
2603 pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
2603 random_id = random.randrange(1, 9999)
2604 random_id = random.randrange(1, 9999)
2604 params = ascii_bytes(ext_json.dumps({
2605 params = ascii_bytes(ext_json.dumps({
2605 "id": random_id,
2606 "id": random_id,
2606 "api_key": self.apikey_regular,
2607 "api_key": self.apikey_regular,
2607 "method": "edit_reviewers",
2608 "method": "edit_reviewers",
2608 "args": {"pull_request_id": pull_request_id, "add": base.TEST_USER_REGULAR2_LOGIN},
2609 "args": {"pull_request_id": pull_request_id, "add": base.TEST_USER_REGULAR2_LOGIN},
2609 }))
2610 }))
2610 response = api_call(self, params)
2611 response = api_call(self, params)
2611 self._compare_error(random_id, "No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.", given=response.body)
2612 self._compare_error(random_id, "No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.", given=response.body)
2612
2613
2613
2614
2614 def test_api_edit_reviewers_remove_single(self):
2615 def test_api_edit_reviewers_remove_single(self):
2615 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2616 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2616 pullrequest = db.PullRequest().get(pull_request_id)
2617 pullrequest = db.PullRequest().get(pull_request_id)
2617 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2618 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2618
2619
2619 pullrequest.owner = self.test_user
2620 pullrequest.owner = self.test_user
2620 random_id = random.randrange(1, 9999)
2621 random_id = random.randrange(1, 9999)
2621 params = ascii_bytes(ext_json.dumps({
2622 params = ascii_bytes(ext_json.dumps({
2622 "id": random_id,
2623 "id": random_id,
2623 "api_key": self.apikey_regular,
2624 "api_key": self.apikey_regular,
2624 "method": "edit_reviewers",
2625 "method": "edit_reviewers",
2625 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR_LOGIN},
2626 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR_LOGIN},
2626 }))
2627 }))
2627 response = api_call(self, params)
2628 response = api_call(self, params)
2628
2629
2629 expected = { 'added': [],
2630 expected = { 'added': [],
2630 'already_present': [],
2631 'already_present': [],
2631 'removed': [base.TEST_USER_REGULAR_LOGIN],
2632 'removed': [base.TEST_USER_REGULAR_LOGIN],
2632 }
2633 }
2633 self._compare_ok(random_id, expected, given=response.body)
2634 self._compare_ok(random_id, expected, given=response.body)
2634 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2635 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2635
2636
2636 def test_api_edit_reviewers_remove_nonexistent(self):
2637 def test_api_edit_reviewers_remove_nonexistent(self):
2637 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2638 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2638 pullrequest = db.PullRequest().get(pull_request_id)
2639 pullrequest = db.PullRequest().get(pull_request_id)
2639 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2640 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2640
2641
2641 pullrequest.owner = self.test_user
2642 pullrequest.owner = self.test_user
2642 random_id = random.randrange(1, 9999)
2643 random_id = random.randrange(1, 9999)
2643 params = ascii_bytes(ext_json.dumps({
2644 params = ascii_bytes(ext_json.dumps({
2644 "id": random_id,
2645 "id": random_id,
2645 "api_key": self.apikey_regular,
2646 "api_key": self.apikey_regular,
2646 "method": "edit_reviewers",
2647 "method": "edit_reviewers",
2647 "args": {"pull_request_id": pull_request_id, "remove": 999},
2648 "args": {"pull_request_id": pull_request_id, "remove": 999},
2648 }))
2649 }))
2649 response = api_call(self, params)
2650 response = api_call(self, params)
2650
2651
2651 self._compare_error(random_id, "user `999` does not exist", given=response.body)
2652 self._compare_error(random_id, "user `999` does not exist", given=response.body)
2652 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2653 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2653
2654
2654 def test_api_edit_reviewers_remove_nonpresent(self):
2655 def test_api_edit_reviewers_remove_nonpresent(self):
2655 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2656 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2656 pullrequest = db.PullRequest().get(pull_request_id)
2657 pullrequest = db.PullRequest().get(pull_request_id)
2657 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2658 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2658 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2659 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2659
2660
2660 pullrequest.owner = self.test_user
2661 pullrequest.owner = self.test_user
2661 random_id = random.randrange(1, 9999)
2662 random_id = random.randrange(1, 9999)
2662 params = ascii_bytes(ext_json.dumps({
2663 params = ascii_bytes(ext_json.dumps({
2663 "id": random_id,
2664 "id": random_id,
2664 "api_key": self.apikey_regular,
2665 "api_key": self.apikey_regular,
2665 "method": "edit_reviewers",
2666 "method": "edit_reviewers",
2666 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR2_LOGIN},
2667 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR2_LOGIN},
2667 }))
2668 }))
2668 response = api_call(self, params)
2669 response = api_call(self, params)
2669
2670
2670 # NOTE: no explicit indication that removed user was not even a reviewer
2671 # NOTE: no explicit indication that removed user was not even a reviewer
2671 expected = { 'added': [],
2672 expected = { 'added': [],
2672 'already_present': [],
2673 'already_present': [],
2673 'removed': [base.TEST_USER_REGULAR2_LOGIN],
2674 'removed': [base.TEST_USER_REGULAR2_LOGIN],
2674 }
2675 }
2675 self._compare_ok(random_id, expected, given=response.body)
2676 self._compare_ok(random_id, expected, given=response.body)
2676 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2677 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2677 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2678 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2678
2679
2679 def test_api_edit_reviewers_remove_multiple(self):
2680 def test_api_edit_reviewers_remove_multiple(self):
2680 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2681 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2681 pullrequest = db.PullRequest().get(pull_request_id)
2682 pullrequest = db.PullRequest().get(pull_request_id)
2682 prr = db.PullRequestReviewer(db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN), pullrequest)
2683 prr = db.PullRequestReviewer(db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN), pullrequest)
2683 meta.Session().add(prr)
2684 meta.Session().add(prr)
2684 meta.Session().commit()
2685 meta.Session().commit()
2685
2686
2686 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2687 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2687 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2688 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2688
2689
2689 pullrequest.owner = self.test_user
2690 pullrequest.owner = self.test_user
2690 random_id = random.randrange(1, 9999)
2691 random_id = random.randrange(1, 9999)
2691 params = ascii_bytes(ext_json.dumps({
2692 params = ascii_bytes(ext_json.dumps({
2692 "id": random_id,
2693 "id": random_id,
2693 "api_key": self.apikey_regular,
2694 "api_key": self.apikey_regular,
2694 "method": "edit_reviewers",
2695 "method": "edit_reviewers",
2695 "args": {"pull_request_id": pull_request_id, "remove": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN ] },
2696 "args": {"pull_request_id": pull_request_id, "remove": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN ] },
2696 }))
2697 }))
2697 response = api_call(self, params)
2698 response = api_call(self, params)
2698
2699
2699 # list order depends on python sorting hash, which is randomized
2700 # list order depends on python sorting hash, which is randomized
2700 assert set(ext_json.loads(response.body)['result']['added']) == set()
2701 assert set(ext_json.loads(response.body)['result']['added']) == set()
2701 assert set(ext_json.loads(response.body)['result']['already_present']) == set()
2702 assert set(ext_json.loads(response.body)['result']['already_present']) == set()
2702 assert set(ext_json.loads(response.body)['result']['removed']) == set([base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN])
2703 assert set(ext_json.loads(response.body)['result']['removed']) == set([base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_REGULAR2_LOGIN])
2703 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2704 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2704 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2705 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2705
2706
2706 def test_api_edit_reviewers_remove_closed(self):
2707 def test_api_edit_reviewers_remove_closed(self):
2707 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2708 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2708 pullrequest = db.PullRequest().get(pull_request_id)
2709 pullrequest = db.PullRequest().get(pull_request_id)
2709 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2710 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2710 PullRequestModel().close_pull_request(pull_request_id)
2711 PullRequestModel().close_pull_request(pull_request_id)
2711
2712
2712 pullrequest.owner = self.test_user
2713 pullrequest.owner = self.test_user
2713 random_id = random.randrange(1, 9999)
2714 random_id = random.randrange(1, 9999)
2714 params = ascii_bytes(ext_json.dumps({
2715 params = ascii_bytes(ext_json.dumps({
2715 "id": random_id,
2716 "id": random_id,
2716 "api_key": self.apikey_regular,
2717 "api_key": self.apikey_regular,
2717 "method": "edit_reviewers",
2718 "method": "edit_reviewers",
2718 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR_LOGIN},
2719 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR_LOGIN},
2719 }))
2720 }))
2720 response = api_call(self, params)
2721 response = api_call(self, params)
2721
2722
2722 self._compare_error(random_id, "Cannot edit reviewers of a closed pull request.", given=response.body)
2723 self._compare_error(random_id, "Cannot edit reviewers of a closed pull request.", given=response.body)
2723 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2724 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2724
2725
2725 def test_api_edit_reviewers_remove_not_owner(self):
2726 def test_api_edit_reviewers_remove_not_owner(self):
2726 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2727 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2727 pullrequest = db.PullRequest().get(pull_request_id)
2728 pullrequest = db.PullRequest().get(pull_request_id)
2728 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2729 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2729
2730
2730 pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
2731 pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
2731 random_id = random.randrange(1, 9999)
2732 random_id = random.randrange(1, 9999)
2732 params = ascii_bytes(ext_json.dumps({
2733 params = ascii_bytes(ext_json.dumps({
2733 "id": random_id,
2734 "id": random_id,
2734 "api_key": self.apikey_regular,
2735 "api_key": self.apikey_regular,
2735 "method": "edit_reviewers",
2736 "method": "edit_reviewers",
2736 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR_LOGIN},
2737 "args": {"pull_request_id": pull_request_id, "remove": base.TEST_USER_REGULAR_LOGIN},
2737 }))
2738 }))
2738 response = api_call(self, params)
2739 response = api_call(self, params)
2739
2740
2740 self._compare_error(random_id, "No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.", given=response.body)
2741 self._compare_error(random_id, "No permission to edit reviewers of this pull request. User needs to be admin or pull request owner.", given=response.body)
2741 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2742 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2742
2743
2743 def test_api_edit_reviewers_add_remove_single(self):
2744 def test_api_edit_reviewers_add_remove_single(self):
2744 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2745 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2745 pullrequest = db.PullRequest().get(pull_request_id)
2746 pullrequest = db.PullRequest().get(pull_request_id)
2746 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2747 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2747 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2748 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2748
2749
2749 pullrequest.owner = self.test_user
2750 pullrequest.owner = self.test_user
2750 random_id = random.randrange(1, 9999)
2751 random_id = random.randrange(1, 9999)
2751 params = ascii_bytes(ext_json.dumps({
2752 params = ascii_bytes(ext_json.dumps({
2752 "id": random_id,
2753 "id": random_id,
2753 "api_key": self.apikey_regular,
2754 "api_key": self.apikey_regular,
2754 "method": "edit_reviewers",
2755 "method": "edit_reviewers",
2755 "args": {"pull_request_id": pull_request_id,
2756 "args": {"pull_request_id": pull_request_id,
2756 "add": base.TEST_USER_REGULAR2_LOGIN,
2757 "add": base.TEST_USER_REGULAR2_LOGIN,
2757 "remove": base.TEST_USER_REGULAR_LOGIN
2758 "remove": base.TEST_USER_REGULAR_LOGIN
2758 },
2759 },
2759 }))
2760 }))
2760 response = api_call(self, params)
2761 response = api_call(self, params)
2761
2762
2762 expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN],
2763 expected = { 'added': [base.TEST_USER_REGULAR2_LOGIN],
2763 'already_present': [],
2764 'already_present': [],
2764 'removed': [base.TEST_USER_REGULAR_LOGIN],
2765 'removed': [base.TEST_USER_REGULAR_LOGIN],
2765 }
2766 }
2766 self._compare_ok(random_id, expected, given=response.body)
2767 self._compare_ok(random_id, expected, given=response.body)
2767 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2768 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2768 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2769 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2769
2770
2770 def test_api_edit_reviewers_add_remove_multiple(self):
2771 def test_api_edit_reviewers_add_remove_multiple(self):
2771 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2772 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2772 pullrequest = db.PullRequest().get(pull_request_id)
2773 pullrequest = db.PullRequest().get(pull_request_id)
2773 prr = db.PullRequestReviewer(db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN), pullrequest)
2774 prr = db.PullRequestReviewer(db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN), pullrequest)
2774 meta.Session().add(prr)
2775 meta.Session().add(prr)
2775 meta.Session().commit()
2776 meta.Session().commit()
2776 assert db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN) in pullrequest.get_reviewer_users()
2777 assert db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN) in pullrequest.get_reviewer_users()
2777 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2778 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2778 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2779 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) not in pullrequest.get_reviewer_users()
2779
2780
2780 pullrequest.owner = self.test_user
2781 pullrequest.owner = self.test_user
2781 random_id = random.randrange(1, 9999)
2782 random_id = random.randrange(1, 9999)
2782 params = ascii_bytes(ext_json.dumps({
2783 params = ascii_bytes(ext_json.dumps({
2783 "id": random_id,
2784 "id": random_id,
2784 "api_key": self.apikey_regular,
2785 "api_key": self.apikey_regular,
2785 "method": "edit_reviewers",
2786 "method": "edit_reviewers",
2786 "args": {"pull_request_id": pull_request_id,
2787 "args": {"pull_request_id": pull_request_id,
2787 "add": [ base.TEST_USER_REGULAR2_LOGIN ],
2788 "add": [ base.TEST_USER_REGULAR2_LOGIN ],
2788 "remove": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_ADMIN_LOGIN ],
2789 "remove": [ base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_ADMIN_LOGIN ],
2789 },
2790 },
2790 }))
2791 }))
2791 response = api_call(self, params)
2792 response = api_call(self, params)
2792
2793
2793 # list order depends on python sorting hash, which is randomized
2794 # list order depends on python sorting hash, which is randomized
2794 assert set(ext_json.loads(response.body)['result']['added']) == set([base.TEST_USER_REGULAR2_LOGIN])
2795 assert set(ext_json.loads(response.body)['result']['added']) == set([base.TEST_USER_REGULAR2_LOGIN])
2795 assert set(ext_json.loads(response.body)['result']['already_present']) == set()
2796 assert set(ext_json.loads(response.body)['result']['already_present']) == set()
2796 assert set(ext_json.loads(response.body)['result']['removed']) == set([base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_ADMIN_LOGIN])
2797 assert set(ext_json.loads(response.body)['result']['removed']) == set([base.TEST_USER_REGULAR_LOGIN, base.TEST_USER_ADMIN_LOGIN])
2797 assert db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN) not in pullrequest.get_reviewer_users()
2798 assert db.User.get_by_username(base.TEST_USER_ADMIN_LOGIN) not in pullrequest.get_reviewer_users()
2798 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2799 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) not in pullrequest.get_reviewer_users()
2799 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2800 assert db.User.get_by_username(base.TEST_USER_REGULAR2_LOGIN) in pullrequest.get_reviewer_users()
2800
2801
2801 def test_api_edit_reviewers_invalid_params(self):
2802 def test_api_edit_reviewers_invalid_params(self):
2802 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2803 pull_request_id = fixture.create_pullrequest(self, self.REPO, self.TEST_PR_SRC, self.TEST_PR_DST, 'edit reviewer test')
2803 pullrequest = db.PullRequest().get(pull_request_id)
2804 pullrequest = db.PullRequest().get(pull_request_id)
2804 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2805 assert db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN) in pullrequest.get_reviewer_users()
2805
2806
2806 pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
2807 pullrequest.owner = db.User.get_by_username(base.TEST_USER_REGULAR_LOGIN)
2807 random_id = random.randrange(1, 9999)
2808 random_id = random.randrange(1, 9999)
2808 params = ascii_bytes(ext_json.dumps({
2809 params = ascii_bytes(ext_json.dumps({
2809 "id": random_id,
2810 "id": random_id,
2810 "api_key": self.apikey_regular,
2811 "api_key": self.apikey_regular,
2811 "method": "edit_reviewers",
2812 "method": "edit_reviewers",
2812 "args": {"pull_request_id": pull_request_id},
2813 "args": {"pull_request_id": pull_request_id},
2813 }))
2814 }))
2814 response = api_call(self, params)
2815 response = api_call(self, params)
2815
2816
2816 self._compare_error(random_id, "Invalid request. Neither 'add' nor 'remove' is specified.", given=response.body)
2817 self._compare_error(random_id, "Invalid request. Neither 'add' nor 'remove' is specified.", given=response.body)
2817 assert ext_json.loads(response.body)['result'] is None
2818 assert ext_json.loads(response.body)['result'] is None
@@ -1,579 +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 kallithea.tests.other.test_libs
15 kallithea.tests.other.test_libs
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Package for testing various lib/helper functions in kallithea
18 Package for testing various lib/helper functions in kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Jun 9, 2011
22 :created_on: Jun 9, 2011
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import datetime
28 import datetime
29 import hashlib
29 import hashlib
30 import re
30 import re
31
31
32 import mock
32 import mock
33 import routes
33 import routes
34 from dateutil import relativedelta
34 from dateutil import relativedelta
35 from tg import request
35 from tg import request
36 from tg.util.webtest import test_context
36 from tg.util.webtest import test_context
37
37
38 import kallithea.lib.helpers as h
38 import kallithea.lib.helpers as h
39 from kallithea.lib import webutils
39 from kallithea.lib import webutils
40 from kallithea.lib.utils2 import AttributeDict, get_clone_url, safe_bytes
40 from kallithea.lib.utils2 import AttributeDict, get_clone_url, safe_bytes
41 from kallithea.model import db
41 from kallithea.model import db
42 from kallithea.tests import base
42 from kallithea.tests import base
43
43
44
44
45 proto = 'http'
45 proto = 'http'
46 TEST_URLS = [
46 TEST_URLS = [
47 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
47 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
48 '%s://127.0.0.1' % proto),
48 '%s://127.0.0.1' % proto),
49 ('%s://username@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
49 ('%s://username@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
50 '%s://127.0.0.1' % proto),
50 '%s://127.0.0.1' % proto),
51 ('%s://username:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
51 ('%s://username:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
52 '%s://127.0.0.1' % proto),
52 '%s://127.0.0.1' % proto),
53 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
53 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
54 '%s://127.0.0.1:8080' % proto),
54 '%s://127.0.0.1:8080' % proto),
55 ('%s://example.com' % proto, ['%s://' % proto, 'example.com'],
55 ('%s://example.com' % proto, ['%s://' % proto, 'example.com'],
56 '%s://example.com' % proto),
56 '%s://example.com' % proto),
57 ('%s://user:pass@example.com:8080' % proto, ['%s://' % proto, 'example.com',
57 ('%s://user:pass@example.com:8080' % proto, ['%s://' % proto, 'example.com',
58 '8080'],
58 '8080'],
59 '%s://example.com:8080' % proto),
59 '%s://example.com:8080' % proto),
60 ]
60 ]
61
61
62 proto = 'https'
62 proto = 'https'
63 TEST_URLS += [
63 TEST_URLS += [
64 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
64 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
65 '%s://127.0.0.1' % proto),
65 '%s://127.0.0.1' % proto),
66 ('%s://username@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
66 ('%s://username@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
67 '%s://127.0.0.1' % proto),
67 '%s://127.0.0.1' % proto),
68 ('%s://username:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
68 ('%s://username:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
69 '%s://127.0.0.1' % proto),
69 '%s://127.0.0.1' % proto),
70 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
70 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
71 '%s://127.0.0.1:8080' % proto),
71 '%s://127.0.0.1:8080' % proto),
72 ('%s://example.com' % proto, ['%s://' % proto, 'example.com'],
72 ('%s://example.com' % proto, ['%s://' % proto, 'example.com'],
73 '%s://example.com' % proto),
73 '%s://example.com' % proto),
74 ('%s://user:pass@example.com:8080' % proto, ['%s://' % proto, 'example.com',
74 ('%s://user:pass@example.com:8080' % proto, ['%s://' % proto, 'example.com',
75 '8080'],
75 '8080'],
76 '%s://example.com:8080' % proto),
76 '%s://example.com:8080' % proto),
77 ]
77 ]
78
78
79
79
80 class TestLibs(base.TestController):
80 class TestLibs(base.TestController):
81
81
82 @base.parametrize('test_url,expected,expected_creds', TEST_URLS)
82 @base.parametrize('test_url,expected,expected_creds', TEST_URLS)
83 def test_uri_filter(self, test_url, expected, expected_creds):
83 def test_uri_filter(self, test_url, expected, expected_creds):
84 from kallithea.lib.utils2 import uri_filter
84 from kallithea.lib.utils2 import uri_filter
85 assert uri_filter(test_url) == expected
85 assert uri_filter(test_url) == expected
86
86
87 @base.parametrize('test_url,expected,expected_creds', TEST_URLS)
87 @base.parametrize('test_url,expected,expected_creds', TEST_URLS)
88 def test_credentials_filter(self, test_url, expected, expected_creds):
88 def test_credentials_filter(self, test_url, expected, expected_creds):
89 from kallithea.lib.utils2 import credentials_filter
89 from kallithea.lib.utils2 import credentials_filter
90 assert credentials_filter(test_url) == expected_creds
90 assert credentials_filter(test_url) == expected_creds
91
91
92 @base.parametrize('str_bool,expected', [
92 @base.parametrize('str_bool,expected', [
93 ('t', True),
93 ('t', True),
94 ('true', True),
94 ('true', True),
95 ('y', True),
95 ('y', True),
96 ('yes', True),
96 ('yes', True),
97 ('on', True),
97 ('on', True),
98 ('1', True),
98 ('1', True),
99 ('Y', True),
99 ('Y', True),
100 ('yeS', True),
100 ('yeS', True),
101 ('Y', True),
101 ('Y', True),
102 ('TRUE', True),
102 ('TRUE', True),
103 ('T', True),
103 ('T', True),
104 ('False', False),
104 ('False', False),
105 ('F', False),
105 ('F', False),
106 ('FALSE', False),
106 ('FALSE', False),
107 ('0', False),
107 ('0', False),
108 ])
108 ])
109 def test_asbool(self, str_bool, expected):
109 def test_asbool(self, str_bool, expected):
110 from kallithea.lib.utils2 import asbool
110 from kallithea.lib.utils2 import asbool
111 assert asbool(str_bool) == expected
111 assert asbool(str_bool) == expected
112
112
113 def test_mention_extractor(self):
113 def test_mention_extractor(self):
114 sample = (
114 sample = (
115 "@first hi there @world here's my email username@example.com "
115 "@first hi there @world here's my email username@example.com "
116 "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
116 "@lukaszb check @one_more22 it pls @ ttwelve @D[] @one@two@three "
117 "@UPPER @cAmEL @2one_more22 @john please see this http://org.pl "
117 "@UPPER @cAmEL @2one_more22 @john please see this http://org.pl "
118 "@marian.user just do it @marco-polo and next extract @marco_polo "
118 "@marian.user just do it @marco-polo and next extract @marco_polo "
119 "user.dot hej ! not-needed maril@example.com"
119 "user.dot hej ! not-needed maril@example.com"
120 )
120 )
121
121
122 expected = set([
122 expected = set([
123 '2one_more22', 'first', 'lukaszb', 'one', 'one_more22', 'UPPER', 'cAmEL', 'john',
123 '2one_more22', 'first', 'lukaszb', 'one', 'one_more22', 'UPPER', 'cAmEL', 'john',
124 'marian.user', 'marco-polo', 'marco_polo', 'world'])
124 'marian.user', 'marco-polo', 'marco_polo', 'world'])
125 assert expected == set(webutils.extract_mentioned_usernames(sample))
125 assert expected == set(webutils.extract_mentioned_usernames(sample))
126
126
127 @base.parametrize('age_args,expected', [
127 @base.parametrize('age_args,expected', [
128 (dict(), 'just now'),
128 (dict(), 'just now'),
129 (dict(seconds= -1), '1 second ago'),
129 (dict(seconds= -1), '1 second ago'),
130 (dict(seconds= -60 * 2), '2 minutes ago'),
130 (dict(seconds= -60 * 2), '2 minutes ago'),
131 (dict(hours= -1), '1 hour ago'),
131 (dict(hours= -1), '1 hour ago'),
132 (dict(hours= -24), '1 day ago'),
132 (dict(hours= -24), '1 day ago'),
133 (dict(hours= -24 * 5), '5 days ago'),
133 (dict(hours= -24 * 5), '5 days ago'),
134 (dict(months= -1), '1 month ago'),
134 (dict(months= -1), '1 month ago'),
135 (dict(months= -1, days= -2), '1 month and 2 days ago'),
135 (dict(months= -1, days= -2), '1 month and 2 days ago'),
136 (dict(months= -1, days= -20), '1 month and 19 days ago'),
136 (dict(months= -1, days= -20), '1 month and 19 days ago'),
137 (dict(years= -1, months= -1), '1 year and 1 month ago'),
137 (dict(years= -1, months= -1), '1 year and 1 month ago'),
138 (dict(years= -1, months= -10), '1 year and 10 months ago'),
138 (dict(years= -1, months= -10), '1 year and 10 months ago'),
139 (dict(years= -2, months= -4), '2 years and 4 months ago'),
139 (dict(years= -2, months= -4), '2 years and 4 months ago'),
140 (dict(years= -2, months= -11), '2 years and 11 months ago'),
140 (dict(years= -2, months= -11), '2 years and 11 months ago'),
141 (dict(years= -3, months= -2), '3 years and 2 months ago'),
141 (dict(years= -3, months= -2), '3 years and 2 months ago'),
142 ])
142 ])
143 def test_age(self, age_args, expected):
143 def test_age(self, age_args, expected):
144 from kallithea.lib.webutils import age
144 from kallithea.lib.webutils import age
145 with test_context(self.app):
145 with test_context(self.app):
146 n = datetime.datetime(year=2012, month=5, day=17)
146 n = datetime.datetime(year=2012, month=5, day=17)
147 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
147 assert age(n + relativedelta.relativedelta(**age_args), now=n) == expected
148 assert age(n + delt(**age_args), now=n) == expected
149
148
150 @base.parametrize('age_args,expected', [
149 @base.parametrize('age_args,expected', [
151 (dict(), 'just now'),
150 (dict(), 'just now'),
152 (dict(seconds= -1), '1 second ago'),
151 (dict(seconds= -1), '1 second ago'),
153 (dict(seconds= -60 * 2), '2 minutes ago'),
152 (dict(seconds= -60 * 2), '2 minutes ago'),
154 (dict(hours= -1), '1 hour ago'),
153 (dict(hours= -1), '1 hour ago'),
155 (dict(hours= -24), '1 day ago'),
154 (dict(hours= -24), '1 day ago'),
156 (dict(hours= -24 * 5), '5 days ago'),
155 (dict(hours= -24 * 5), '5 days ago'),
157 (dict(months= -1), '1 month ago'),
156 (dict(months= -1), '1 month ago'),
158 (dict(months= -1, days= -2), '1 month ago'),
157 (dict(months= -1, days= -2), '1 month ago'),
159 (dict(months= -1, days= -20), '1 month ago'),
158 (dict(months= -1, days= -20), '1 month ago'),
160 (dict(years= -1, months= -1), '13 months ago'),
159 (dict(years= -1, months= -1), '13 months ago'),
161 (dict(years= -1, months= -10), '22 months ago'),
160 (dict(years= -1, months= -10), '22 months ago'),
162 (dict(years= -2, months= -4), '2 years ago'),
161 (dict(years= -2, months= -4), '2 years ago'),
163 (dict(years= -2, months= -11), '3 years ago'),
162 (dict(years= -2, months= -11), '3 years ago'),
164 (dict(years= -3, months= -2), '3 years ago'),
163 (dict(years= -3, months= -2), '3 years ago'),
165 (dict(years= -4, months= -8), '5 years ago'),
164 (dict(years= -4, months= -8), '5 years ago'),
166 ])
165 ])
167 def test_age_short(self, age_args, expected):
166 def test_age_short(self, age_args, expected):
168 from kallithea.lib.webutils import age
167 from kallithea.lib.webutils import age
169 with test_context(self.app):
168 with test_context(self.app):
170 n = datetime.datetime(year=2012, month=5, day=17)
169 n = datetime.datetime(year=2012, month=5, day=17)
171 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
170 assert age(n + relativedelta.relativedelta(**age_args), show_short_version=True, now=n) == expected
172 assert age(n + delt(**age_args), show_short_version=True, now=n) == expected
173
171
174 @base.parametrize('age_args,expected', [
172 @base.parametrize('age_args,expected', [
175 (dict(), 'just now'),
173 (dict(), 'just now'),
176 (dict(seconds=1), 'in 1 second'),
174 (dict(seconds=1), 'in 1 second'),
177 (dict(seconds=60 * 2), 'in 2 minutes'),
175 (dict(seconds=60 * 2), 'in 2 minutes'),
178 (dict(hours=1), 'in 1 hour'),
176 (dict(hours=1), 'in 1 hour'),
179 (dict(hours=24), 'in 1 day'),
177 (dict(hours=24), 'in 1 day'),
180 (dict(hours=24 * 5), 'in 5 days'),
178 (dict(hours=24 * 5), 'in 5 days'),
181 (dict(months=1), 'in 1 month'),
179 (dict(months=1), 'in 1 month'),
182 (dict(months=1, days=1), 'in 1 month and 1 day'),
180 (dict(months=1, days=1), 'in 1 month and 1 day'),
183 (dict(years=1, months=1), 'in 1 year and 1 month')
181 (dict(years=1, months=1), 'in 1 year and 1 month')
184 ])
182 ])
185 def test_age_in_future(self, age_args, expected):
183 def test_age_in_future(self, age_args, expected):
186 from kallithea.lib.webutils import age
184 from kallithea.lib.webutils import age
187 with test_context(self.app):
185 with test_context(self.app):
188 n = datetime.datetime(year=2012, month=5, day=17)
186 n = datetime.datetime(year=2012, month=5, day=17)
189 delt = lambda *args, **kwargs: relativedelta.relativedelta(*args, **kwargs)
187 assert age(n + relativedelta.relativedelta(**age_args), now=n) == expected
190 assert age(n + delt(**age_args), now=n) == expected
191
188
192 def test_tag_extractor(self):
189 def test_tag_extractor(self):
193 sample = (
190 sample = (
194 "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
191 "hello pta[tag] gog [[]] [[] sda ero[or]d [me =>>< sa]"
195 "[requires] [stale] [see<>=>] [see => http://example.com]"
192 "[requires] [stale] [see<>=>] [see => http://example.com]"
196 "[requires => url] [lang => python] [just a tag]"
193 "[requires => url] [lang => python] [just a tag]"
197 "[,d] [ => ULR ] [obsolete] [desc]]"
194 "[,d] [ => ULR ] [obsolete] [desc]]"
198 )
195 )
199 res = webutils.urlify_text(sample, stylize=True)
196 res = webutils.urlify_text(sample, stylize=True)
200 assert '<div class="label label-meta" data-tag="tag">tag</div>' in res
197 assert '<div class="label label-meta" data-tag="tag">tag</div>' in res
201 assert '<div class="label label-meta" data-tag="obsolete">obsolete</div>' in res
198 assert '<div class="label label-meta" data-tag="obsolete">obsolete</div>' in res
202 assert '<div class="label label-meta" data-tag="stale">stale</div>' in res
199 assert '<div class="label label-meta" data-tag="stale">stale</div>' in res
203 assert '<div class="label label-meta" data-tag="lang">python</div>' in res
200 assert '<div class="label label-meta" data-tag="lang">python</div>' in res
204 assert '<div class="label label-meta" data-tag="requires">requires =&gt; <a href="/url">url</a></div>' in res
201 assert '<div class="label label-meta" data-tag="requires">requires =&gt; <a href="/url">url</a></div>' in res
205 assert '<div class="label label-meta" data-tag="tag">tag</div>' in res
202 assert '<div class="label label-meta" data-tag="tag">tag</div>' in res
206
203
207 def test_alternative_gravatar(self):
204 def test_alternative_gravatar(self):
208 _md5 = lambda s: hashlib.md5(safe_bytes(s)).hexdigest()
205 def _md5(s):
206 return hashlib.md5(safe_bytes(s)).hexdigest()
209
207
210 # mock tg.tmpl_context
208 # mock tg.tmpl_context
211 def fake_tmpl_context(_url):
209 def fake_tmpl_context(_url):
212 _c = AttributeDict()
210 _c = AttributeDict()
213 _c.visual = AttributeDict()
211 _c.visual = AttributeDict()
214 _c.visual.use_gravatar = True
212 _c.visual.use_gravatar = True
215 _c.visual.gravatar_url = _url
213 _c.visual.gravatar_url = _url
216
214
217 return _c
215 return _c
218
216
219 with mock.patch('kallithea.lib.webutils.url.current', lambda *a, **b: 'https://example.com'):
217 with mock.patch('kallithea.lib.webutils.url.current', lambda *a, **b: 'https://example.com'):
220 fake = fake_tmpl_context(_url='http://example.com/{email}')
218 fake = fake_tmpl_context(_url='http://example.com/{email}')
221 with mock.patch('kallithea.lib.helpers.c', fake):
219 with mock.patch('kallithea.lib.helpers.c', fake):
222 assert webutils.url.current() == 'https://example.com'
220 assert webutils.url.current() == 'https://example.com'
223 grav = h.gravatar_url(email_address='test@example.com', size=24)
221 grav = h.gravatar_url(email_address='test@example.com', size=24)
224 assert grav == 'http://example.com/test@example.com'
222 assert grav == 'http://example.com/test@example.com'
225
223
226 fake = fake_tmpl_context(_url='http://example.com/{email}')
224 fake = fake_tmpl_context(_url='http://example.com/{email}')
227 with mock.patch('kallithea.lib.helpers.c', fake):
225 with mock.patch('kallithea.lib.helpers.c', fake):
228 grav = h.gravatar_url(email_address='test@example.com', size=24)
226 grav = h.gravatar_url(email_address='test@example.com', size=24)
229 assert grav == 'http://example.com/test@example.com'
227 assert grav == 'http://example.com/test@example.com'
230
228
231 fake = fake_tmpl_context(_url='http://example.com/{md5email}')
229 fake = fake_tmpl_context(_url='http://example.com/{md5email}')
232 with mock.patch('kallithea.lib.helpers.c', fake):
230 with mock.patch('kallithea.lib.helpers.c', fake):
233 em = 'test@example.com'
231 em = 'test@example.com'
234 grav = h.gravatar_url(email_address=em, size=24)
232 grav = h.gravatar_url(email_address=em, size=24)
235 assert grav == 'http://example.com/%s' % (_md5(em))
233 assert grav == 'http://example.com/%s' % (_md5(em))
236
234
237 fake = fake_tmpl_context(_url='http://example.com/{md5email}/{size}')
235 fake = fake_tmpl_context(_url='http://example.com/{md5email}/{size}')
238 with mock.patch('kallithea.lib.helpers.c', fake):
236 with mock.patch('kallithea.lib.helpers.c', fake):
239 em = 'test@example.com'
237 em = 'test@example.com'
240 grav = h.gravatar_url(email_address=em, size=24)
238 grav = h.gravatar_url(email_address=em, size=24)
241 assert grav == 'http://example.com/%s/%s' % (_md5(em), 24)
239 assert grav == 'http://example.com/%s/%s' % (_md5(em), 24)
242
240
243 fake = fake_tmpl_context(_url='{scheme}://{netloc}/{md5email}/{size}')
241 fake = fake_tmpl_context(_url='{scheme}://{netloc}/{md5email}/{size}')
244 with mock.patch('kallithea.lib.helpers.c', fake):
242 with mock.patch('kallithea.lib.helpers.c', fake):
245 em = 'test@example.com'
243 em = 'test@example.com'
246 grav = h.gravatar_url(email_address=em, size=24)
244 grav = h.gravatar_url(email_address=em, size=24)
247 assert grav == 'https://example.com/%s/%s' % (_md5(em), 24)
245 assert grav == 'https://example.com/%s/%s' % (_md5(em), 24)
248
246
249 @base.parametrize('clone_uri_tmpl,repo_name,username,prefix,expected', [
247 @base.parametrize('clone_uri_tmpl,repo_name,username,prefix,expected', [
250 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '', 'http://vps1:8000/group/repo1'),
248 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '', 'http://vps1:8000/group/repo1'),
251 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '', 'http://username@vps1:8000/group/repo1'),
249 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '', 'http://username@vps1:8000/group/repo1'),
252 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '/prefix', 'http://vps1:8000/prefix/group/repo1'),
250 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', None, '/prefix', 'http://vps1:8000/prefix/group/repo1'),
253 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix', 'http://user@vps1:8000/prefix/group/repo1'),
251 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix', 'http://user@vps1:8000/prefix/group/repo1'),
254 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix', 'http://username@vps1:8000/prefix/group/repo1'),
252 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix', 'http://username@vps1:8000/prefix/group/repo1'),
255 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix/', 'http://user@vps1:8000/prefix/group/repo1'),
253 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'user', '/prefix/', 'http://user@vps1:8000/prefix/group/repo1'),
256 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix/', 'http://username@vps1:8000/prefix/group/repo1'),
254 (db.Repository.DEFAULT_CLONE_URI, 'group/repo1', 'username', '/prefix/', 'http://username@vps1:8000/prefix/group/repo1'),
257 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', None, '', 'http://vps1:8000/_23'),
255 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', None, '', 'http://vps1:8000/_23'),
258 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://username@vps1:8000/_23'),
256 ('{scheme}://{user}@{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://username@vps1:8000/_23'),
259 ('http://{user}@{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://username@vps1:8000/_23'),
257 ('http://{user}@{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://username@vps1:8000/_23'),
260 ('http://{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://vps1:8000/_23'),
258 ('http://{netloc}/_{repoid}', 'group/repo1', 'username', '', 'http://vps1:8000/_23'),
261 ('https://{user}@proxy1.example.com/{repo}', 'group/repo1', 'username', '', 'https://username@proxy1.example.com/group/repo1'),
259 ('https://{user}@proxy1.example.com/{repo}', 'group/repo1', 'username', '', 'https://username@proxy1.example.com/group/repo1'),
262 ('https://{user}@proxy1.example.com/{repo}', 'group/repo1', None, '', 'https://proxy1.example.com/group/repo1'),
260 ('https://{user}@proxy1.example.com/{repo}', 'group/repo1', None, '', 'https://proxy1.example.com/group/repo1'),
263 ('https://proxy1.example.com/{user}/{repo}', 'group/repo1', 'username', '', 'https://proxy1.example.com/username/group/repo1'),
261 ('https://proxy1.example.com/{user}/{repo}', 'group/repo1', 'username', '', 'https://proxy1.example.com/username/group/repo1'),
264 ])
262 ])
265 def test_clone_url_generator(self, clone_uri_tmpl, repo_name, username, prefix, expected):
263 def test_clone_url_generator(self, clone_uri_tmpl, repo_name, username, prefix, expected):
266 clone_url = get_clone_url(clone_uri_tmpl=clone_uri_tmpl, prefix_url='http://vps1:8000' + prefix,
264 clone_url = get_clone_url(clone_uri_tmpl=clone_uri_tmpl, prefix_url='http://vps1:8000' + prefix,
267 repo_name=repo_name, repo_id=23, username=username)
265 repo_name=repo_name, repo_id=23, username=username)
268 assert clone_url == expected
266 assert clone_url == expected
269
267
270 def _quick_url(self, text, tmpl="""<a class="changeset_hash" href="%s">%s</a>""", url_=None):
268 def _quick_url(self, text, tmpl="""<a class="changeset_hash" href="%s">%s</a>""", url_=None):
271 """
269 """
272 Changes `some text url[foo]` => `some text <a href="/">foo</a>
270 Changes `some text url[foo]` => `some text <a href="/">foo</a>
273
271
274 :param text:
272 :param text:
275 """
273 """
276 # quickly change expected url[] into a link
274 # quickly change expected url[] into a link
277 url_pattern = re.compile(r'(?:url\[)(.+?)(?:\])')
275 url_pattern = re.compile(r'(?:url\[)(.+?)(?:\])')
278
276
279 def url_func(match_obj):
277 def url_func(match_obj):
280 _url = match_obj.groups()[0]
278 _url = match_obj.groups()[0]
281 return tmpl % (url_ or '/repo_name/changeset/%s' % _url, _url)
279 return tmpl % (url_ or '/repo_name/changeset/%s' % _url, _url)
282 return url_pattern.sub(url_func, text)
280 return url_pattern.sub(url_func, text)
283
281
284 @base.parametrize('sample,expected', [
282 @base.parametrize('sample,expected', [
285 ("",
283 ("",
286 ""),
284 ""),
287 ("git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
285 ("git-svn-id: https://svn.apache.org/repos/asf/libcloud/trunk@1441655 13f79535-47bb-0310-9956-ffa450edef68",
288 """git-svn-id: <a href="https://svn.apache.org/repos/asf/libcloud/trunk@1441655">https://svn.apache.org/repos/asf/libcloud/trunk@1441655</a> 13f79535-47bb-0310-9956-ffa450edef68"""),
286 """git-svn-id: <a href="https://svn.apache.org/repos/asf/libcloud/trunk@1441655">https://svn.apache.org/repos/asf/libcloud/trunk@1441655</a> 13f79535-47bb-0310-9956-ffa450edef68"""),
289 ("from rev 000000000000",
287 ("from rev 000000000000",
290 """from rev url[000000000000]"""),
288 """from rev url[000000000000]"""),
291 ("from rev 000000000000123123 also rev 000000000000",
289 ("from rev 000000000000123123 also rev 000000000000",
292 """from rev url[000000000000123123] also rev url[000000000000]"""),
290 """from rev url[000000000000123123] also rev url[000000000000]"""),
293 ("this should-000 00",
291 ("this should-000 00",
294 """this should-000 00"""),
292 """this should-000 00"""),
295 ("longtextffffffffff rev 123123123123",
293 ("longtextffffffffff rev 123123123123",
296 """longtextffffffffff rev url[123123123123]"""),
294 """longtextffffffffff rev url[123123123123]"""),
297 ("rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
295 ("rev ffffffffffffffffffffffffffffffffffffffffffffffffff",
298 """rev ffffffffffffffffffffffffffffffffffffffffffffffffff"""),
296 """rev ffffffffffffffffffffffffffffffffffffffffffffffffff"""),
299 ("ffffffffffff some text traalaa",
297 ("ffffffffffff some text traalaa",
300 """url[ffffffffffff] some text traalaa"""),
298 """url[ffffffffffff] some text traalaa"""),
301 ("""Multi line
299 ("""Multi line
302 123123123123
300 123123123123
303 some text 123123123123
301 some text 123123123123
304 sometimes !
302 sometimes !
305 """,
303 """,
306 """Multi line<br/>"""
304 """Multi line<br/>"""
307 """ url[123123123123]<br/>"""
305 """ url[123123123123]<br/>"""
308 """ some text url[123123123123]<br/>"""
306 """ some text url[123123123123]<br/>"""
309 """ sometimes !"""),
307 """ sometimes !"""),
310 ])
308 ])
311 def test_urlify_text(self, sample, expected):
309 def test_urlify_text(self, sample, expected):
312 expected = self._quick_url(expected)
310 expected = self._quick_url(expected)
313
311
314 with mock.patch('kallithea.lib.webutils.UrlGenerator.__call__',
312 with mock.patch('kallithea.lib.webutils.UrlGenerator.__call__',
315 lambda self, name, **kwargs: dict(changeset_home='/%(repo_name)s/changeset/%(revision)s')[name] % kwargs,
313 lambda self, name, **kwargs: dict(changeset_home='/%(repo_name)s/changeset/%(revision)s')[name] % kwargs,
316 ):
314 ):
317 assert webutils.urlify_text(sample, 'repo_name') == expected
315 assert webutils.urlify_text(sample, 'repo_name') == expected
318
316
319 @base.parametrize('sample,expected,url_', [
317 @base.parametrize('sample,expected,url_', [
320 ("",
318 ("",
321 "",
319 "",
322 ""),
320 ""),
323 ("https://svn.apache.org/repos",
321 ("https://svn.apache.org/repos",
324 """url[https://svn.apache.org/repos]""",
322 """url[https://svn.apache.org/repos]""",
325 "https://svn.apache.org/repos"),
323 "https://svn.apache.org/repos"),
326 ("http://svn.apache.org/repos",
324 ("http://svn.apache.org/repos",
327 """url[http://svn.apache.org/repos]""",
325 """url[http://svn.apache.org/repos]""",
328 "http://svn.apache.org/repos"),
326 "http://svn.apache.org/repos"),
329 ("from rev a also rev http://google.com",
327 ("from rev a also rev http://google.com",
330 """from rev a also rev url[http://google.com]""",
328 """from rev a also rev url[http://google.com]""",
331 "http://google.com"),
329 "http://google.com"),
332 ("http://imgur.com/foo.gif inline http://imgur.com/foo.gif ending http://imgur.com/foo.gif",
330 ("http://imgur.com/foo.gif inline http://imgur.com/foo.gif ending http://imgur.com/foo.gif",
333 """url[http://imgur.com/foo.gif] inline url[http://imgur.com/foo.gif] ending url[http://imgur.com/foo.gif]""",
331 """url[http://imgur.com/foo.gif] inline url[http://imgur.com/foo.gif] ending url[http://imgur.com/foo.gif]""",
334 "http://imgur.com/foo.gif"),
332 "http://imgur.com/foo.gif"),
335 ("""Multi line
333 ("""Multi line
336 https://foo.bar.example.com
334 https://foo.bar.example.com
337 some text lalala""",
335 some text lalala""",
338 """Multi line<br/>"""
336 """Multi line<br/>"""
339 """ url[https://foo.bar.example.com]<br/>"""
337 """ url[https://foo.bar.example.com]<br/>"""
340 """ some text lalala""",
338 """ some text lalala""",
341 "https://foo.bar.example.com"),
339 "https://foo.bar.example.com"),
342 ("@mention @someone",
340 ("@mention @someone",
343 """<b>@mention</b> <b>@someone</b>""",
341 """<b>@mention</b> <b>@someone</b>""",
344 ""),
342 ""),
345 ("deadbeefcafe 123412341234",
343 ("deadbeefcafe 123412341234",
346 """<a class="changeset_hash" href="/repo_name/changeset/deadbeefcafe">deadbeefcafe</a> <a class="changeset_hash" href="/repo_name/changeset/123412341234">123412341234</a>""",
344 """<a class="changeset_hash" href="/repo_name/changeset/deadbeefcafe">deadbeefcafe</a> <a class="changeset_hash" href="/repo_name/changeset/123412341234">123412341234</a>""",
347 ""),
345 ""),
348 ("We support * markup for *bold* markup of *single or multiple* words, "
346 ("We support * markup for *bold* markup of *single or multiple* words, "
349 "*a bit @like http://slack.com*. "
347 "*a bit @like http://slack.com*. "
350 "The first * must come after whitespace and not be followed by whitespace, "
348 "The first * must come after whitespace and not be followed by whitespace, "
351 "contain anything but * and newline until the next *, "
349 "contain anything but * and newline until the next *, "
352 "which must not come after whitespace "
350 "which must not come after whitespace "
353 "and not be followed by * or alphanumerical *characters*.",
351 "and not be followed by * or alphanumerical *characters*.",
354 """We support * markup for <b>*bold*</b> markup of <b>*single or multiple*</b> words, """
352 """We support * markup for <b>*bold*</b> markup of <b>*single or multiple*</b> words, """
355 """<b>*a bit <b>@like</b> <a href="http://slack.com">http://slack.com</a>*</b>. """
353 """<b>*a bit <b>@like</b> <a href="http://slack.com">http://slack.com</a>*</b>. """
356 """The first * must come after whitespace and not be followed by whitespace, """
354 """The first * must come after whitespace and not be followed by whitespace, """
357 """contain anything but * and newline until the next *, """
355 """contain anything but * and newline until the next *, """
358 """which must not come after whitespace """
356 """which must not come after whitespace """
359 """and not be followed by * or alphanumerical <b>*characters*</b>.""",
357 """and not be followed by * or alphanumerical <b>*characters*</b>.""",
360 "-"),
358 "-"),
361 ("HTML escaping: <abc> 'single' \"double\" &pointer",
359 ("HTML escaping: <abc> 'single' \"double\" &pointer",
362 "HTML escaping: &lt;abc&gt; &#39;single&#39; &quot;double&quot; &amp;pointer",
360 "HTML escaping: &lt;abc&gt; &#39;single&#39; &quot;double&quot; &amp;pointer",
363 "-"),
361 "-"),
364 # tags are covered by test_tag_extractor
362 # tags are covered by test_tag_extractor
365 ])
363 ])
366 def test_urlify_test(self, sample, expected, url_):
364 def test_urlify_test(self, sample, expected, url_):
367 expected = self._quick_url(expected,
365 expected = self._quick_url(expected,
368 tmpl="""<a href="%s">%s</a>""", url_=url_)
366 tmpl="""<a href="%s">%s</a>""", url_=url_)
369 with mock.patch('kallithea.lib.webutils.UrlGenerator.__call__',
367 with mock.patch('kallithea.lib.webutils.UrlGenerator.__call__',
370 lambda self, name, **kwargs: dict(changeset_home='/%(repo_name)s/changeset/%(revision)s')[name] % kwargs,
368 lambda self, name, **kwargs: dict(changeset_home='/%(repo_name)s/changeset/%(revision)s')[name] % kwargs,
371 ):
369 ):
372 assert webutils.urlify_text(sample, 'repo_name', stylize=True) == expected
370 assert webutils.urlify_text(sample, 'repo_name', stylize=True) == expected
373
371
374 @base.parametrize('sample,expected', [
372 @base.parametrize('sample,expected', [
375 ("deadbeefcafe @mention, and http://foo.bar/ yo",
373 ("deadbeefcafe @mention, and http://foo.bar/ yo",
376 """<a class="changeset_hash" href="/repo_name/changeset/deadbeefcafe">deadbeefcafe</a>"""
374 """<a class="changeset_hash" href="/repo_name/changeset/deadbeefcafe">deadbeefcafe</a>"""
377 """<a class="message-link" href="#the-link"> <b>@mention</b>, and </a>"""
375 """<a class="message-link" href="#the-link"> <b>@mention</b>, and </a>"""
378 """<a href="http://foo.bar/">http://foo.bar/</a>"""
376 """<a href="http://foo.bar/">http://foo.bar/</a>"""
379 """<a class="message-link" href="#the-link"> yo</a>"""),
377 """<a class="message-link" href="#the-link"> yo</a>"""),
380 ])
378 ])
381 def test_urlify_link(self, sample, expected):
379 def test_urlify_link(self, sample, expected):
382 with mock.patch('kallithea.lib.webutils.UrlGenerator.__call__',
380 with mock.patch('kallithea.lib.webutils.UrlGenerator.__call__',
383 lambda self, name, **kwargs: dict(changeset_home='/%(repo_name)s/changeset/%(revision)s')[name] % kwargs,
381 lambda self, name, **kwargs: dict(changeset_home='/%(repo_name)s/changeset/%(revision)s')[name] % kwargs,
384 ):
382 ):
385 assert webutils.urlify_text(sample, 'repo_name', link_='#the-link') == expected
383 assert webutils.urlify_text(sample, 'repo_name', link_='#the-link') == expected
386
384
387 @base.parametrize('issue_pat,issue_server,issue_sub,sample,expected', [
385 @base.parametrize('issue_pat,issue_server,issue_sub,sample,expected', [
388 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
386 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
389 'issue #123 and issue#456',
387 'issue #123 and issue#456',
390 """issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
388 """issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
391 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/456">#456</a>"""),
389 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/456">#456</a>"""),
392 (r'(?:\s*#)(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
390 (r'(?:\s*#)(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
393 'issue #123 and issue#456',
391 'issue #123 and issue#456',
394 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
392 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
395 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/456">#456</a>"""),
393 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/456">#456</a>"""),
396 # to require whitespace before the issue reference, one may be tempted to use \b...
394 # to require whitespace before the issue reference, one may be tempted to use \b...
397 (r'\bPR(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
395 (r'\bPR(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
398 'issue PR123 and issuePR456',
396 'issue PR123 and issuePR456',
399 """issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
397 """issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
400 """issuePR456"""),
398 """issuePR456"""),
401 # ... but it turns out that \b does not work well in combination with '#': the expectations
399 # ... but it turns out that \b does not work well in combination with '#': the expectations
402 # are reversed from what is actually happening.
400 # are reversed from what is actually happening.
403 (r'\b#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
401 (r'\b#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
404 'issue #123 and issue#456',
402 'issue #123 and issue#456',
405 """issue #123 and """
403 """issue #123 and """
406 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/456">#456</a>"""),
404 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/456">#456</a>"""),
407 # ... so maybe try to be explicit? Unfortunately the whitespace before the issue
405 # ... so maybe try to be explicit? Unfortunately the whitespace before the issue
408 # reference is not retained, again, because it is part of the pattern.
406 # reference is not retained, again, because it is part of the pattern.
409 (r'(?:^|\s)#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
407 (r'(?:^|\s)#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
410 '#15 and issue #123 and issue#456',
408 '#15 and issue #123 and issue#456',
411 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/15">#15</a> and """
409 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/15">#15</a> and """
412 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
410 """issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
413 """issue#456"""),
411 """issue#456"""),
414 # ... instead, use lookbehind assertions.
412 # ... instead, use lookbehind assertions.
415 (r'(?:^|(?<=\s))#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
413 (r'(?:^|(?<=\s))#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
416 '#15 and issue #123 and issue#456',
414 '#15 and issue #123 and issue#456',
417 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/15">#15</a> and """
415 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/15">#15</a> and """
418 """issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
416 """issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> and """
419 """issue#456"""),
417 """issue#456"""),
420 (r'(?:pullrequest|pull request|PR|pr) ?#?(\d+)', 'http://foo/{repo}/issue/\\1', 'PR#\\1',
418 (r'(?:pullrequest|pull request|PR|pr) ?#?(\d+)', 'http://foo/{repo}/issue/\\1', 'PR#\\1',
421 'fixed with pullrequest #1, pull request#2, PR 3, pr4',
419 'fixed with pullrequest #1, pull request#2, PR 3, pr4',
422 """fixed with <a class="issue-tracker-link" href="http://foo/repo_name/issue/1">PR#1</a>, """
420 """fixed with <a class="issue-tracker-link" href="http://foo/repo_name/issue/1">PR#1</a>, """
423 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/2">PR#2</a>, """
421 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/2">PR#2</a>, """
424 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/3">PR#3</a>, """
422 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/3">PR#3</a>, """
425 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/4">PR#4</a>"""),
423 """<a class="issue-tracker-link" href="http://foo/repo_name/issue/4">PR#4</a>"""),
426 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', 'PR\\1',
424 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', 'PR\\1',
427 'interesting issue #123',
425 'interesting issue #123',
428 """interesting issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">PR123</a>"""),
426 """interesting issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">PR123</a>"""),
429 (r'BUG\d{5}', 'https://bar/{repo}/\\1', '\\1',
427 (r'BUG\d{5}', 'https://bar/{repo}/\\1', '\\1',
430 'silly me, I did not parenthesize the id, BUG12345.',
428 'silly me, I did not parenthesize the id, BUG12345.',
431 """silly me, I did not parenthesize the id, <a class="issue-tracker-link" href="https://bar/repo_name/\\1">BUG12345</a>."""),
429 """silly me, I did not parenthesize the id, <a class="issue-tracker-link" href="https://bar/repo_name/\\1">BUG12345</a>."""),
432 (r'BUG(\d{5})', 'https://bar/{repo}/', 'BUG\\1',
430 (r'BUG(\d{5})', 'https://bar/{repo}/', 'BUG\\1',
433 'silly me, the URL does not contain id, BUG12345.',
431 'silly me, the URL does not contain id, BUG12345.',
434 """silly me, the URL does not contain id, <a class="issue-tracker-link" href="https://bar/repo_name/">BUG12345</a>."""),
432 """silly me, the URL does not contain id, <a class="issue-tracker-link" href="https://bar/repo_name/">BUG12345</a>."""),
435 (r'(PR-\d+)', 'http://foo/{repo}/issue/\\1', '',
433 (r'(PR-\d+)', 'http://foo/{repo}/issue/\\1', '',
436 'interesting issue #123, err PR-56',
434 'interesting issue #123, err PR-56',
437 """interesting issue #123, err <a class="issue-tracker-link" href="http://foo/repo_name/issue/PR-56">PR-56</a>"""),
435 """interesting issue #123, err <a class="issue-tracker-link" href="http://foo/repo_name/issue/PR-56">PR-56</a>"""),
438 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
436 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
439 "some 'standard' text with apostrophes",
437 "some 'standard' text with apostrophes",
440 """some &#39;standard&#39; text with apostrophes"""),
438 """some &#39;standard&#39; text with apostrophes"""),
441 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
439 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
442 "some 'standard' issue #123",
440 "some 'standard' issue #123",
443 """some &#39;standard&#39; issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a>"""),
441 """some &#39;standard&#39; issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a>"""),
444 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
442 (r'#(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
445 'an issue #123 with extra whitespace',
443 'an issue #123 with extra whitespace',
446 """an issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> with extra whitespace"""),
444 """an issue <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> with extra whitespace"""),
447 (r'(?:\s*#)(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
445 (r'(?:\s*#)(\d+)', 'http://foo/{repo}/issue/\\1', '#\\1',
448 'an issue #123 with extra whitespace',
446 'an issue #123 with extra whitespace',
449 """an issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> with extra whitespace"""),
447 """an issue<a class="issue-tracker-link" href="http://foo/repo_name/issue/123">#123</a> with extra whitespace"""),
450 # invalid issue pattern
448 # invalid issue pattern
451 (r'(PR\d+', 'http://foo/{repo}/issue/{id}', '',
449 (r'(PR\d+', 'http://foo/{repo}/issue/{id}', '',
452 'PR135',
450 'PR135',
453 """PR135"""),
451 """PR135"""),
454 # other character than #
452 # other character than #
455 (r'(?:^|(?<=\s))\$(\d+)', 'http://foo/{repo}/issue/\\1', '',
453 (r'(?:^|(?<=\s))\$(\d+)', 'http://foo/{repo}/issue/\\1', '',
456 'empty issue_sub $123 and issue$456',
454 'empty issue_sub $123 and issue$456',
457 """empty issue_sub <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">$123</a> and """
455 """empty issue_sub <a class="issue-tracker-link" href="http://foo/repo_name/issue/123">$123</a> and """
458 """issue$456"""),
456 """issue$456"""),
459 # named groups
457 # named groups
460 (r'(PR|pullrequest|pull request) ?(?P<sitecode>BRU|CPH|BER)-(?P<id>\d+)', r'http://foo/\g<sitecode>/pullrequest/\g<id>/', r'PR-\g<sitecode>-\g<id>',
458 (r'(PR|pullrequest|pull request) ?(?P<sitecode>BRU|CPH|BER)-(?P<id>\d+)', r'http://foo/\g<sitecode>/pullrequest/\g<id>/', r'PR-\g<sitecode>-\g<id>',
461 'pullrequest CPH-789 is similar to PRBRU-747',
459 'pullrequest CPH-789 is similar to PRBRU-747',
462 """<a class="issue-tracker-link" href="http://foo/CPH/pullrequest/789/">PR-CPH-789</a> is similar to """
460 """<a class="issue-tracker-link" href="http://foo/CPH/pullrequest/789/">PR-CPH-789</a> is similar to """
463 """<a class="issue-tracker-link" href="http://foo/BRU/pullrequest/747/">PR-BRU-747</a>"""),
461 """<a class="issue-tracker-link" href="http://foo/BRU/pullrequest/747/">PR-BRU-747</a>"""),
464 ])
462 ])
465 def test_urlify_issues(self, issue_pat, issue_server, issue_sub, sample, expected):
463 def test_urlify_issues(self, issue_pat, issue_server, issue_sub, sample, expected):
466 config_stub = {
464 config_stub = {
467 'sqlalchemy.url': 'foo',
465 'sqlalchemy.url': 'foo',
468 'issue_pat': issue_pat,
466 'issue_pat': issue_pat,
469 'issue_server_link': issue_server,
467 'issue_server_link': issue_server,
470 'issue_sub': issue_sub,
468 'issue_sub': issue_sub,
471 }
469 }
472 # force recreation of lazy function
470 # force recreation of lazy function
473 with mock.patch('kallithea.lib.webutils._urlify_issues_f', None):
471 with mock.patch('kallithea.lib.webutils._urlify_issues_f', None):
474 with mock.patch('kallithea.CONFIG', config_stub):
472 with mock.patch('kallithea.CONFIG', config_stub):
475 assert webutils.urlify_text(sample, 'repo_name') == expected
473 assert webutils.urlify_text(sample, 'repo_name') == expected
476
474
477 @base.parametrize('sample,expected', [
475 @base.parametrize('sample,expected', [
478 ('abc X5', 'abc <a class="issue-tracker-link" href="http://main/repo_name/main/5/">#5</a>'),
476 ('abc X5', 'abc <a class="issue-tracker-link" href="http://main/repo_name/main/5/">#5</a>'),
479 ('abc pullrequest #6 xyz', 'abc <a class="issue-tracker-link" href="http://pr/repo_name/pr/6">PR#6</a> xyz'),
477 ('abc pullrequest #6 xyz', 'abc <a class="issue-tracker-link" href="http://pr/repo_name/pr/6">PR#6</a> xyz'),
480 ('pull request7 #', '<a class="issue-tracker-link" href="http://pr/repo_name/pr/7">PR#7</a> #'),
478 ('pull request7 #', '<a class="issue-tracker-link" href="http://pr/repo_name/pr/7">PR#7</a> #'),
481 ('look PR9 and pr #11', 'look <a class="issue-tracker-link" href="http://pr/repo_name/pr/9">PR#9</a> and <a class="issue-tracker-link" href="http://pr/repo_name/pr/11">PR#11</a>'),
479 ('look PR9 and pr #11', 'look <a class="issue-tracker-link" href="http://pr/repo_name/pr/9">PR#9</a> and <a class="issue-tracker-link" href="http://pr/repo_name/pr/11">PR#11</a>'),
482 ('pullrequest#10 solves issue 9', '<a class="issue-tracker-link" href="http://pr/repo_name/pr/10">PR#10</a> solves <a class="issue-tracker-link" href="http://bug/repo_name/bug/9">bug#9</a>'),
480 ('pullrequest#10 solves issue 9', '<a class="issue-tracker-link" href="http://pr/repo_name/pr/10">PR#10</a> solves <a class="issue-tracker-link" href="http://bug/repo_name/bug/9">bug#9</a>'),
483 ('issue FAIL67', 'issue <a class="issue-tracker-link" href="http://fail/repo_name/67">FAIL67</a>'),
481 ('issue FAIL67', 'issue <a class="issue-tracker-link" href="http://fail/repo_name/67">FAIL67</a>'),
484 ('issue FAILMORE89', 'issue FAILMORE89'), # no match because absent prefix
482 ('issue FAILMORE89', 'issue FAILMORE89'), # no match because absent prefix
485 ])
483 ])
486 def test_urlify_issues_multiple_issue_patterns(self, sample, expected):
484 def test_urlify_issues_multiple_issue_patterns(self, sample, expected):
487 config_stub = {
485 config_stub = {
488 'sqlalchemy.url': r'foo',
486 'sqlalchemy.url': r'foo',
489 'issue_pat': r'X(\d+)',
487 'issue_pat': r'X(\d+)',
490 'issue_server_link': r'http://main/{repo}/main/\1/',
488 'issue_server_link': r'http://main/{repo}/main/\1/',
491 'issue_sub': r'#\1',
489 'issue_sub': r'#\1',
492 'issue_pat_pr': r'(?:pullrequest|pull request|PR|pr) ?#?(\d+)',
490 'issue_pat_pr': r'(?:pullrequest|pull request|PR|pr) ?#?(\d+)',
493 'issue_server_link_pr': r'http://pr/{repo}/pr/\1',
491 'issue_server_link_pr': r'http://pr/{repo}/pr/\1',
494 'issue_sub_pr': r'PR#\1',
492 'issue_sub_pr': r'PR#\1',
495 'issue_pat_bug': r'(?:BUG|bug|issue) ?#?(\d+)',
493 'issue_pat_bug': r'(?:BUG|bug|issue) ?#?(\d+)',
496 'issue_server_link_bug': r'http://bug/{repo}/bug/\1',
494 'issue_server_link_bug': r'http://bug/{repo}/bug/\1',
497 'issue_sub_bug': r'bug#\1',
495 'issue_sub_bug': r'bug#\1',
498 'issue_pat_empty_prefix': r'FAIL(\d+)',
496 'issue_pat_empty_prefix': r'FAIL(\d+)',
499 'issue_server_link_empty_prefix': r'http://fail/{repo}/\1',
497 'issue_server_link_empty_prefix': r'http://fail/{repo}/\1',
500 'issue_sub_empty_prefix': r'',
498 'issue_sub_empty_prefix': r'',
501 'issue_pat_absent_prefix': r'FAILMORE(\d+)',
499 'issue_pat_absent_prefix': r'FAILMORE(\d+)',
502 'issue_server_link_absent_prefix': r'http://failmore/{repo}/\1',
500 'issue_server_link_absent_prefix': r'http://failmore/{repo}/\1',
503 }
501 }
504 # force recreation of lazy function
502 # force recreation of lazy function
505 with mock.patch('kallithea.lib.webutils._urlify_issues_f', None):
503 with mock.patch('kallithea.lib.webutils._urlify_issues_f', None):
506 with mock.patch('kallithea.CONFIG', config_stub):
504 with mock.patch('kallithea.CONFIG', config_stub):
507 assert webutils.urlify_text(sample, 'repo_name') == expected
505 assert webutils.urlify_text(sample, 'repo_name') == expected
508
506
509 @base.parametrize('test,expected', [
507 @base.parametrize('test,expected', [
510 ("", None),
508 ("", None),
511 ("/_2", None),
509 ("/_2", None),
512 ("_2", 2),
510 ("_2", 2),
513 ("_2/", None),
511 ("_2/", None),
514 ])
512 ])
515 def test_get_permanent_id(self, test, expected):
513 def test_get_permanent_id(self, test, expected):
516 from kallithea.lib.utils import _get_permanent_id
514 from kallithea.lib.utils import _get_permanent_id
517 extracted = _get_permanent_id(test)
515 extracted = _get_permanent_id(test)
518 assert extracted == expected, 'url:%s, got:`%s` expected: `%s`' % (test, base._test, expected)
516 assert extracted == expected, 'url:%s, got:`%s` expected: `%s`' % (test, base._test, expected)
519
517
520 @base.parametrize('test,expected', [
518 @base.parametrize('test,expected', [
521 ("", ""),
519 ("", ""),
522 ("/", "/"),
520 ("/", "/"),
523 ("/_ID", '/_ID'),
521 ("/_ID", '/_ID'),
524 ("ID", "ID"),
522 ("ID", "ID"),
525 ("_ID", 'NAME'),
523 ("_ID", 'NAME'),
526 ("_ID/", 'NAME/'),
524 ("_ID/", 'NAME/'),
527 ("_ID/1/2", 'NAME/1/2'),
525 ("_ID/1/2", 'NAME/1/2'),
528 ("_IDa", '_IDa'),
526 ("_IDa", '_IDa'),
529 ])
527 ])
530 def test_fix_repo_id_name(self, test, expected):
528 def test_fix_repo_id_name(self, test, expected):
531 repo = db.Repository.get_by_repo_name(base.HG_REPO)
529 repo = db.Repository.get_by_repo_name(base.HG_REPO)
532 test = test.replace('ID', str(repo.repo_id))
530 test = test.replace('ID', str(repo.repo_id))
533 expected = expected.replace('NAME', repo.repo_name).replace('ID', str(repo.repo_id))
531 expected = expected.replace('NAME', repo.repo_name).replace('ID', str(repo.repo_id))
534 from kallithea.lib.utils import fix_repo_id_name
532 from kallithea.lib.utils import fix_repo_id_name
535 replaced = fix_repo_id_name(test)
533 replaced = fix_repo_id_name(test)
536 assert replaced == expected, 'url:%s, got:`%s` expected: `%s`' % (test, replaced, expected)
534 assert replaced == expected, 'url:%s, got:`%s` expected: `%s`' % (test, replaced, expected)
537
535
538 @base.parametrize('canonical,test,expected', [
536 @base.parametrize('canonical,test,expected', [
539 ('http://www.example.org/', '/abc/xyz', 'http://www.example.org/abc/xyz'),
537 ('http://www.example.org/', '/abc/xyz', 'http://www.example.org/abc/xyz'),
540 ('http://www.example.org', '/abc/xyz', 'http://www.example.org/abc/xyz'),
538 ('http://www.example.org', '/abc/xyz', 'http://www.example.org/abc/xyz'),
541 ('http://www.example.org', '/abc/xyz/', 'http://www.example.org/abc/xyz/'),
539 ('http://www.example.org', '/abc/xyz/', 'http://www.example.org/abc/xyz/'),
542 ('http://www.example.org', 'abc/xyz/', 'http://www.example.org/abc/xyz/'),
540 ('http://www.example.org', 'abc/xyz/', 'http://www.example.org/abc/xyz/'),
543 ('http://www.example.org', 'about', 'http://www.example.org/about-page'),
541 ('http://www.example.org', 'about', 'http://www.example.org/about-page'),
544 ('http://www.example.org/repos/', 'abc/xyz/', 'http://www.example.org/repos/abc/xyz/'),
542 ('http://www.example.org/repos/', 'abc/xyz/', 'http://www.example.org/repos/abc/xyz/'),
545 ('http://www.example.org/kallithea/repos/', 'abc/xyz/', 'http://www.example.org/kallithea/repos/abc/xyz/'),
543 ('http://www.example.org/kallithea/repos/', 'abc/xyz/', 'http://www.example.org/kallithea/repos/abc/xyz/'),
546 ])
544 ])
547 def test_canonical_url(self, canonical, test, expected):
545 def test_canonical_url(self, canonical, test, expected):
548 # setup url(), used by canonical_url
546 # setup url(), used by canonical_url
549 m = routes.Mapper()
547 m = routes.Mapper()
550 m.connect('about', '/about-page')
548 m.connect('about', '/about-page')
551 url = routes.URLGenerator(m, {'HTTP_HOST': 'http_host.example.org'})
549 url = routes.URLGenerator(m, {'HTTP_HOST': 'http_host.example.org'})
552
550
553 config_mock = {
551 config_mock = {
554 'canonical_url': canonical,
552 'canonical_url': canonical,
555 }
553 }
556
554
557 with test_context(self.app):
555 with test_context(self.app):
558 request.environ['routes.url'] = url
556 request.environ['routes.url'] = url
559 with mock.patch('kallithea.CONFIG', config_mock):
557 with mock.patch('kallithea.CONFIG', config_mock):
560 assert webutils.canonical_url(test) == expected
558 assert webutils.canonical_url(test) == expected
561
559
562 @base.parametrize('canonical,expected', [
560 @base.parametrize('canonical,expected', [
563 ('http://www.example.org', 'www.example.org'),
561 ('http://www.example.org', 'www.example.org'),
564 ('http://www.example.org/repos/', 'www.example.org'),
562 ('http://www.example.org/repos/', 'www.example.org'),
565 ('http://www.example.org/kallithea/repos/', 'www.example.org'),
563 ('http://www.example.org/kallithea/repos/', 'www.example.org'),
566 ])
564 ])
567 def test_canonical_hostname(self, canonical, expected):
565 def test_canonical_hostname(self, canonical, expected):
568 # setup url(), used by canonical_hostname
566 # setup url(), used by canonical_hostname
569 m = routes.Mapper()
567 m = routes.Mapper()
570 url = routes.URLGenerator(m, {'HTTP_HOST': 'http_host.example.org'})
568 url = routes.URLGenerator(m, {'HTTP_HOST': 'http_host.example.org'})
571
569
572 config_mock = {
570 config_mock = {
573 'canonical_url': canonical,
571 'canonical_url': canonical,
574 }
572 }
575
573
576 with test_context(self.app):
574 with test_context(self.app):
577 request.environ['routes.url'] = url
575 request.environ['routes.url'] = url
578 with mock.patch('kallithea.CONFIG', config_mock):
576 with mock.patch('kallithea.CONFIG', config_mock):
579 assert webutils.canonical_hostname() == expected
577 assert webutils.canonical_hostname() == expected
@@ -1,848 +1,849 b''
1 import datetime
1 import datetime
2 import os
2 import os
3 import sys
3 import sys
4
4
5 import mock
5 import mock
6 import pytest
6 import pytest
7
7
8 from kallithea.lib.vcs.backends.git import GitChangeset, GitRepository
8 from kallithea.lib.vcs.backends.git import GitChangeset, GitRepository
9 from kallithea.lib.vcs.exceptions import NodeDoesNotExistError, RepositoryError, VCSError
9 from kallithea.lib.vcs.exceptions import NodeDoesNotExistError, RepositoryError, VCSError
10 from kallithea.lib.vcs.nodes import DirNode, FileNode, NodeKind, NodeState
10 from kallithea.lib.vcs.nodes import DirNode, FileNode, NodeKind, NodeState
11 from kallithea.model.scm import ScmModel
11 from kallithea.model.scm import ScmModel
12 from kallithea.tests.vcs.base import _BackendTestMixin
12 from kallithea.tests.vcs.base import _BackendTestMixin
13 from kallithea.tests.vcs.conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, TESTS_TMP_PATH, get_new_dir
13 from kallithea.tests.vcs.conf import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, TESTS_TMP_PATH, get_new_dir
14
14
15
15
16 class TestGitRepository(object):
16 class TestGitRepository(object):
17
17
18 def __check_for_existing_repo(self):
18 def __check_for_existing_repo(self):
19 if os.path.exists(TEST_GIT_REPO_CLONE):
19 if os.path.exists(TEST_GIT_REPO_CLONE):
20 pytest.fail('Cannot test git clone repo as location %s already '
20 pytest.fail('Cannot test git clone repo as location %s already '
21 'exists. You should manually remove it first.'
21 'exists. You should manually remove it first.'
22 % TEST_GIT_REPO_CLONE)
22 % TEST_GIT_REPO_CLONE)
23
23
24 def setup_method(self):
24 def setup_method(self):
25 self.repo = GitRepository(TEST_GIT_REPO)
25 self.repo = GitRepository(TEST_GIT_REPO)
26
26
27 def test_wrong_repo_path(self):
27 def test_wrong_repo_path(self):
28 wrong_repo_path = os.path.join(TESTS_TMP_PATH, 'errorrepo')
28 wrong_repo_path = os.path.join(TESTS_TMP_PATH, 'errorrepo')
29 with pytest.raises(RepositoryError):
29 with pytest.raises(RepositoryError):
30 GitRepository(wrong_repo_path)
30 GitRepository(wrong_repo_path)
31
31
32 def test_git_cmd_injection(self):
32 def test_git_cmd_injection(self):
33 repo_inject_path = 'file:/%s; echo "Cake";' % TEST_GIT_REPO
33 repo_inject_path = 'file:/%s; echo "Cake";' % TEST_GIT_REPO
34 with pytest.raises(RepositoryError):
34 with pytest.raises(RepositoryError):
35 # Should fail because URL will contain the parts after ; too
35 # Should fail because URL will contain the parts after ; too
36 GitRepository(get_new_dir('injection-repo'), src_url=repo_inject_path, update_after_clone=True, create=True)
36 GitRepository(get_new_dir('injection-repo'), src_url=repo_inject_path, update_after_clone=True, create=True)
37
37
38 with pytest.raises(RepositoryError):
38 with pytest.raises(RepositoryError):
39 # Should fail on direct clone call, which as of this writing does not happen outside of class
39 # Should fail on direct clone call, which as of this writing does not happen outside of class
40 clone_fail_repo = GitRepository(get_new_dir('injection-repo'), create=True)
40 clone_fail_repo = GitRepository(get_new_dir('injection-repo'), create=True)
41 clone_fail_repo.clone(repo_inject_path, update_after_clone=True,)
41 clone_fail_repo.clone(repo_inject_path, update_after_clone=True,)
42
42
43 # Verify correct quoting of evil characters that should work on posix file systems
43 # Verify correct quoting of evil characters that should work on posix file systems
44 if sys.platform == 'win32':
44 if sys.platform == 'win32':
45 # windows does not allow '"' in dir names
45 # windows does not allow '"' in dir names
46 # and some versions of the git client don't like ` and '
46 # and some versions of the git client don't like ` and '
47 tricky_path = get_new_dir("tricky-path-repo-$")
47 tricky_path = get_new_dir("tricky-path-repo-$")
48 else:
48 else:
49 tricky_path = get_new_dir("tricky-path-repo-$'\"`")
49 tricky_path = get_new_dir("tricky-path-repo-$'\"`")
50 successfully_cloned = GitRepository(tricky_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
50 successfully_cloned = GitRepository(tricky_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
51 # Repo should have been created
51 # Repo should have been created
52 assert not successfully_cloned._repo.bare
52 assert not successfully_cloned._repo.bare
53
53
54 if sys.platform == 'win32':
54 if sys.platform == 'win32':
55 # windows does not allow '"' in dir names
55 # windows does not allow '"' in dir names
56 # and some versions of the git client don't like ` and '
56 # and some versions of the git client don't like ` and '
57 tricky_path_2 = get_new_dir("tricky-path-2-repo-$")
57 tricky_path_2 = get_new_dir("tricky-path-2-repo-$")
58 else:
58 else:
59 tricky_path_2 = get_new_dir("tricky-path-2-repo-$'\"`")
59 tricky_path_2 = get_new_dir("tricky-path-2-repo-$'\"`")
60 successfully_cloned2 = GitRepository(tricky_path_2, src_url=tricky_path, bare=True, create=True)
60 successfully_cloned2 = GitRepository(tricky_path_2, src_url=tricky_path, bare=True, create=True)
61 # Repo should have been created and thus used correct quoting for clone
61 # Repo should have been created and thus used correct quoting for clone
62 assert successfully_cloned2._repo.bare
62 assert successfully_cloned2._repo.bare
63
63
64 # Should pass because URL has been properly quoted
64 # Should pass because URL has been properly quoted
65 successfully_cloned.pull(tricky_path_2)
65 successfully_cloned.pull(tricky_path_2)
66 successfully_cloned2.fetch(tricky_path)
66 successfully_cloned2.fetch(tricky_path)
67
67
68 def test_repo_create_with_spaces_in_path(self):
68 def test_repo_create_with_spaces_in_path(self):
69 repo_path = get_new_dir("path with spaces")
69 repo_path = get_new_dir("path with spaces")
70 repo = GitRepository(repo_path, src_url=None, bare=True, create=True)
70 repo = GitRepository(repo_path, src_url=None, bare=True, create=True)
71 # Repo should have been created
71 # Repo should have been created
72 assert repo._repo.bare
72 assert repo._repo.bare
73
73
74 def test_repo_clone(self):
74 def test_repo_clone(self):
75 self.__check_for_existing_repo()
75 self.__check_for_existing_repo()
76 repo = GitRepository(TEST_GIT_REPO)
76 repo = GitRepository(TEST_GIT_REPO)
77 repo_clone = GitRepository(TEST_GIT_REPO_CLONE,
77 repo_clone = GitRepository(TEST_GIT_REPO_CLONE,
78 src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
78 src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
79 assert len(repo.revisions) == len(repo_clone.revisions)
79 assert len(repo.revisions) == len(repo_clone.revisions)
80 # Checking hashes of changesets should be enough
80 # Checking hashes of changesets should be enough
81 for changeset in repo.get_changesets():
81 for changeset in repo.get_changesets():
82 raw_id = changeset.raw_id
82 raw_id = changeset.raw_id
83 assert raw_id == repo_clone.get_changeset(raw_id).raw_id
83 assert raw_id == repo_clone.get_changeset(raw_id).raw_id
84
84
85 def test_repo_clone_with_spaces_in_path(self):
85 def test_repo_clone_with_spaces_in_path(self):
86 repo_path = get_new_dir("path with spaces")
86 repo_path = get_new_dir("path with spaces")
87 successfully_cloned = GitRepository(repo_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
87 successfully_cloned = GitRepository(repo_path, src_url=TEST_GIT_REPO, update_after_clone=True, create=True)
88 # Repo should have been created
88 # Repo should have been created
89 assert not successfully_cloned._repo.bare
89 assert not successfully_cloned._repo.bare
90
90
91 successfully_cloned.pull(TEST_GIT_REPO)
91 successfully_cloned.pull(TEST_GIT_REPO)
92 self.repo.fetch(repo_path)
92 self.repo.fetch(repo_path)
93
93
94 def test_repo_clone_without_create(self):
94 def test_repo_clone_without_create(self):
95 with pytest.raises(RepositoryError):
95 with pytest.raises(RepositoryError):
96 GitRepository(TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
96 GitRepository(TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
97
97
98 def test_repo_clone_with_update(self):
98 def test_repo_clone_with_update(self):
99 repo = GitRepository(TEST_GIT_REPO)
99 repo = GitRepository(TEST_GIT_REPO)
100 clone_path = TEST_GIT_REPO_CLONE + '_with_update'
100 clone_path = TEST_GIT_REPO_CLONE + '_with_update'
101 repo_clone = GitRepository(clone_path,
101 repo_clone = GitRepository(clone_path,
102 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
102 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
103 assert len(repo.revisions) == len(repo_clone.revisions)
103 assert len(repo.revisions) == len(repo_clone.revisions)
104
104
105 # check if current workdir was updated
105 # check if current workdir was updated
106 fpath = os.path.join(clone_path, 'MANIFEST.in')
106 fpath = os.path.join(clone_path, 'MANIFEST.in')
107 assert os.path.isfile(fpath) == True, 'Repo was cloned and updated but file %s could not be found' % fpath
107 assert os.path.isfile(fpath) == True, 'Repo was cloned and updated but file %s could not be found' % fpath
108
108
109 def test_repo_clone_without_update(self):
109 def test_repo_clone_without_update(self):
110 repo = GitRepository(TEST_GIT_REPO)
110 repo = GitRepository(TEST_GIT_REPO)
111 clone_path = TEST_GIT_REPO_CLONE + '_without_update'
111 clone_path = TEST_GIT_REPO_CLONE + '_without_update'
112 repo_clone = GitRepository(clone_path,
112 repo_clone = GitRepository(clone_path,
113 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
113 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
114 assert len(repo.revisions) == len(repo_clone.revisions)
114 assert len(repo.revisions) == len(repo_clone.revisions)
115 # check if current workdir was *NOT* updated
115 # check if current workdir was *NOT* updated
116 fpath = os.path.join(clone_path, 'MANIFEST.in')
116 fpath = os.path.join(clone_path, 'MANIFEST.in')
117 # Make sure it's not bare repo
117 # Make sure it's not bare repo
118 assert not repo_clone._repo.bare
118 assert not repo_clone._repo.bare
119 assert os.path.isfile(fpath) == False, 'Repo was cloned and updated but file %s was found' % fpath
119 assert os.path.isfile(fpath) == False, 'Repo was cloned and updated but file %s was found' % fpath
120
120
121 def test_repo_clone_into_bare_repo(self):
121 def test_repo_clone_into_bare_repo(self):
122 repo = GitRepository(TEST_GIT_REPO)
122 repo = GitRepository(TEST_GIT_REPO)
123 clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
123 clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
124 repo_clone = GitRepository(clone_path, create=True,
124 repo_clone = GitRepository(clone_path, create=True,
125 src_url=repo.path, bare=True)
125 src_url=repo.path, bare=True)
126 assert repo_clone._repo.bare
126 assert repo_clone._repo.bare
127
127
128 def test_create_repo_is_not_bare_by_default(self):
128 def test_create_repo_is_not_bare_by_default(self):
129 repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
129 repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
130 assert not repo._repo.bare
130 assert not repo._repo.bare
131
131
132 def test_create_bare_repo(self):
132 def test_create_bare_repo(self):
133 repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
133 repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
134 assert repo._repo.bare
134 assert repo._repo.bare
135
135
136 def test_revisions(self):
136 def test_revisions(self):
137 # there are 112 revisions (by now)
137 # there are 112 revisions (by now)
138 # so we can assume they would be available from now on
138 # so we can assume they would be available from now on
139 subset = set([
139 subset = set([
140 'c1214f7e79e02fc37156ff215cd71275450cffc3',
140 'c1214f7e79e02fc37156ff215cd71275450cffc3',
141 '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
141 '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
142 'fa6600f6848800641328adbf7811fd2372c02ab2',
142 'fa6600f6848800641328adbf7811fd2372c02ab2',
143 '102607b09cdd60e2793929c4f90478be29f85a17',
143 '102607b09cdd60e2793929c4f90478be29f85a17',
144 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
144 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
145 '2d1028c054665b962fa3d307adfc923ddd528038',
145 '2d1028c054665b962fa3d307adfc923ddd528038',
146 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
146 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
147 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
147 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
148 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
148 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
149 '8430a588b43b5d6da365400117c89400326e7992',
149 '8430a588b43b5d6da365400117c89400326e7992',
150 'd955cd312c17b02143c04fa1099a352b04368118',
150 'd955cd312c17b02143c04fa1099a352b04368118',
151 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
151 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
152 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
152 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
153 'f298fe1189f1b69779a4423f40b48edf92a703fc',
153 'f298fe1189f1b69779a4423f40b48edf92a703fc',
154 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
154 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
155 '6e125e7c890379446e98980d8ed60fba87d0f6d1',
155 '6e125e7c890379446e98980d8ed60fba87d0f6d1',
156 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
156 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
157 '0b05e4ed56c802098dfc813cbe779b2f49e92500',
157 '0b05e4ed56c802098dfc813cbe779b2f49e92500',
158 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
158 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
159 '45223f8f114c64bf4d6f853e3c35a369a6305520',
159 '45223f8f114c64bf4d6f853e3c35a369a6305520',
160 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
160 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
161 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
161 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
162 '27d48942240f5b91dfda77accd2caac94708cc7d',
162 '27d48942240f5b91dfda77accd2caac94708cc7d',
163 '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
163 '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
164 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
164 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
165 assert subset.issubset(set(self.repo.revisions))
165 assert subset.issubset(set(self.repo.revisions))
166
166
167 def test_slicing(self):
167 def test_slicing(self):
168 # 4 1 5 10 95
168 # 4 1 5 10 95
169 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
169 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
170 (10, 20, 10), (5, 100, 95)]:
170 (10, 20, 10), (5, 100, 95)]:
171 revs = list(self.repo[sfrom:sto])
171 revs = list(self.repo[sfrom:sto])
172 assert len(revs) == size
172 assert len(revs) == size
173 assert revs[0] == self.repo.get_changeset(sfrom)
173 assert revs[0] == self.repo.get_changeset(sfrom)
174 assert revs[-1] == self.repo.get_changeset(sto - 1)
174 assert revs[-1] == self.repo.get_changeset(sto - 1)
175
175
176 def test_branches(self):
176 def test_branches(self):
177 # TODO: Need more tests here
177 # TODO: Need more tests here
178 # Removed (those are 'remotes' branches for cloned repo)
178 # Removed (those are 'remotes' branches for cloned repo)
179 #assert 'master' in self.repo.branches
179 #assert 'master' in self.repo.branches
180 #assert 'gittree' in self.repo.branches
180 #assert 'gittree' in self.repo.branches
181 #assert 'web-branch' in self.repo.branches
181 #assert 'web-branch' in self.repo.branches
182 for name, id in self.repo.branches.items():
182 for name, id in self.repo.branches.items():
183 assert isinstance(self.repo.get_changeset(id), GitChangeset)
183 assert isinstance(self.repo.get_changeset(id), GitChangeset)
184
184
185 def test_tags(self):
185 def test_tags(self):
186 # TODO: Need more tests here
186 # TODO: Need more tests here
187 assert 'v0.1.1' in self.repo.tags
187 assert 'v0.1.1' in self.repo.tags
188 assert 'v0.1.2' in self.repo.tags
188 assert 'v0.1.2' in self.repo.tags
189 for name, id in self.repo.tags.items():
189 for name, id in self.repo.tags.items():
190 assert isinstance(self.repo.get_changeset(id), GitChangeset)
190 assert isinstance(self.repo.get_changeset(id), GitChangeset)
191
191
192 def _test_single_changeset_cache(self, revision):
192 def _test_single_changeset_cache(self, revision):
193 chset = self.repo.get_changeset(revision)
193 chset = self.repo.get_changeset(revision)
194 assert revision in self.repo.changesets
194 assert revision in self.repo.changesets
195 assert chset is self.repo.changesets[revision]
195 assert chset is self.repo.changesets[revision]
196
196
197 def test_initial_changeset(self):
197 def test_initial_changeset(self):
198 id = self.repo.revisions[0]
198 id = self.repo.revisions[0]
199 init_chset = self.repo.get_changeset(id)
199 init_chset = self.repo.get_changeset(id)
200 assert init_chset.message == 'initial import\n'
200 assert init_chset.message == 'initial import\n'
201 assert init_chset.author == 'Marcin Kuzminski <marcin@python-blog.com>'
201 assert init_chset.author == 'Marcin Kuzminski <marcin@python-blog.com>'
202 for path in ('vcs/__init__.py',
202 for path in ('vcs/__init__.py',
203 'vcs/backends/BaseRepository.py',
203 'vcs/backends/BaseRepository.py',
204 'vcs/backends/__init__.py'):
204 'vcs/backends/__init__.py'):
205 assert isinstance(init_chset.get_node(path), FileNode)
205 assert isinstance(init_chset.get_node(path), FileNode)
206 for path in ('', 'vcs', 'vcs/backends'):
206 for path in ('', 'vcs', 'vcs/backends'):
207 assert isinstance(init_chset.get_node(path), DirNode)
207 assert isinstance(init_chset.get_node(path), DirNode)
208
208
209 with pytest.raises(NodeDoesNotExistError):
209 with pytest.raises(NodeDoesNotExistError):
210 init_chset.get_node(path='foobar')
210 init_chset.get_node(path='foobar')
211
211
212 node = init_chset.get_node('vcs/')
212 node = init_chset.get_node('vcs/')
213 assert hasattr(node, 'kind')
213 assert hasattr(node, 'kind')
214 assert node.kind == NodeKind.DIR
214 assert node.kind == NodeKind.DIR
215
215
216 node = init_chset.get_node('vcs')
216 node = init_chset.get_node('vcs')
217 assert hasattr(node, 'kind')
217 assert hasattr(node, 'kind')
218 assert node.kind == NodeKind.DIR
218 assert node.kind == NodeKind.DIR
219
219
220 node = init_chset.get_node('vcs/__init__.py')
220 node = init_chset.get_node('vcs/__init__.py')
221 assert hasattr(node, 'kind')
221 assert hasattr(node, 'kind')
222 assert node.kind == NodeKind.FILE
222 assert node.kind == NodeKind.FILE
223
223
224 def test_not_existing_changeset(self):
224 def test_not_existing_changeset(self):
225 with pytest.raises(RepositoryError):
225 with pytest.raises(RepositoryError):
226 self.repo.get_changeset('f' * 40)
226 self.repo.get_changeset('f' * 40)
227
227
228 def test_changeset10(self):
228 def test_changeset10(self):
229
229
230 chset10 = self.repo.get_changeset(self.repo.revisions[9])
230 chset10 = self.repo.get_changeset(self.repo.revisions[9])
231 readme = b"""===
231 readme = b"""===
232 VCS
232 VCS
233 ===
233 ===
234
234
235 Various Version Control System management abstraction layer for Python.
235 Various Version Control System management abstraction layer for Python.
236
236
237 Introduction
237 Introduction
238 ------------
238 ------------
239
239
240 TODO: To be written...
240 TODO: To be written...
241
241
242 """
242 """
243 node = chset10.get_node('README.rst')
243 node = chset10.get_node('README.rst')
244 assert node.kind == NodeKind.FILE
244 assert node.kind == NodeKind.FILE
245 assert node.content == readme
245 assert node.content == readme
246
246
247
247
248 class TestGitChangeset(object):
248 class TestGitChangeset(object):
249
249
250 def setup_method(self):
250 def setup_method(self):
251 self.repo = GitRepository(TEST_GIT_REPO)
251 self.repo = GitRepository(TEST_GIT_REPO)
252
252
253 def test_default_changeset(self):
253 def test_default_changeset(self):
254 tip = self.repo.get_changeset()
254 tip = self.repo.get_changeset()
255 assert tip == self.repo.get_changeset(None)
255 assert tip == self.repo.get_changeset(None)
256 assert tip == self.repo.get_changeset('tip')
256 assert tip == self.repo.get_changeset('tip')
257
257
258 def test_root_node(self):
258 def test_root_node(self):
259 tip = self.repo.get_changeset()
259 tip = self.repo.get_changeset()
260 assert tip.root is tip.get_node('')
260 assert tip.root is tip.get_node('')
261
261
262 def test_lazy_fetch(self):
262 def test_lazy_fetch(self):
263 """
263 """
264 Test if changeset's nodes expands and are cached as we walk through
264 Test if changeset's nodes expands and are cached as we walk through
265 the revision. This test is somewhat hard to write as order of tests
265 the revision. This test is somewhat hard to write as order of tests
266 is a key here. Written by running command after command in a shell.
266 is a key here. Written by running command after command in a shell.
267 """
267 """
268 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
268 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
269 assert commit_id in self.repo.revisions
269 assert commit_id in self.repo.revisions
270 chset = self.repo.get_changeset(commit_id)
270 chset = self.repo.get_changeset(commit_id)
271 assert len(chset.nodes) == 0
271 assert len(chset.nodes) == 0
272 root = chset.root
272 root = chset.root
273 assert len(chset.nodes) == 1
273 assert len(chset.nodes) == 1
274 assert len(root.nodes) == 8
274 assert len(root.nodes) == 8
275 # accessing root.nodes updates chset.nodes
275 # accessing root.nodes updates chset.nodes
276 assert len(chset.nodes) == 9
276 assert len(chset.nodes) == 9
277
277
278 docs = root.get_node('docs')
278 docs = root.get_node('docs')
279 # we haven't yet accessed anything new as docs dir was already cached
279 # we haven't yet accessed anything new as docs dir was already cached
280 assert len(chset.nodes) == 9
280 assert len(chset.nodes) == 9
281 assert len(docs.nodes) == 8
281 assert len(docs.nodes) == 8
282 # accessing docs.nodes updates chset.nodes
282 # accessing docs.nodes updates chset.nodes
283 assert len(chset.nodes) == 17
283 assert len(chset.nodes) == 17
284
284
285 assert docs is chset.get_node('docs')
285 assert docs is chset.get_node('docs')
286 assert docs is root.nodes[0]
286 assert docs is root.nodes[0]
287 assert docs is root.dirs[0]
287 assert docs is root.dirs[0]
288 assert docs is chset.get_node('docs')
288 assert docs is chset.get_node('docs')
289
289
290 def test_nodes_with_changeset(self):
290 def test_nodes_with_changeset(self):
291 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
291 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
292 chset = self.repo.get_changeset(commit_id)
292 chset = self.repo.get_changeset(commit_id)
293 root = chset.root
293 root = chset.root
294 docs = root.get_node('docs')
294 docs = root.get_node('docs')
295 assert docs is chset.get_node('docs')
295 assert docs is chset.get_node('docs')
296 api = docs.get_node('api')
296 api = docs.get_node('api')
297 assert api is chset.get_node('docs/api')
297 assert api is chset.get_node('docs/api')
298 index = api.get_node('index.rst')
298 index = api.get_node('index.rst')
299 assert index is chset.get_node('docs/api/index.rst')
299 assert index is chset.get_node('docs/api/index.rst')
300 assert index is chset.get_node('docs') \
300 assert index is chset.get_node('docs') \
301 .get_node('api') \
301 .get_node('api') \
302 .get_node('index.rst')
302 .get_node('index.rst')
303
303
304 def test_branch_and_tags(self):
304 def test_branch_and_tags(self):
305 # Those tests seem to show wrong results:
305 # Those tests seem to show wrong results:
306 # in Git, only heads have a branch - most changesets don't
306 # in Git, only heads have a branch - most changesets don't
307 rev0 = self.repo.revisions[0]
307 rev0 = self.repo.revisions[0]
308 chset0 = self.repo.get_changeset(rev0)
308 chset0 = self.repo.get_changeset(rev0)
309 assert chset0.branch is None # should be 'master'?
309 assert chset0.branch is None # should be 'master'?
310 assert chset0.branches == [] # should be 'master'?
310 assert chset0.branches == [] # should be 'master'?
311 assert chset0.tags == []
311 assert chset0.tags == []
312
312
313 rev10 = self.repo.revisions[10]
313 rev10 = self.repo.revisions[10]
314 chset10 = self.repo.get_changeset(rev10)
314 chset10 = self.repo.get_changeset(rev10)
315 assert chset10.branch is None # should be 'master'?
315 assert chset10.branch is None # should be 'master'?
316 assert chset10.branches == [] # should be 'master'?
316 assert chset10.branches == [] # should be 'master'?
317 assert chset10.tags == []
317 assert chset10.tags == []
318
318
319 rev44 = self.repo.revisions[44]
319 rev44 = self.repo.revisions[44]
320 chset44 = self.repo.get_changeset(rev44)
320 chset44 = self.repo.get_changeset(rev44)
321 assert chset44.branch is None # should be 'web-branch'?
321 assert chset44.branch is None # should be 'web-branch'?
322 assert chset44.branches == [] # should be 'web-branch'?
322 assert chset44.branches == [] # should be 'web-branch'?
323
323
324 tip = self.repo.get_changeset('tip')
324 tip = self.repo.get_changeset('tip')
325 assert 'tip' not in tip.tags # it should be?
325 assert 'tip' not in tip.tags # it should be?
326 assert not tip.tags # how it is!
326 assert not tip.tags # how it is!
327
327
328 def _test_slices(self, limit, offset):
328 def _test_slices(self, limit, offset):
329 count = self.repo.count()
329 count = self.repo.count()
330 changesets = self.repo.get_changesets(limit=limit, offset=offset)
330 changesets = self.repo.get_changesets(limit=limit, offset=offset)
331 idx = 0
331 idx = 0
332 for changeset in changesets:
332 for changeset in changesets:
333 rev = offset + idx
333 rev = offset + idx
334 idx += 1
334 idx += 1
335 rev_id = self.repo.revisions[rev]
335 rev_id = self.repo.revisions[rev]
336 if idx > limit:
336 if idx > limit:
337 pytest.fail("Exceeded limit already (getting revision %s, "
337 pytest.fail("Exceeded limit already (getting revision %s, "
338 "there are %s total revisions, offset=%s, limit=%s)"
338 "there are %s total revisions, offset=%s, limit=%s)"
339 % (rev_id, count, offset, limit))
339 % (rev_id, count, offset, limit))
340 assert changeset == self.repo.get_changeset(rev_id)
340 assert changeset == self.repo.get_changeset(rev_id)
341 result = list(self.repo.get_changesets(limit=limit, offset=offset))
341 result = list(self.repo.get_changesets(limit=limit, offset=offset))
342 start = offset
342 start = offset
343 end = limit and offset + limit or None
343 end = limit and offset + limit or None
344 sliced = list(self.repo[start:end])
344 sliced = list(self.repo[start:end])
345 pytest.assertEqual(result, sliced,
345 pytest.assertEqual(result, sliced,
346 msg="Comparison failed for limit=%s, offset=%s"
346 msg="Comparison failed for limit=%s, offset=%s"
347 "(get_changeset returned: %s and sliced: %s"
347 "(get_changeset returned: %s and sliced: %s"
348 % (limit, offset, result, sliced))
348 % (limit, offset, result, sliced))
349
349
350 def _test_file_size(self, revision, path, size):
350 def _test_file_size(self, revision, path, size):
351 node = self.repo.get_changeset(revision).get_node(path)
351 node = self.repo.get_changeset(revision).get_node(path)
352 assert node.is_file()
352 assert node.is_file()
353 assert node.size == size
353 assert node.size == size
354
354
355 def test_file_size(self):
355 def test_file_size(self):
356 to_check = (
356 to_check = (
357 ('c1214f7e79e02fc37156ff215cd71275450cffc3',
357 ('c1214f7e79e02fc37156ff215cd71275450cffc3',
358 'vcs/backends/BaseRepository.py', 502),
358 'vcs/backends/BaseRepository.py', 502),
359 ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
359 ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
360 'vcs/backends/hg.py', 854),
360 'vcs/backends/hg.py', 854),
361 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
361 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
362 'setup.py', 1068),
362 'setup.py', 1068),
363 ('d955cd312c17b02143c04fa1099a352b04368118',
363 ('d955cd312c17b02143c04fa1099a352b04368118',
364 'vcs/backends/base.py', 2921),
364 'vcs/backends/base.py', 2921),
365 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
365 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
366 'vcs/backends/base.py', 3936),
366 'vcs/backends/base.py', 3936),
367 ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
367 ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
368 'vcs/backends/base.py', 6189),
368 'vcs/backends/base.py', 6189),
369 )
369 )
370 for revision, path, size in to_check:
370 for revision, path, size in to_check:
371 self._test_file_size(revision, path, size)
371 self._test_file_size(revision, path, size)
372
372
373 def _test_dir_size(self, revision, path, size):
373 def _test_dir_size(self, revision, path, size):
374 node = self.repo.get_changeset(revision).get_node(path)
374 node = self.repo.get_changeset(revision).get_node(path)
375 assert node.size == size
375 assert node.size == size
376
376
377 def test_dir_size(self):
377 def test_dir_size(self):
378 to_check = (
378 to_check = (
379 ('5f2c6ee195929b0be80749243c18121c9864a3b3', '/', 674076),
379 ('5f2c6ee195929b0be80749243c18121c9864a3b3', '/', 674076),
380 ('7ab37bc680b4aa72c34d07b230c866c28e9fc204', '/', 674049),
380 ('7ab37bc680b4aa72c34d07b230c866c28e9fc204', '/', 674049),
381 ('6892503fb8f2a552cef5f4d4cc2cdbd13ae1cd2f', '/', 671830),
381 ('6892503fb8f2a552cef5f4d4cc2cdbd13ae1cd2f', '/', 671830),
382 )
382 )
383 for revision, path, size in to_check:
383 for revision, path, size in to_check:
384 self._test_dir_size(revision, path, size)
384 self._test_dir_size(revision, path, size)
385
385
386 def test_repo_size(self):
386 def test_repo_size(self):
387 assert self.repo.size == 674076
387 assert self.repo.size == 674076
388
388
389 def test_file_history(self):
389 def test_file_history(self):
390 # we can only check if those revisions are present in the history
390 # we can only check if those revisions are present in the history
391 # as we cannot update this test every time file is changed
391 # as we cannot update this test every time file is changed
392 files = {
392 files = {
393 'setup.py': [
393 'setup.py': [
394 '54386793436c938cff89326944d4c2702340037d',
394 '54386793436c938cff89326944d4c2702340037d',
395 '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
395 '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
396 '998ed409c795fec2012b1c0ca054d99888b22090',
396 '998ed409c795fec2012b1c0ca054d99888b22090',
397 '5e0eb4c47f56564395f76333f319d26c79e2fb09',
397 '5e0eb4c47f56564395f76333f319d26c79e2fb09',
398 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
398 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
399 '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
399 '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
400 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
400 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
401 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
401 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
402 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
402 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
403 ],
403 ],
404 'vcs/nodes.py': [
404 'vcs/nodes.py': [
405 '33fa3223355104431402a888fa77a4e9956feb3e',
405 '33fa3223355104431402a888fa77a4e9956feb3e',
406 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
406 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
407 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
407 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
408 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
408 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
409 'c877b68d18e792a66b7f4c529ea02c8f80801542',
409 'c877b68d18e792a66b7f4c529ea02c8f80801542',
410 '4313566d2e417cb382948f8d9d7c765330356054',
410 '4313566d2e417cb382948f8d9d7c765330356054',
411 '6c2303a793671e807d1cfc70134c9ca0767d98c2',
411 '6c2303a793671e807d1cfc70134c9ca0767d98c2',
412 '54386793436c938cff89326944d4c2702340037d',
412 '54386793436c938cff89326944d4c2702340037d',
413 '54000345d2e78b03a99d561399e8e548de3f3203',
413 '54000345d2e78b03a99d561399e8e548de3f3203',
414 '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
414 '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
415 '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
415 '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
416 '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
416 '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
417 '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
417 '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
418 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
418 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
419 '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
419 '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
420 '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
420 '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
421 '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
421 '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
422 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
422 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
423 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
423 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
424 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
424 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
425 'f15c21f97864b4f071cddfbf2750ec2e23859414',
425 'f15c21f97864b4f071cddfbf2750ec2e23859414',
426 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
426 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
427 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
427 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
428 '84dec09632a4458f79f50ddbbd155506c460b4f9',
428 '84dec09632a4458f79f50ddbbd155506c460b4f9',
429 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
429 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
430 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
430 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
431 '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
431 '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
432 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
432 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
433 '6970b057cffe4aab0a792aa634c89f4bebf01441',
433 '6970b057cffe4aab0a792aa634c89f4bebf01441',
434 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
434 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
435 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
435 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
436 ],
436 ],
437 'vcs/backends/git.py': [
437 'vcs/backends/git.py': [
438 '4cf116ad5a457530381135e2f4c453e68a1b0105',
438 '4cf116ad5a457530381135e2f4c453e68a1b0105',
439 '9a751d84d8e9408e736329767387f41b36935153',
439 '9a751d84d8e9408e736329767387f41b36935153',
440 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
440 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
441 '428f81bb652bcba8d631bce926e8834ff49bdcc6',
441 '428f81bb652bcba8d631bce926e8834ff49bdcc6',
442 '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
442 '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
443 '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
443 '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
444 '50e08c506174d8645a4bb517dd122ac946a0f3bf',
444 '50e08c506174d8645a4bb517dd122ac946a0f3bf',
445 '54000345d2e78b03a99d561399e8e548de3f3203',
445 '54000345d2e78b03a99d561399e8e548de3f3203',
446 ],
446 ],
447 }
447 }
448 for path, revs in files.items():
448 for path, revs in files.items():
449 node = self.repo.get_changeset(revs[0]).get_node(path)
449 node = self.repo.get_changeset(revs[0]).get_node(path)
450 node_revs = [chset.raw_id for chset in node.history]
450 node_revs = [chset.raw_id for chset in node.history]
451 assert set(revs).issubset(set(node_revs)), "We assumed that %s is subset of revisions for which file %s " \
451 assert set(revs).issubset(set(node_revs)), "We assumed that %s is subset of revisions for which file %s " \
452 "has been changed, and history of that node returned: %s" \
452 "has been changed, and history of that node returned: %s" \
453 % (revs, path, node_revs)
453 % (revs, path, node_revs)
454
454
455 def test_file_annotate(self):
455 def test_file_annotate(self):
456 files = {
456 files = {
457 'vcs/backends/__init__.py': {
457 'vcs/backends/__init__.py': {
458 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
458 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
459 'lines_no': 1,
459 'lines_no': 1,
460 'changesets': [
460 'changesets': [
461 'c1214f7e79e02fc37156ff215cd71275450cffc3',
461 'c1214f7e79e02fc37156ff215cd71275450cffc3',
462 ],
462 ],
463 },
463 },
464 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
464 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
465 'lines_no': 21,
465 'lines_no': 21,
466 'changesets': [
466 'changesets': [
467 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
467 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
468 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
468 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
469 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
469 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
470 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
470 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
471 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
471 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
472 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
472 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
473 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
473 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
474 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
474 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
475 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
475 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
476 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
476 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
477 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
477 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
478 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
478 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
479 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
479 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
480 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
480 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
481 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
481 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
482 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
482 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
483 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
483 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
484 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
484 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
485 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
485 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
486 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
486 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
487 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
487 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
488 ],
488 ],
489 },
489 },
490 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
490 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
491 'lines_no': 32,
491 'lines_no': 32,
492 'changesets': [
492 'changesets': [
493 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
493 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
494 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
494 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
495 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
495 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
496 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
496 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
497 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
497 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
498 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
498 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
499 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
499 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
500 '54000345d2e78b03a99d561399e8e548de3f3203',
500 '54000345d2e78b03a99d561399e8e548de3f3203',
501 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
501 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
502 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
502 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
503 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
503 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
504 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
504 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
505 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
505 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
506 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
506 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
507 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
507 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
508 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
508 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
509 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
509 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
510 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
510 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
511 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
511 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
512 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
512 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
513 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
513 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
514 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
514 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
515 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
515 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
516 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
516 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
517 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
517 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
518 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
518 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
519 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
519 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
520 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
520 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
521 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
521 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
522 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
522 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
523 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
523 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
524 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
524 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
525 ],
525 ],
526 },
526 },
527 },
527 },
528 }
528 }
529
529
530 for fname, revision_dict in files.items():
530 for fname, revision_dict in files.items():
531 for rev, data in revision_dict.items():
531 for rev, data in revision_dict.items():
532 cs = self.repo.get_changeset(rev)
532 cs = self.repo.get_changeset(rev)
533
533
534 l1_1 = [x[1] for x in cs.get_file_annotate(fname)]
534 l1_1 = [x[1] for x in cs.get_file_annotate(fname)]
535 l1_2 = [x[2]().raw_id for x in cs.get_file_annotate(fname)]
535 l1_2 = [x[2]().raw_id for x in cs.get_file_annotate(fname)]
536 assert l1_1 == l1_2
536 assert l1_1 == l1_2
537 l1 = l1_1
537 l1 = l1_1
538 l2 = files[fname][rev]['changesets']
538 l2 = files[fname][rev]['changesets']
539 assert l1 == l2, "The lists of revision for %s@rev %s" \
539 assert l1 == l2, "The lists of revision for %s@rev %s" \
540 "from annotation list should match each other, " \
540 "from annotation list should match each other, " \
541 "got \n%s \nvs \n%s " % (fname, rev, l1, l2)
541 "got \n%s \nvs \n%s " % (fname, rev, l1, l2)
542
542
543 def test_files_state(self):
543 def test_files_state(self):
544 """
544 """
545 Tests state of FileNodes.
545 Tests state of FileNodes.
546 """
546 """
547 node = self.repo \
547 node = self.repo \
548 .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0') \
548 .get_changeset('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0') \
549 .get_node('vcs/utils/diffs.py')
549 .get_node('vcs/utils/diffs.py')
550 assert node.state, NodeState.ADDED
550 assert node.state, NodeState.ADDED
551 assert node.added
551 assert node.added
552 assert not node.changed
552 assert not node.changed
553 assert not node.not_changed
553 assert not node.not_changed
554 assert not node.removed
554 assert not node.removed
555
555
556 node = self.repo \
556 node = self.repo \
557 .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e') \
557 .get_changeset('33fa3223355104431402a888fa77a4e9956feb3e') \
558 .get_node('.hgignore')
558 .get_node('.hgignore')
559 assert node.state, NodeState.CHANGED
559 assert node.state, NodeState.CHANGED
560 assert not node.added
560 assert not node.added
561 assert node.changed
561 assert node.changed
562 assert not node.not_changed
562 assert not node.not_changed
563 assert not node.removed
563 assert not node.removed
564
564
565 node = self.repo \
565 node = self.repo \
566 .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064') \
566 .get_changeset('e29b67bd158580fc90fc5e9111240b90e6e86064') \
567 .get_node('setup.py')
567 .get_node('setup.py')
568 assert node.state, NodeState.NOT_CHANGED
568 assert node.state, NodeState.NOT_CHANGED
569 assert not node.added
569 assert not node.added
570 assert not node.changed
570 assert not node.changed
571 assert node.not_changed
571 assert node.not_changed
572 assert not node.removed
572 assert not node.removed
573
573
574 # If node has REMOVED state then trying to fetch it would raise
574 # If node has REMOVED state then trying to fetch it would raise
575 # ChangesetError exception
575 # ChangesetError exception
576 chset = self.repo.get_changeset(
576 chset = self.repo.get_changeset(
577 'fa6600f6848800641328adbf7811fd2372c02ab2')
577 'fa6600f6848800641328adbf7811fd2372c02ab2')
578 path = 'vcs/backends/BaseRepository.py'
578 path = 'vcs/backends/BaseRepository.py'
579 with pytest.raises(NodeDoesNotExistError):
579 with pytest.raises(NodeDoesNotExistError):
580 chset.get_node(path)
580 chset.get_node(path)
581 # but it would be one of ``removed`` (changeset's attribute)
581 # but it would be one of ``removed`` (changeset's attribute)
582 assert path in [rf.path for rf in chset.removed]
582 assert path in [rf.path for rf in chset.removed]
583
583
584 chset = self.repo.get_changeset(
584 chset = self.repo.get_changeset(
585 '54386793436c938cff89326944d4c2702340037d')
585 '54386793436c938cff89326944d4c2702340037d')
586 changed = ['setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
586 changed = ['setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
587 'vcs/nodes.py']
587 'vcs/nodes.py']
588 assert set(changed) == set([f.path for f in chset.changed])
588 assert set(changed) == set([f.path for f in chset.changed])
589
589
590 def test_commit_message_is_str(self):
590 def test_commit_message_is_str(self):
591 for cs in self.repo:
591 for cs in self.repo:
592 assert isinstance(cs.message, str)
592 assert isinstance(cs.message, str)
593
593
594 def test_changeset_author_is_str(self):
594 def test_changeset_author_is_str(self):
595 for cs in self.repo:
595 for cs in self.repo:
596 assert isinstance(cs.author, str)
596 assert isinstance(cs.author, str)
597
597
598 def test_repo_files_content_is_bytes(self):
598 def test_repo_files_content_is_bytes(self):
599 changeset = self.repo.get_changeset()
599 changeset = self.repo.get_changeset()
600 for node in changeset.get_node('/'):
600 for node in changeset.get_node('/'):
601 if node.is_file():
601 if node.is_file():
602 assert isinstance(node.content, bytes)
602 assert isinstance(node.content, bytes)
603
603
604 def test_wrong_path(self):
604 def test_wrong_path(self):
605 # There is 'setup.py' in the root dir but not there:
605 # There is 'setup.py' in the root dir but not there:
606 path = 'foo/bar/setup.py'
606 path = 'foo/bar/setup.py'
607 tip = self.repo.get_changeset()
607 tip = self.repo.get_changeset()
608 with pytest.raises(VCSError):
608 with pytest.raises(VCSError):
609 tip.get_node(path)
609 tip.get_node(path)
610
610
611 def test_author_email(self):
611 def test_author_email(self):
612 assert 'marcin@python-blog.com' == self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3').author_email
612 assert 'marcin@python-blog.com' == self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3').author_email
613 assert 'lukasz.balcerzak@python-center.pl' == self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b').author_email
613 assert 'lukasz.balcerzak@python-center.pl' == self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b').author_email
614 assert '' == self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992').author_email
614 assert '' == self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992').author_email
615
615
616 def test_author_username(self):
616 def test_author_username(self):
617 assert 'Marcin Kuzminski' == self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3').author_name
617 assert 'Marcin Kuzminski' == self.repo.get_changeset('c1214f7e79e02fc37156ff215cd71275450cffc3').author_name
618 assert 'Lukasz Balcerzak' == self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b').author_name
618 assert 'Lukasz Balcerzak' == self.repo.get_changeset('ff7ca51e58c505fec0dd2491de52c622bb7a806b').author_name
619 assert 'marcink none@none' == self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992').author_name
619 assert 'marcink none@none' == self.repo.get_changeset('8430a588b43b5d6da365400117c89400326e7992').author_name
620
620
621
621
622 class TestGitSpecificWithRepo(_BackendTestMixin):
622 class TestGitSpecificWithRepo(_BackendTestMixin):
623 backend_alias = 'git'
623 backend_alias = 'git'
624
624
625 @classmethod
625 @classmethod
626 def _get_commits(cls):
626 def _get_commits(cls):
627 return [
627 return [
628 {
628 {
629 'message': 'Initial',
629 'message': 'Initial',
630 'author': 'Joe Doe <joe.doe@example.com>',
630 'author': 'Joe Doe <joe.doe@example.com>',
631 'date': datetime.datetime(2010, 1, 1, 20),
631 'date': datetime.datetime(2010, 1, 1, 20),
632 'added': [
632 'added': [
633 FileNode('foobar/static/js/admin/base.js', content='base'),
633 FileNode('foobar/static/js/admin/base.js', content='base'),
634 FileNode('foobar/static/admin', content='admin',
634 FileNode('foobar/static/admin', content='admin',
635 mode=0o120000), # this is a link
635 mode=0o120000), # this is a link
636 FileNode('foo', content='foo'),
636 FileNode('foo', content='foo'),
637 ],
637 ],
638 },
638 },
639 {
639 {
640 'message': 'Second',
640 'message': 'Second',
641 'author': 'Joe Doe <joe.doe@example.com>',
641 'author': 'Joe Doe <joe.doe@example.com>',
642 'date': datetime.datetime(2010, 1, 1, 22),
642 'date': datetime.datetime(2010, 1, 1, 22),
643 'added': [
643 'added': [
644 FileNode('foo2', content='foo2'),
644 FileNode('foo2', content='foo2'),
645 ],
645 ],
646 },
646 },
647 ]
647 ]
648
648
649 def test_paths_slow_traversing(self):
649 def test_paths_slow_traversing(self):
650 cs = self.repo.get_changeset()
650 cs = self.repo.get_changeset()
651 assert cs.get_node('foobar').get_node('static').get_node('js').get_node('admin').get_node('base.js').content == b'base'
651 assert cs.get_node('foobar').get_node('static').get_node('js').get_node('admin').get_node('base.js').content == b'base'
652
652
653 def test_paths_fast_traversing(self):
653 def test_paths_fast_traversing(self):
654 cs = self.repo.get_changeset()
654 cs = self.repo.get_changeset()
655 assert cs.get_node('foobar/static/js/admin/base.js').content == b'base'
655 assert cs.get_node('foobar/static/js/admin/base.js').content == b'base'
656
656
657 def test_workdir_get_branch(self):
657 def test_workdir_get_branch(self):
658 self.repo.run_git_command(['checkout', '-b', 'production'])
658 self.repo.run_git_command(['checkout', '-b', 'production'])
659 # Regression test: one of following would fail if we don't check
659 # Regression test: one of following would fail if we don't check
660 # .git/HEAD file
660 # .git/HEAD file
661 self.repo.run_git_command(['checkout', 'production'])
661 self.repo.run_git_command(['checkout', 'production'])
662 assert self.repo.workdir.get_branch() == 'production'
662 assert self.repo.workdir.get_branch() == 'production'
663 self.repo.run_git_command(['checkout', 'master'])
663 self.repo.run_git_command(['checkout', 'master'])
664 assert self.repo.workdir.get_branch() == 'master'
664 assert self.repo.workdir.get_branch() == 'master'
665
665
666 def test_get_diff_runs_git_command_with_hashes(self):
666 def test_get_diff_runs_git_command_with_hashes(self):
667 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
667 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
668 self.repo.get_diff(0, 1)
668 self.repo.get_diff(0, 1)
669 self.repo._run_git_command.assert_called_once_with(
669 self.repo._run_git_command.assert_called_once_with(
670 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
670 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
671 self.repo._get_revision(0), self.repo._get_revision(1)], cwd=self.repo.path)
671 self.repo._get_revision(0), self.repo._get_revision(1)], cwd=self.repo.path)
672
672
673 def test_get_diff_runs_git_command_with_str_hashes(self):
673 def test_get_diff_runs_git_command_with_str_hashes(self):
674 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
674 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
675 self.repo.get_diff(self.repo.EMPTY_CHANGESET, 1)
675 self.repo.get_diff(self.repo.EMPTY_CHANGESET, 1)
676 self.repo._run_git_command.assert_called_once_with(
676 self.repo._run_git_command.assert_called_once_with(
677 ['show', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
677 ['show', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
678 self.repo._get_revision(1)], cwd=self.repo.path)
678 self.repo._get_revision(1)], cwd=self.repo.path)
679
679
680 def test_get_diff_runs_git_command_with_path_if_its_given(self):
680 def test_get_diff_runs_git_command_with_path_if_its_given(self):
681 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
681 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
682 self.repo.get_diff(0, 1, 'foo')
682 self.repo.get_diff(0, 1, 'foo')
683 self.repo._run_git_command.assert_called_once_with(
683 self.repo._run_git_command.assert_called_once_with(
684 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
684 ['diff', '-U3', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
685 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
685 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
686
686
687 def test_get_diff_does_not_sanitize_valid_context(self):
687 def test_get_diff_does_not_sanitize_valid_context(self):
688 almost_overflowed_long_int = 2**31-1
688 almost_overflowed_long_int = 2**31-1
689
689
690 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
690 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
691 self.repo.get_diff(0, 1, 'foo', context=almost_overflowed_long_int)
691 self.repo.get_diff(0, 1, 'foo', context=almost_overflowed_long_int)
692 self.repo._run_git_command.assert_called_once_with(
692 self.repo._run_git_command.assert_called_once_with(
693 ['diff', '-U' + str(almost_overflowed_long_int), '--full-index', '--binary', '-p', '-M', '--abbrev=40',
693 ['diff', '-U' + str(almost_overflowed_long_int), '--full-index', '--binary', '-p', '-M', '--abbrev=40',
694 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
694 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
695
695
696 def test_get_diff_sanitizes_overflowing_context(self):
696 def test_get_diff_sanitizes_overflowing_context(self):
697 overflowed_long_int = 2**31
697 overflowed_long_int = 2**31
698 sanitized_overflowed_long_int = overflowed_long_int-1
698 sanitized_overflowed_long_int = overflowed_long_int-1
699
699
700 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
700 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
701 self.repo.get_diff(0, 1, 'foo', context=overflowed_long_int)
701 self.repo.get_diff(0, 1, 'foo', context=overflowed_long_int)
702
702
703 self.repo._run_git_command.assert_called_once_with(
703 self.repo._run_git_command.assert_called_once_with(
704 ['diff', '-U' + str(sanitized_overflowed_long_int), '--full-index', '--binary', '-p', '-M', '--abbrev=40',
704 ['diff', '-U' + str(sanitized_overflowed_long_int), '--full-index', '--binary', '-p', '-M', '--abbrev=40',
705 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
705 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
706
706
707 def test_get_diff_does_not_sanitize_zero_context(self):
707 def test_get_diff_does_not_sanitize_zero_context(self):
708 zero_context = 0
708 zero_context = 0
709
709
710 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
710 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
711 self.repo.get_diff(0, 1, 'foo', context=zero_context)
711 self.repo.get_diff(0, 1, 'foo', context=zero_context)
712
712
713 self.repo._run_git_command.assert_called_once_with(
713 self.repo._run_git_command.assert_called_once_with(
714 ['diff', '-U' + str(zero_context), '--full-index', '--binary', '-p', '-M', '--abbrev=40',
714 ['diff', '-U' + str(zero_context), '--full-index', '--binary', '-p', '-M', '--abbrev=40',
715 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
715 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
716
716
717 def test_get_diff_sanitizes_negative_context(self):
717 def test_get_diff_sanitizes_negative_context(self):
718 negative_context = -10
718 negative_context = -10
719
719
720 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
720 self.repo._run_git_command = mock.Mock(return_value=(b'', b''))
721 self.repo.get_diff(0, 1, 'foo', context=negative_context)
721 self.repo.get_diff(0, 1, 'foo', context=negative_context)
722
722
723 self.repo._run_git_command.assert_called_once_with(
723 self.repo._run_git_command.assert_called_once_with(
724 ['diff', '-U0', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
724 ['diff', '-U0', '--full-index', '--binary', '-p', '-M', '--abbrev=40',
725 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
725 self.repo._get_revision(0), self.repo._get_revision(1), '--', 'foo'], cwd=self.repo.path)
726
726
727
727
728 class TestGitRegression(_BackendTestMixin):
728 class TestGitRegression(_BackendTestMixin):
729 backend_alias = 'git'
729 backend_alias = 'git'
730
730
731 @classmethod
731 @classmethod
732 def _get_commits(cls):
732 def _get_commits(cls):
733 return [
733 return [
734 {
734 {
735 'message': 'Initial',
735 'message': 'Initial',
736 'author': 'Joe Doe <joe.doe@example.com>',
736 'author': 'Joe Doe <joe.doe@example.com>',
737 'date': datetime.datetime(2010, 1, 1, 20),
737 'date': datetime.datetime(2010, 1, 1, 20),
738 'added': [
738 'added': [
739 FileNode('bot/__init__.py', content='base'),
739 FileNode('bot/__init__.py', content='base'),
740 FileNode('bot/templates/404.html', content='base'),
740 FileNode('bot/templates/404.html', content='base'),
741 FileNode('bot/templates/500.html', content='base'),
741 FileNode('bot/templates/500.html', content='base'),
742 ],
742 ],
743 },
743 },
744 {
744 {
745 'message': 'Second',
745 'message': 'Second',
746 'author': 'Joe Doe <joe.doe@example.com>',
746 'author': 'Joe Doe <joe.doe@example.com>',
747 'date': datetime.datetime(2010, 1, 1, 22),
747 'date': datetime.datetime(2010, 1, 1, 22),
748 'added': [
748 'added': [
749 FileNode('bot/build/migrations/1.py', content='foo2'),
749 FileNode('bot/build/migrations/1.py', content='foo2'),
750 FileNode('bot/build/migrations/2.py', content='foo2'),
750 FileNode('bot/build/migrations/2.py', content='foo2'),
751 FileNode('bot/build/static/templates/f.html', content='foo2'),
751 FileNode('bot/build/static/templates/f.html', content='foo2'),
752 FileNode('bot/build/static/templates/f1.html', content='foo2'),
752 FileNode('bot/build/static/templates/f1.html', content='foo2'),
753 FileNode('bot/build/templates/err.html', content='foo2'),
753 FileNode('bot/build/templates/err.html', content='foo2'),
754 FileNode('bot/build/templates/err2.html', content='foo2'),
754 FileNode('bot/build/templates/err2.html', content='foo2'),
755 ],
755 ],
756 },
756 },
757 ]
757 ]
758
758
759 def test_similar_paths(self):
759 def test_similar_paths(self):
760 cs = self.repo.get_changeset()
760 cs = self.repo.get_changeset()
761 paths = lambda *n: [x.path for x in n]
761 def paths(*n):
762 return [x.path for x in n]
762 assert paths(*cs.get_nodes('bot')) == ['bot/build', 'bot/templates', 'bot/__init__.py']
763 assert paths(*cs.get_nodes('bot')) == ['bot/build', 'bot/templates', 'bot/__init__.py']
763 assert paths(*cs.get_nodes('bot/build')) == ['bot/build/migrations', 'bot/build/static', 'bot/build/templates']
764 assert paths(*cs.get_nodes('bot/build')) == ['bot/build/migrations', 'bot/build/static', 'bot/build/templates']
764 assert paths(*cs.get_nodes('bot/build/static')) == ['bot/build/static/templates']
765 assert paths(*cs.get_nodes('bot/build/static')) == ['bot/build/static/templates']
765 # this get_nodes below causes troubles !
766 # this get_nodes below causes troubles !
766 assert paths(*cs.get_nodes('bot/build/static/templates')) == ['bot/build/static/templates/f.html', 'bot/build/static/templates/f1.html']
767 assert paths(*cs.get_nodes('bot/build/static/templates')) == ['bot/build/static/templates/f.html', 'bot/build/static/templates/f1.html']
767 assert paths(*cs.get_nodes('bot/build/templates')) == ['bot/build/templates/err.html', 'bot/build/templates/err2.html']
768 assert paths(*cs.get_nodes('bot/build/templates')) == ['bot/build/templates/err.html', 'bot/build/templates/err2.html']
768 assert paths(*cs.get_nodes('bot/templates/')) == ['bot/templates/404.html', 'bot/templates/500.html']
769 assert paths(*cs.get_nodes('bot/templates/')) == ['bot/templates/404.html', 'bot/templates/500.html']
769
770
770
771
771 class TestGitHooks(object):
772 class TestGitHooks(object):
772 """
773 """
773 Tests related to hook functionality of Git repositories.
774 Tests related to hook functionality of Git repositories.
774 """
775 """
775
776
776 def setup_method(self):
777 def setup_method(self):
777 # For each run we want a fresh repo.
778 # For each run we want a fresh repo.
778 self.repo_directory = get_new_dir("githookrepo")
779 self.repo_directory = get_new_dir("githookrepo")
779 self.repo = GitRepository(self.repo_directory, create=True)
780 self.repo = GitRepository(self.repo_directory, create=True)
780
781
781 # Create a dictionary where keys are hook names, and values are paths to
782 # Create a dictionary where keys are hook names, and values are paths to
782 # them in the non-bare repo. Deduplicates code in tests a bit.
783 # them in the non-bare repo. Deduplicates code in tests a bit.
783 self.pre_receive = os.path.join(self.repo.path, '.git', 'hooks', "pre-receive")
784 self.pre_receive = os.path.join(self.repo.path, '.git', 'hooks', "pre-receive")
784 self.post_receive = os.path.join(self.repo.path, '.git', 'hooks', "post-receive")
785 self.post_receive = os.path.join(self.repo.path, '.git', 'hooks', "post-receive")
785 self.kallithea_hooks = {
786 self.kallithea_hooks = {
786 "pre-receive": self.pre_receive,
787 "pre-receive": self.pre_receive,
787 "post-receive": self.post_receive,
788 "post-receive": self.post_receive,
788 }
789 }
789
790
790 def test_hooks_created_if_missing(self):
791 def test_hooks_created_if_missing(self):
791 """
792 """
792 Tests if hooks are installed in repository if they are missing.
793 Tests if hooks are installed in repository if they are missing.
793 """
794 """
794
795
795 for hook, hook_path in self.kallithea_hooks.items():
796 for hook, hook_path in self.kallithea_hooks.items():
796 if os.path.exists(hook_path):
797 if os.path.exists(hook_path):
797 os.remove(hook_path)
798 os.remove(hook_path)
798
799
799 ScmModel().install_git_hooks(self.repo)
800 ScmModel().install_git_hooks(self.repo)
800
801
801 assert not os.path.exists(self.pre_receive)
802 assert not os.path.exists(self.pre_receive)
802 assert os.path.exists(self.post_receive)
803 assert os.path.exists(self.post_receive)
803
804
804 def test_kallithea_hooks_updated(self):
805 def test_kallithea_hooks_updated(self):
805 """
806 """
806 Tests if hooks are updated if they are Kallithea hooks already.
807 Tests if hooks are updated if they are Kallithea hooks already.
807 """
808 """
808
809
809 for hook, hook_path in self.kallithea_hooks.items():
810 for hook, hook_path in self.kallithea_hooks.items():
810 with open(hook_path, "w") as f:
811 with open(hook_path, "w") as f:
811 f.write("KALLITHEA_HOOK_VER=0.0.0\nJUST_BOGUS")
812 f.write("KALLITHEA_HOOK_VER=0.0.0\nJUST_BOGUS")
812
813
813 ScmModel().install_git_hooks(self.repo)
814 ScmModel().install_git_hooks(self.repo)
814
815
815 assert not os.path.exists(self.pre_receive)
816 assert not os.path.exists(self.pre_receive)
816 with open(self.post_receive) as f:
817 with open(self.post_receive) as f:
817 assert "JUST_BOGUS" not in f.read()
818 assert "JUST_BOGUS" not in f.read()
818
819
819 def test_custom_hooks_untouched(self):
820 def test_custom_hooks_untouched(self):
820 """
821 """
821 Tests if hooks are left untouched if they are not Kallithea hooks.
822 Tests if hooks are left untouched if they are not Kallithea hooks.
822 """
823 """
823
824
824 for hook, hook_path in self.kallithea_hooks.items():
825 for hook, hook_path in self.kallithea_hooks.items():
825 with open(hook_path, "w") as f:
826 with open(hook_path, "w") as f:
826 f.write("#!/bin/bash\n#CUSTOM_HOOK")
827 f.write("#!/bin/bash\n#CUSTOM_HOOK")
827
828
828 ScmModel().install_git_hooks(self.repo)
829 ScmModel().install_git_hooks(self.repo)
829
830
830 for hook, hook_path in self.kallithea_hooks.items():
831 for hook, hook_path in self.kallithea_hooks.items():
831 with open(hook_path) as f:
832 with open(hook_path) as f:
832 assert "CUSTOM_HOOK" in f.read()
833 assert "CUSTOM_HOOK" in f.read()
833
834
834 def test_custom_hooks_forced_update(self):
835 def test_custom_hooks_forced_update(self):
835 """
836 """
836 Tests if hooks are forcefully updated even though they are custom hooks.
837 Tests if hooks are forcefully updated even though they are custom hooks.
837 """
838 """
838
839
839 for hook, hook_path in self.kallithea_hooks.items():
840 for hook, hook_path in self.kallithea_hooks.items():
840 with open(hook_path, "w") as f:
841 with open(hook_path, "w") as f:
841 f.write("#!/bin/bash\n#CUSTOM_HOOK")
842 f.write("#!/bin/bash\n#CUSTOM_HOOK")
842
843
843 ScmModel().install_git_hooks(self.repo, force=True)
844 ScmModel().install_git_hooks(self.repo, force=True)
844
845
845 with open(self.pre_receive) as f:
846 with open(self.pre_receive) as f:
846 assert "KALLITHEA_HOOK_VER" not in f.read()
847 assert "KALLITHEA_HOOK_VER" not in f.read()
847 with open(self.post_receive) as f:
848 with open(self.post_receive) as f:
848 assert "KALLITHEA_HOOK_VER" in f.read()
849 assert "KALLITHEA_HOOK_VER" in f.read()
General Comments 0
You need to be logged in to leave comments. Login now