##// END OF EJS Templates
tests: avoid collision with dev servers - use port 4999 for testing
Mads Kiilerich -
r5388:5f932134 default
parent child Browse files
Show More
@@ -1,536 +1,536 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.tests.other.manual_test_vcs_operations
16 16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 Test suite for making push/pull operations.
19 19
20 20 Run it in two terminals::
21 21 paster serve test.ini
22 22 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 nosetests kallithea/tests/other/manual_test_vcs_operations.py
23 23
24 24 You must have git > 1.8.1 for tests to work fine
25 25
26 26 This file was forked by the Kallithea project in July 2014.
27 27 Original author and date, and relevant copyright and licensing information is below:
28 28 :created_on: Dec 30, 2010
29 29 :author: marcink
30 30 :copyright: (c) 2013 RhodeCode GmbH, and others.
31 31 :license: GPLv3, see LICENSE.md for more details.
32 32
33 33 """
34 34
35 35 import tempfile
36 36 import time
37 37 from os.path import join as jn
38 38
39 39 from tempfile import _RandomNameSequence
40 40 from subprocess import Popen, PIPE
41 41
42 42 from kallithea.tests import *
43 43 from kallithea.model.db import User, Repository, UserIpMap, CacheInvalidation
44 44 from kallithea.model.meta import Session
45 45 from kallithea.model.repo import RepoModel
46 46 from kallithea.model.user import UserModel
47 47
48 48 DEBUG = True
49 HOST = '127.0.0.1:5000' # test host
49 HOST = '127.0.0.1:4999' # test host
50 50
51 51
52 52 class Command(object):
53 53
54 54 def __init__(self, cwd):
55 55 self.cwd = cwd
56 56
57 57 def execute(self, cmd, *args):
58 58 """
59 59 Runs command on the system with given ``args``.
60 60 """
61 61
62 62 command = cmd + ' ' + ' '.join(args)
63 63 if DEBUG:
64 64 print '*** CMD %s ***' % command
65 65 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
66 66 stdout, stderr = p.communicate()
67 67 if DEBUG:
68 68 print 'stdout:', repr(stdout)
69 69 print 'stderr:', repr(stderr)
70 70 return stdout, stderr
71 71
72 72
73 73 def _get_tmp_dir():
74 74 return tempfile.mkdtemp(prefix='rc_integration_test')
75 75
76 76
77 77 def _construct_url(repo, dest=None, **kwargs):
78 78 if dest is None:
79 79 #make temp clone
80 80 dest = _get_tmp_dir()
81 81 params = {
82 82 'user': TEST_USER_ADMIN_LOGIN,
83 83 'passwd': TEST_USER_ADMIN_PASS,
84 84 'host': HOST,
85 85 'cloned_repo': repo,
86 86 'dest': dest
87 87 }
88 88 params.update(**kwargs)
89 89 if params['user'] and params['passwd']:
90 90 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s %(dest)s' % params
91 91 else:
92 92 _url = 'http://(host)s/%(cloned_repo)s %(dest)s' % params
93 93 return _url
94 94
95 95
96 96 def _add_files_and_push(vcs, DEST, **kwargs):
97 97 """
98 98 Generate some files, add it to DEST repo and push back
99 99 vcs is git or hg and defines what VCS we want to make those files for
100 100
101 101 :param vcs:
102 102 :param DEST:
103 103 """
104 104 # commit some stuff into this repo
105 105 cwd = path = jn(DEST)
106 106 #added_file = jn(path, '%ssetupΔ…ΕΌΕΊΔ‡.py' % _RandomNameSequence().next())
107 107 added_file = jn(path, '%ssetup.py' % _RandomNameSequence().next())
108 108 Command(cwd).execute('touch %s' % added_file)
109 109 Command(cwd).execute('%s add %s' % (vcs, added_file))
110 110
111 111 for i in xrange(kwargs.get('files_no', 3)):
112 112 cmd = """echo 'added_line%s' >> %s""" % (i, added_file)
113 113 Command(cwd).execute(cmd)
114 114 author_str = 'User ǝɯɐᴎ <me@email.com>'
115 115 if vcs == 'hg':
116 116 cmd = """hg commit -m 'commited new %s' -u '%s' %s """ % (
117 117 i, author_str, added_file
118 118 )
119 119 elif vcs == 'git':
120 120 cmd = """EMAIL="me@email.com" git commit -m 'commited new %s' --author '%s' %s """ % (
121 121 i, author_str, added_file
122 122 )
123 123 Command(cwd).execute(cmd)
124 124
125 125 # PUSH it back
126 126 _REPO = None
127 127 if vcs == 'hg':
128 128 _REPO = HG_REPO
129 129 elif vcs == 'git':
130 130 _REPO = GIT_REPO
131 131
132 132 kwargs['dest'] = ''
133 133 clone_url = _construct_url(_REPO, **kwargs)
134 134 if 'clone_url' in kwargs:
135 135 clone_url = kwargs['clone_url']
136 136 stdout = stderr = None
137 137 if vcs == 'hg':
138 138 stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
139 139 elif vcs == 'git':
140 140 stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
141 141
142 142 return stdout, stderr
143 143
144 144
145 145 def set_anonymous_access(enable=True):
146 146 user = User.get_by_username(User.DEFAULT_USER)
147 147 user.active = enable
148 148 Session().add(user)
149 149 Session().commit()
150 150 print '\tanonymous access is now:', enable
151 151 if enable != User.get_by_username(User.DEFAULT_USER).active:
152 152 raise Exception('Cannot set anonymous access')
153 153
154 154
155 155 #==============================================================================
156 156 # TESTS
157 157 #==============================================================================
158 158
159 159
160 160 def _check_proper_git_push(stdout, stderr):
161 161 #WTF Git stderr is output ?!
162 162 assert 'fatal' not in stderr
163 163 assert 'rejected' not in stderr
164 164 assert 'Pushing to' in stderr
165 165 assert 'master -> master' in stderr
166 166
167 167
168 168 class TestVCSOperations(BaseTestCase):
169 169
170 170 @classmethod
171 171 def setup_class(cls):
172 172 #DISABLE ANONYMOUS ACCESS
173 173 set_anonymous_access(False)
174 174
175 175 def setUp(self):
176 176 r = Repository.get_by_repo_name(GIT_REPO)
177 177 Repository.unlock(r)
178 178 r.enable_locking = False
179 179 Session().add(r)
180 180 Session().commit()
181 181
182 182 r = Repository.get_by_repo_name(HG_REPO)
183 183 Repository.unlock(r)
184 184 r.enable_locking = False
185 185 Session().add(r)
186 186 Session().commit()
187 187
188 188 def test_clone_hg_repo_by_admin(self):
189 189 clone_url = _construct_url(HG_REPO)
190 190 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
191 191
192 192 assert 'requesting all changes' in stdout
193 193 assert 'adding changesets' in stdout
194 194 assert 'adding manifests' in stdout
195 195 assert 'adding file changes' in stdout
196 196
197 197 assert stderr == ''
198 198
199 199 def test_clone_git_repo_by_admin(self):
200 200 clone_url = _construct_url(GIT_REPO)
201 201 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
202 202
203 203 assert 'Cloning into' in stdout + stderr
204 204 assert stderr == '' or stdout == ''
205 205
206 206 def test_clone_wrong_credentials_hg(self):
207 207 clone_url = _construct_url(HG_REPO, passwd='bad!')
208 208 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
209 209 assert 'abort: authorization failed' in stderr
210 210
211 211 def test_clone_wrong_credentials_git(self):
212 212 clone_url = _construct_url(GIT_REPO, passwd='bad!')
213 213 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
214 214 assert 'fatal: Authentication failed' in stderr
215 215
216 216 def test_clone_git_dir_as_hg(self):
217 217 clone_url = _construct_url(GIT_REPO)
218 218 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
219 219 assert 'HTTP Error 404: Not Found' in stderr
220 220
221 221 def test_clone_hg_repo_as_git(self):
222 222 clone_url = _construct_url(HG_REPO)
223 223 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
224 224 assert 'not found' in stderr
225 225
226 226 def test_clone_non_existing_path_hg(self):
227 227 clone_url = _construct_url('trololo')
228 228 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
229 229 assert 'HTTP Error 404: Not Found' in stderr
230 230
231 231 def test_clone_non_existing_path_git(self):
232 232 clone_url = _construct_url('trololo')
233 233 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
234 234 assert 'not found' in stderr
235 235
236 236 def test_push_new_file_hg(self):
237 237 DEST = _get_tmp_dir()
238 238 clone_url = _construct_url(HG_REPO, dest=DEST)
239 239 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
240 240
241 241 stdout, stderr = _add_files_and_push('hg', DEST)
242 242
243 243 assert 'pushing to' in stdout
244 244 assert 'Repository size' in stdout
245 245 assert 'Last revision is now' in stdout
246 246
247 247 def test_push_new_file_git(self):
248 248 DEST = _get_tmp_dir()
249 249 clone_url = _construct_url(GIT_REPO, dest=DEST)
250 250 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
251 251
252 252 # commit some stuff into this repo
253 253 stdout, stderr = _add_files_and_push('git', DEST)
254 254
255 255 print [(x.repo_full_path,x.repo_path) for x in Repository.get_all()]
256 256 _check_proper_git_push(stdout, stderr)
257 257
258 258 def test_push_invalidates_cache_hg(self):
259 259 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
260 260 ==HG_REPO).scalar()
261 261 if not key:
262 262 key = CacheInvalidation(HG_REPO, HG_REPO)
263 263
264 264 key.cache_active = True
265 265 Session().add(key)
266 266 Session().commit()
267 267
268 268 DEST = _get_tmp_dir()
269 269 clone_url = _construct_url(HG_REPO, dest=DEST)
270 270 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
271 271
272 272 stdout, stderr = _add_files_and_push('hg', DEST, files_no=1)
273 273
274 274 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
275 275 ==HG_REPO).one()
276 276 self.assertEqual(key.cache_active, False)
277 277
278 278 def test_push_invalidates_cache_git(self):
279 279 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
280 280 ==GIT_REPO).scalar()
281 281 if not key:
282 282 key = CacheInvalidation(GIT_REPO, GIT_REPO)
283 283
284 284 key.cache_active = True
285 285 Session().add(key)
286 286 Session().commit()
287 287
288 288 DEST = _get_tmp_dir()
289 289 clone_url = _construct_url(GIT_REPO, dest=DEST)
290 290 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
291 291
292 292 # commit some stuff into this repo
293 293 stdout, stderr = _add_files_and_push('git', DEST, files_no=1)
294 294 _check_proper_git_push(stdout, stderr)
295 295
296 296 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
297 297 ==GIT_REPO).one()
298 298 print CacheInvalidation.get_all()
299 299 self.assertEqual(key.cache_active, False)
300 300
301 301 def test_push_wrong_credentials_hg(self):
302 302 DEST = _get_tmp_dir()
303 303 clone_url = _construct_url(HG_REPO, dest=DEST)
304 304 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
305 305
306 306 stdout, stderr = _add_files_and_push('hg', DEST, user='bad',
307 307 passwd='name')
308 308
309 309 assert 'abort: authorization failed' in stderr
310 310
311 311 def test_push_wrong_credentials_git(self):
312 312 DEST = _get_tmp_dir()
313 313 clone_url = _construct_url(GIT_REPO, dest=DEST)
314 314 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
315 315
316 316 stdout, stderr = _add_files_and_push('git', DEST, user='bad',
317 317 passwd='name')
318 318
319 319 assert 'fatal: Authentication failed' in stderr
320 320
321 321 def test_push_back_to_wrong_url_hg(self):
322 322 DEST = _get_tmp_dir()
323 323 clone_url = _construct_url(HG_REPO, dest=DEST)
324 324 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
325 325
326 326 stdout, stderr = _add_files_and_push('hg', DEST,
327 clone_url='http://127.0.0.1:5000/tmp',)
327 clone_url='http://%s/tmp' % HOST)
328 328
329 329 assert 'HTTP Error 404: Not Found' in stderr
330 330
331 331 def test_push_back_to_wrong_url_git(self):
332 332 DEST = _get_tmp_dir()
333 333 clone_url = _construct_url(GIT_REPO, dest=DEST)
334 334 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
335 335
336 336 stdout, stderr = _add_files_and_push('git', DEST,
337 clone_url='http://127.0.0.1:5000/tmp',)
337 clone_url='http://%s/tmp' % HOST)
338 338
339 339 assert 'not found' in stderr
340 340
341 341 def test_clone_and_create_lock_hg(self):
342 342 # enable locking
343 343 r = Repository.get_by_repo_name(HG_REPO)
344 344 r.enable_locking = True
345 345 Session().add(r)
346 346 Session().commit()
347 347 # clone
348 348 clone_url = _construct_url(HG_REPO)
349 349 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
350 350
351 351 #check if lock was made
352 352 r = Repository.get_by_repo_name(HG_REPO)
353 353 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
354 354
355 355 def test_clone_and_create_lock_git(self):
356 356 # enable locking
357 357 r = Repository.get_by_repo_name(GIT_REPO)
358 358 r.enable_locking = True
359 359 Session().add(r)
360 360 Session().commit()
361 361 # clone
362 362 clone_url = _construct_url(GIT_REPO)
363 363 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
364 364
365 365 #check if lock was made
366 366 r = Repository.get_by_repo_name(GIT_REPO)
367 367 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
368 368
369 369 def test_clone_after_repo_was_locked_hg(self):
370 370 #lock repo
371 371 r = Repository.get_by_repo_name(HG_REPO)
372 372 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
373 373 #pull fails since repo is locked
374 374 clone_url = _construct_url(HG_REPO)
375 375 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
376 376 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
377 377 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
378 378 assert msg in stderr
379 379
380 380 def test_clone_after_repo_was_locked_git(self):
381 381 #lock repo
382 382 r = Repository.get_by_repo_name(GIT_REPO)
383 383 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
384 384 #pull fails since repo is locked
385 385 clone_url = _construct_url(GIT_REPO)
386 386 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
387 387 msg = ("""The requested URL returned error: 423""")
388 388 assert msg in stderr
389 389
390 390 def test_push_on_locked_repo_by_other_user_hg(self):
391 391 #clone some temp
392 392 DEST = _get_tmp_dir()
393 393 clone_url = _construct_url(HG_REPO, dest=DEST)
394 394 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
395 395
396 396 #lock repo
397 397 r = Repository.get_by_repo_name(HG_REPO)
398 398 # let this user actually push !
399 399 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
400 400 perm='repository.write')
401 401 Session().commit()
402 402 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
403 403
404 404 #push fails repo is locked by other user !
405 405 stdout, stderr = _add_files_and_push('hg', DEST,
406 406 user=TEST_USER_REGULAR_LOGIN,
407 407 passwd=TEST_USER_REGULAR_PASS)
408 408 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
409 409 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
410 410 assert msg in stderr
411 411
412 412 def test_push_on_locked_repo_by_other_user_git(self):
413 413 #clone some temp
414 414 DEST = _get_tmp_dir()
415 415 clone_url = _construct_url(GIT_REPO, dest=DEST)
416 416 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
417 417
418 418 #lock repo
419 419 r = Repository.get_by_repo_name(GIT_REPO)
420 420 # let this user actually push !
421 421 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
422 422 perm='repository.write')
423 423 Session().commit()
424 424 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
425 425
426 426 #push fails repo is locked by other user !
427 427 stdout, stderr = _add_files_and_push('git', DEST,
428 428 user=TEST_USER_REGULAR_LOGIN,
429 429 passwd=TEST_USER_REGULAR_PASS)
430 430 err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN)
431 431 assert err in stderr
432 432
433 433 #TODO: fix this somehow later on Git, Git is stupid and even if we throw
434 434 #back 423 to it, it makes ANOTHER request and we fail there with 405 :/
435 435
436 436 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
437 437 % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
438 438 #msg = "405 Method Not Allowed"
439 439 #assert msg in stderr
440 440
441 441 def test_push_unlocks_repository_hg(self):
442 442 # enable locking
443 443 r = Repository.get_by_repo_name(HG_REPO)
444 444 r.enable_locking = True
445 445 Session().add(r)
446 446 Session().commit()
447 447 #clone some temp
448 448 DEST = _get_tmp_dir()
449 449 clone_url = _construct_url(HG_REPO, dest=DEST)
450 450 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
451 451
452 452 #check for lock repo after clone
453 453 r = Repository.get_by_repo_name(HG_REPO)
454 454 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
455 455 assert r.locked[0] == uid
456 456
457 457 #push is ok and repo is now unlocked
458 458 stdout, stderr = _add_files_and_push('hg', DEST)
459 459 assert ('remote: Released lock on repo `%s`' % HG_REPO) in stdout
460 460 #we need to cleanup the Session Here !
461 461 Session.remove()
462 462 r = Repository.get_by_repo_name(HG_REPO)
463 463 assert r.locked == [None, None]
464 464
465 465 #TODO: fix me ! somehow during tests hooks don't get called on Git
466 466 def test_push_unlocks_repository_git(self):
467 467 # enable locking
468 468 r = Repository.get_by_repo_name(GIT_REPO)
469 469 r.enable_locking = True
470 470 Session().add(r)
471 471 Session().commit()
472 472 #clone some temp
473 473 DEST = _get_tmp_dir()
474 474 clone_url = _construct_url(GIT_REPO, dest=DEST)
475 475 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
476 476
477 477 #check for lock repo after clone
478 478 r = Repository.get_by_repo_name(GIT_REPO)
479 479 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
480 480
481 481 #push is ok and repo is now unlocked
482 482 stdout, stderr = _add_files_and_push('git', DEST)
483 483 _check_proper_git_push(stdout, stderr)
484 484
485 485 #assert ('remote: Released lock on repo `%s`' % GIT_REPO) in stdout
486 486 #we need to cleanup the Session Here !
487 487 Session.remove()
488 488 r = Repository.get_by_repo_name(GIT_REPO)
489 489 assert r.locked == [None, None]
490 490
491 491 def test_ip_restriction_hg(self):
492 492 user_model = UserModel()
493 493 try:
494 494 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
495 495 Session().commit()
496 496 clone_url = _construct_url(HG_REPO)
497 497 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
498 498 assert 'abort: HTTP Error 403: Forbidden' in stderr
499 499 finally:
500 500 #release IP restrictions
501 501 for ip in UserIpMap.getAll():
502 502 UserIpMap.delete(ip.ip_id)
503 503 Session().commit()
504 504
505 505 time.sleep(2)
506 506 clone_url = _construct_url(HG_REPO)
507 507 stdout, stderr = Command('/tmp').execute('hg clone', clone_url)
508 508
509 509 assert 'requesting all changes' in stdout
510 510 assert 'adding changesets' in stdout
511 511 assert 'adding manifests' in stdout
512 512 assert 'adding file changes' in stdout
513 513
514 514 assert stderr == ''
515 515
516 516 def test_ip_restriction_git(self):
517 517 user_model = UserModel()
518 518 try:
519 519 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
520 520 Session().commit()
521 521 clone_url = _construct_url(GIT_REPO)
522 522 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
523 523 msg = ("""The requested URL returned error: 403""")
524 524 assert msg in stderr
525 525 finally:
526 526 #release IP restrictions
527 527 for ip in UserIpMap.getAll():
528 528 UserIpMap.delete(ip.ip_id)
529 529 Session().commit()
530 530
531 531 time.sleep(2)
532 532 clone_url = _construct_url(GIT_REPO)
533 533 stdout, stderr = Command('/tmp').execute('git clone', clone_url)
534 534
535 535 assert 'Cloning into' in stdout + stderr
536 536 assert stderr == '' or stdout == ''
@@ -1,614 +1,614 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # Kallithea - config for tests: #
4 4 # initial_repo_scan = true #
5 5 # vcs_full_cache = false #
6 6 # sqlalchemy and kallithea_test.sqlite #
7 7 # custom logging #
8 8 # #
9 9 # The %(here)s variable will be replaced with the parent directory of this file#
10 10 ################################################################################
11 11 ################################################################################
12 12
13 13 [DEFAULT]
14 14 debug = true
15 15 pdebug = false
16 16
17 17 ################################################################################
18 18 ## E-mail settings ##
19 19 ## ##
20 20 ## Refer to the documentation ("E-mail settings") for more details. ##
21 21 ## ##
22 22 ## It is recommended to use a valid sender address that passes access ##
23 23 ## validation and spam filtering in mail servers. ##
24 24 ################################################################################
25 25
26 26 ## 'From' header for application e-mails. You can optionally add a name.
27 27 ## Default:
28 28 #app_email_from = Kallithea
29 29 ## Examples:
30 30 #app_email_from = Kallithea <kallithea-noreply@example.com>
31 31 #app_email_from = kallithea-noreply@example.com
32 32
33 33 ## Subject prefix for application e-mails.
34 34 ## A space between this prefix and the real subject is automatically added.
35 35 ## Default:
36 36 #email_prefix =
37 37 ## Example:
38 38 #email_prefix = [Kallithea]
39 39
40 40 ## Recipients for error e-mails and fallback recipients of application mails.
41 41 ## Multiple addresses can be specified, space-separated.
42 42 ## Only addresses are allowed, do not add any name part.
43 43 ## Default:
44 44 #email_to =
45 45 ## Examples:
46 46 #email_to = admin@example.com
47 47 #email_to = admin@example.com another_admin@example.com
48 48
49 49 ## 'From' header for error e-mails. You can optionally add a name.
50 50 ## Default:
51 51 #error_email_from = pylons@yourapp.com
52 52 ## Examples:
53 53 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
54 54 #error_email_from = paste_error@example.com
55 55
56 56 ## SMTP server settings
57 57 ## Only smtp_server is mandatory. All other settings take the specified default
58 58 ## values.
59 59 #smtp_server = mail.server.com
60 60 #smtp_username =
61 61 #smtp_password =
62 62 #smtp_port = 25
63 63 #smtp_use_tls = false
64 64 #smtp_use_ssl = false
65 65 ## SMTP authentication parameters to use (e.g. LOGIN PLAIN CRAM-MD5, etc.).
66 66 ## If empty, use any of the authentication parameters supported by the server.
67 67 #smtp_auth =
68 68
69 69 [server:main]
70 70 ## PASTE ##
71 71 #use = egg:Paste#http
72 72 ## nr of worker threads to spawn
73 73 #threadpool_workers = 5
74 74 ## max request before thread respawn
75 75 #threadpool_max_requests = 10
76 76 ## option to use threads of process
77 77 #use_threadpool = true
78 78
79 79 ## WAITRESS ##
80 80 use = egg:waitress#main
81 81 ## number of worker threads
82 82 threads = 5
83 83 ## MAX BODY SIZE 100GB
84 84 max_request_body_size = 107374182400
85 85 ## use poll instead of select, fixes fd limits, may not work on old
86 86 ## windows systems.
87 87 #asyncore_use_poll = True
88 88
89 89 ## GUNICORN ##
90 90 #use = egg:gunicorn#main
91 91 ## number of process workers. You must set `instance_id = *` when this option
92 92 ## is set to more than one worker
93 93 #workers = 1
94 94 ## process name
95 95 #proc_name = kallithea
96 96 ## type of worker class, one of sync, eventlet, gevent, tornado
97 97 ## recommended for bigger setup is using of of other than sync one
98 98 #worker_class = sync
99 99 #max_requests = 1000
100 100 ## ammount of time a worker can handle request before it gets killed and
101 101 ## restarted
102 102 #timeout = 3600
103 103
104 104 ## UWSGI ##
105 105 ## run with uwsgi --ini-paste-logged <inifile.ini>
106 106 #[uwsgi]
107 107 #socket = /tmp/uwsgi.sock
108 108 #master = true
109 109 #http = 127.0.0.1:5000
110 110
111 111 ## set as deamon and redirect all output to file
112 112 #daemonize = ./uwsgi_kallithea.log
113 113
114 114 ## master process PID
115 115 #pidfile = ./uwsgi_kallithea.pid
116 116
117 117 ## stats server with workers statistics, use uwsgitop
118 118 ## for monitoring, `uwsgitop 127.0.0.1:1717`
119 119 #stats = 127.0.0.1:1717
120 120 #memory-report = true
121 121
122 122 ## log 5XX errors
123 123 #log-5xx = true
124 124
125 125 ## Set the socket listen queue size.
126 126 #listen = 256
127 127
128 128 ## Gracefully Reload workers after the specified amount of managed requests
129 129 ## (avoid memory leaks).
130 130 #max-requests = 1000
131 131
132 132 ## enable large buffers
133 133 #buffer-size = 65535
134 134
135 135 ## socket and http timeouts ##
136 136 #http-timeout = 3600
137 137 #socket-timeout = 3600
138 138
139 139 ## Log requests slower than the specified number of milliseconds.
140 140 #log-slow = 10
141 141
142 142 ## Exit if no app can be loaded.
143 143 #need-app = true
144 144
145 145 ## Set lazy mode (load apps in workers instead of master).
146 146 #lazy = true
147 147
148 148 ## scaling ##
149 149 ## set cheaper algorithm to use, if not set default will be used
150 150 #cheaper-algo = spare
151 151
152 152 ## minimum number of workers to keep at all times
153 153 #cheaper = 1
154 154
155 155 ## number of workers to spawn at startup
156 156 #cheaper-initial = 1
157 157
158 158 ## maximum number of workers that can be spawned
159 159 #workers = 4
160 160
161 161 ## how many workers should be spawned at a time
162 162 #cheaper-step = 1
163 163
164 164 ## COMMON ##
165 165 host = 127.0.0.1
166 port = 5000
166 port = 4999
167 167
168 168 ## middleware for hosting the WSGI application under a URL prefix
169 169 #[filter:proxy-prefix]
170 170 #use = egg:PasteDeploy#prefix
171 171 #prefix = /<your-prefix>
172 172
173 173 [app:main]
174 174 use = egg:kallithea
175 175 ## enable proxy prefix middleware
176 176 #filter-with = proxy-prefix
177 177
178 178 full_stack = true
179 179 static_files = true
180 180 ## Available Languages:
181 181 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
182 182 lang =
183 183 cache_dir = %(here)s/data
184 184 index_dir = %(here)s/data/index
185 185
186 186 ## perform a full repository scan on each server start, this should be
187 187 ## set to false after first startup, to allow faster server restarts.
188 188 #initial_repo_scan = false
189 189 initial_repo_scan = true
190 190
191 191 ## uncomment and set this path to use archive download cache
192 192 archive_cache_dir = %(here)s/tarballcache
193 193
194 194 ## change this to unique ID for security
195 195 app_instance_uuid = test
196 196
197 197 ## cut off limit for large diffs (size in bytes)
198 198 cut_off_limit = 256000
199 199
200 200 ## use cache version of scm repo everywhere
201 201 #vcs_full_cache = true
202 202 vcs_full_cache = false
203 203
204 204 ## force https in Kallithea, fixes https redirects, assumes it's always https
205 205 force_https = false
206 206
207 207 ## use Strict-Transport-Security headers
208 208 use_htsts = false
209 209
210 210 ## number of commits stats will parse on each iteration
211 211 commit_parse_limit = 25
212 212
213 213 ## path to git executable
214 214 git_path = git
215 215
216 216 ## git rev filter option, --all is the default filter, if you need to
217 217 ## hide all refs in changelog switch this to --branches --tags
218 218 #git_rev_filter = --branches --tags
219 219
220 220 ## RSS feed options
221 221 rss_cut_off_limit = 256000
222 222 rss_items_per_page = 10
223 223 rss_include_diff = false
224 224
225 225 ## options for showing and identifying changesets
226 226 show_sha_length = 12
227 227 show_revision_number = true
228 228
229 229 ## gist URL alias, used to create nicer urls for gist. This should be an
230 230 ## url that does rewrites to _admin/gists/<gistid>.
231 231 ## example: http://gist.kallithea.server/{gistid}. Empty means use the internal
232 232 ## Kallithea url, ie. http[s]://your.kallithea.server/_admin/gists/<gistid>
233 233 gist_alias_url =
234 234
235 235 ## white list of API enabled controllers. This allows to add list of
236 236 ## controllers to which access will be enabled by api_key. eg: to enable
237 237 ## api access to raw_files put `FilesController:raw`, to enable access to patches
238 238 ## add `ChangesetController:changeset_patch`. This list should be "," separated
239 239 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
240 240 ## Recommended settings below are commented out:
241 241 api_access_controllers_whitelist =
242 242 # ChangesetController:changeset_patch,
243 243 # ChangesetController:changeset_raw,
244 244 # FilesController:raw,
245 245 # FilesController:archivefile
246 246
247 247 ## default encoding used to convert from and to unicode
248 248 ## can be also a comma seperated list of encoding in case of mixed encodings
249 249 default_encoding = utf8
250 250
251 251 ## issue tracker for Kallithea (leave blank to disable, absent for default)
252 252 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
253 253
254 254 ## issue tracking mapping for commits messages
255 255 ## comment out issue_pat, issue_server, issue_prefix to enable
256 256
257 257 ## pattern to get the issues from commit messages
258 258 ## default one used here is #<numbers> with a regex passive group for `#`
259 259 ## {id} will be all groups matched from this pattern
260 260
261 261 issue_pat = (?:\s*#)(\d+)
262 262
263 263 ## server url to the issue, each {id} will be replaced with match
264 264 ## fetched from the regex and {repo} is replaced with full repository name
265 265 ## including groups {repo_name} is replaced with just name of repo
266 266
267 267 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
268 268
269 269 ## prefix to add to link to indicate it's an url
270 270 ## #314 will be replaced by <issue_prefix><id>
271 271
272 272 issue_prefix = #
273 273
274 274 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
275 275 ## multiple patterns, to other issues server, wiki or others
276 276 ## below an example how to create a wiki pattern
277 277 # wiki-some-id -> https://mywiki.com/some-id
278 278
279 279 #issue_pat_wiki = (?:wiki-)(.+)
280 280 #issue_server_link_wiki = https://mywiki.com/{id}
281 281 #issue_prefix_wiki = WIKI-
282 282
283 283 ## instance-id prefix
284 284 ## a prefix key for this instance used for cache invalidation when running
285 285 ## multiple instances of kallithea, make sure it's globally unique for
286 286 ## all running kallithea instances. Leave empty if you don't use it
287 287 instance_id =
288 288
289 289 ## alternative return HTTP header for failed authentication. Default HTTP
290 290 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
291 291 ## handling that. Set this variable to 403 to return HTTPForbidden
292 292 auth_ret_code =
293 293
294 294 ## locking return code. When repository is locked return this HTTP code. 2XX
295 295 ## codes don't break the transactions while 4XX codes do
296 296 lock_ret_code = 423
297 297
298 298 ## allows to change the repository location in settings page
299 299 allow_repo_location_change = True
300 300
301 301 ## allows to setup custom hooks in settings page
302 302 allow_custom_hooks_settings = True
303 303
304 304 ####################################
305 305 ### CELERY CONFIG ####
306 306 ####################################
307 307
308 308 use_celery = false
309 309 broker.host = localhost
310 310 broker.vhost = rabbitmqhost
311 311 broker.port = 5672
312 312 broker.user = rabbitmq
313 313 broker.password = qweqwe
314 314
315 315 celery.imports = kallithea.lib.celerylib.tasks
316 316
317 317 celery.result.backend = amqp
318 318 celery.result.dburi = amqp://
319 319 celery.result.serialier = json
320 320
321 321 #celery.send.task.error.emails = true
322 322 #celery.amqp.task.result.expires = 18000
323 323
324 324 celeryd.concurrency = 2
325 325 #celeryd.log.file = celeryd.log
326 326 celeryd.log.level = DEBUG
327 327 celeryd.max.tasks.per.child = 1
328 328
329 329 ## tasks will never be sent to the queue, but executed locally instead.
330 330 celery.always.eager = false
331 331
332 332 ####################################
333 333 ### BEAKER CACHE ####
334 334 ####################################
335 335
336 336 beaker.cache.data_dir = %(here)s/data/cache/data
337 337 beaker.cache.lock_dir = %(here)s/data/cache/lock
338 338
339 339 beaker.cache.regions = super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
340 340
341 341 beaker.cache.super_short_term.type = memory
342 342 beaker.cache.super_short_term.expire = 10
343 343 beaker.cache.super_short_term.key_length = 256
344 344
345 345 beaker.cache.short_term.type = memory
346 346 beaker.cache.short_term.expire = 60
347 347 beaker.cache.short_term.key_length = 256
348 348
349 349 beaker.cache.long_term.type = memory
350 350 beaker.cache.long_term.expire = 36000
351 351 beaker.cache.long_term.key_length = 256
352 352
353 353 beaker.cache.sql_cache_short.type = memory
354 354 beaker.cache.sql_cache_short.expire = 1
355 355 beaker.cache.sql_cache_short.key_length = 256
356 356
357 357 beaker.cache.sql_cache_med.type = memory
358 358 beaker.cache.sql_cache_med.expire = 360
359 359 beaker.cache.sql_cache_med.key_length = 256
360 360
361 361 beaker.cache.sql_cache_long.type = file
362 362 beaker.cache.sql_cache_long.expire = 3600
363 363 beaker.cache.sql_cache_long.key_length = 256
364 364
365 365 ####################################
366 366 ### BEAKER SESSION ####
367 367 ####################################
368 368 ## Type of storage used for the session, current types are
369 369 ## dbm, file, memcached, database, and memory.
370 370 ## The storage uses the Container API
371 371 ## that is also used by the cache system.
372 372
373 373 ## db session ##
374 374 #beaker.session.type = ext:database
375 375 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
376 376 #beaker.session.table_name = db_session
377 377
378 378 ## encrypted cookie client side session, good for many instances ##
379 379 #beaker.session.type = cookie
380 380
381 381 ## file based cookies (default) ##
382 382 #beaker.session.type = file
383 383
384 384 ## beaker.session.key should be unique for a given host, even when running
385 385 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
386 386 beaker.session.key = kallithea
387 387 beaker.session.secret = {74e0cd75-b339-478b-b129-07dd221def1f}
388 388
389 389 ## Secure encrypted cookie. Requires AES and AES python libraries
390 390 ## you must disable beaker.session.secret to use this
391 391 #beaker.session.encrypt_key = <key_for_encryption>
392 392 #beaker.session.validate_key = <validation_key>
393 393
394 394 ## sets session as invalid if it haven't been accessed for given amount of time
395 395 beaker.session.timeout = 2592000
396 396 beaker.session.httponly = true
397 397 #beaker.session.cookie_path = /<your-prefix>
398 398
399 399 ## uncomment for https secure cookie
400 400 beaker.session.secure = false
401 401
402 402 ## auto save the session to not to use .save()
403 403 beaker.session.auto = False
404 404
405 405 ## default cookie expiration time in seconds `true` expire at browser close ##
406 406 #beaker.session.cookie_expires = 3600
407 407
408 408 ############################
409 409 ## ERROR HANDLING SYSTEMS ##
410 410 ############################
411 411
412 412 ####################
413 413 ### [errormator] ###
414 414 ####################
415 415
416 416 ## Errormator is tailored to work with Kallithea, see
417 417 ## http://errormator.com for details how to obtain an account
418 418 ## you must install python package `errormator_client` to make it work
419 419
420 420 ## errormator enabled
421 421 errormator = false
422 422
423 423 errormator.server_url = https://api.errormator.com
424 424 errormator.api_key = YOUR_API_KEY
425 425
426 426 ## TWEAK AMOUNT OF INFO SENT HERE
427 427
428 428 ## enables 404 error logging (default False)
429 429 errormator.report_404 = false
430 430
431 431 ## time in seconds after request is considered being slow (default 1)
432 432 errormator.slow_request_time = 1
433 433
434 434 ## record slow requests in application
435 435 ## (needs to be enabled for slow datastore recording and time tracking)
436 436 errormator.slow_requests = true
437 437
438 438 ## enable hooking to application loggers
439 439 #errormator.logging = true
440 440
441 441 ## minimum log level for log capture
442 442 #errormator.logging.level = WARNING
443 443
444 444 ## send logs only from erroneous/slow requests
445 445 ## (saves API quota for intensive logging)
446 446 errormator.logging_on_error = false
447 447
448 448 ## list of additonal keywords that should be grabbed from environ object
449 449 ## can be string with comma separated list of words in lowercase
450 450 ## (by default client will always send following info:
451 451 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
452 452 ## start with HTTP* this list be extended with additional keywords here
453 453 errormator.environ_keys_whitelist =
454 454
455 455 ## list of keywords that should be blanked from request object
456 456 ## can be string with comma separated list of words in lowercase
457 457 ## (by default client will always blank keys that contain following words
458 458 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
459 459 ## this list be extended with additional keywords set here
460 460 errormator.request_keys_blacklist =
461 461
462 462 ## list of namespaces that should be ignores when gathering log entries
463 463 ## can be string with comma separated list of namespaces
464 464 ## (by default the client ignores own entries: errormator_client.client)
465 465 errormator.log_namespace_blacklist =
466 466
467 467 ################
468 468 ### [sentry] ###
469 469 ################
470 470
471 471 ## sentry is a alternative open source error aggregator
472 472 ## you must install python packages `sentry` and `raven` to enable
473 473
474 474 sentry.dsn = YOUR_DNS
475 475 sentry.servers =
476 476 sentry.name =
477 477 sentry.key =
478 478 sentry.public_key =
479 479 sentry.secret_key =
480 480 sentry.project =
481 481 sentry.site =
482 482 sentry.include_paths =
483 483 sentry.exclude_paths =
484 484
485 485 ################################################################################
486 486 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
487 487 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
488 488 ## execute malicious code after an exception is raised. ##
489 489 ################################################################################
490 490 set debug = false
491 491
492 492 ##################################
493 493 ### LOGVIEW CONFIG ###
494 494 ##################################
495 495
496 496 logview.sqlalchemy = #faa
497 497 logview.pylons.templating = #bfb
498 498 logview.pylons.util = #eee
499 499
500 500 #########################################################
501 501 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
502 502 #########################################################
503 503
504 504 # SQLITE [default]
505 505 #sqlalchemy.db1.url = sqlite:///%(here)s/kallithea.db?timeout=60
506 506 sqlalchemy.db1.url = sqlite:///%(here)s/kallithea_test.sqlite
507 507
508 508 # POSTGRESQL
509 509 #sqlalchemy.db1.url = postgresql://user:pass@localhost/kallithea
510 510
511 511 # MySQL
512 512 #sqlalchemy.db1.url = mysql://user:pass@localhost/kallithea
513 513
514 514 # see sqlalchemy docs for others
515 515
516 516 sqlalchemy.db1.echo = false
517 517 sqlalchemy.db1.pool_recycle = 3600
518 518 sqlalchemy.db1.convert_unicode = true
519 519
520 520 ################################
521 521 ### LOGGING CONFIGURATION ####
522 522 ################################
523 523
524 524 [loggers]
525 525 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
526 526
527 527 [handlers]
528 528 keys = console, console_sql
529 529
530 530 [formatters]
531 531 keys = generic, color_formatter, color_formatter_sql
532 532
533 533 #############
534 534 ## LOGGERS ##
535 535 #############
536 536
537 537 [logger_root]
538 538 #level = NOTSET
539 539 level = DEBUG
540 540 handlers = console
541 541
542 542 [logger_routes]
543 543 level = DEBUG
544 544 handlers =
545 545 qualname = routes.middleware
546 546 ## "level = DEBUG" logs the route matched and routing variables.
547 547 propagate = 1
548 548
549 549 [logger_beaker]
550 550 level = DEBUG
551 551 handlers =
552 552 qualname = beaker.container
553 553 propagate = 1
554 554
555 555 [logger_templates]
556 556 level = INFO
557 557 handlers =
558 558 qualname = pylons.templating
559 559 propagate = 1
560 560
561 561 [logger_kallithea]
562 562 level = DEBUG
563 563 handlers =
564 564 qualname = kallithea
565 565 propagate = 1
566 566
567 567 [logger_sqlalchemy]
568 568 #level = INFO
569 569 #handlers = console_sql
570 570 level = ERROR
571 571 handlers = console
572 572 qualname = sqlalchemy.engine
573 573 propagate = 0
574 574
575 575 [logger_whoosh_indexer]
576 576 level = DEBUG
577 577 handlers =
578 578 qualname = whoosh_indexer
579 579 propagate = 1
580 580
581 581 ##############
582 582 ## HANDLERS ##
583 583 ##############
584 584
585 585 [handler_console]
586 586 class = StreamHandler
587 587 args = (sys.stderr,)
588 588 #level = INFO
589 589 level = NOTSET
590 590 formatter = generic
591 591
592 592 [handler_console_sql]
593 593 class = StreamHandler
594 594 args = (sys.stderr,)
595 595 level = WARN
596 596 formatter = generic
597 597
598 598 ################
599 599 ## FORMATTERS ##
600 600 ################
601 601
602 602 [formatter_generic]
603 603 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
604 604 datefmt = %Y-%m-%d %H:%M:%S
605 605
606 606 [formatter_color_formatter]
607 607 class = kallithea.lib.colored_formatter.ColorFormatter
608 608 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
609 609 datefmt = %Y-%m-%d %H:%M:%S
610 610
611 611 [formatter_color_formatter_sql]
612 612 class = kallithea.lib.colored_formatter.ColorFormatterSql
613 613 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
614 614 datefmt = %Y-%m-%d %H:%M:%S
General Comments 0
You need to be logged in to leave comments. Login now