##// END OF EJS Templates
test env update
marcink -
r1416:df04752d beta
parent child Browse files
Show More
@@ -1,116 +1,115 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.hooks
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Hooks runned by rhodecode
7 7
8 8 :created_on: Aug 6, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25 import os
26 26 import sys
27 import getpass
28 27
29 28 from mercurial.scmutil import revrange
30 29 from mercurial.node import nullrev
31 30
32 31 from rhodecode.lib import helpers as h
33 32 from rhodecode.lib.utils import action_logger
34 33
35 34
36 35 def repo_size(ui, repo, hooktype=None, **kwargs):
37 36 """Presents size of repository after push
38 37
39 38 :param ui:
40 39 :param repo:
41 40 :param hooktype:
42 41 """
43 42
44 43 if hooktype != 'changegroup':
45 44 return False
46 45 size_hg, size_root = 0, 0
47 46 for path, dirs, files in os.walk(repo.root):
48 47 if path.find('.hg') != -1:
49 48 for f in files:
50 49 try:
51 50 size_hg += os.path.getsize(os.path.join(path, f))
52 51 except OSError:
53 52 pass
54 53 else:
55 54 for f in files:
56 55 try:
57 56 size_root += os.path.getsize(os.path.join(path, f))
58 57 except OSError:
59 58 pass
60 59
61 60 size_hg_f = h.format_byte_size(size_hg)
62 61 size_root_f = h.format_byte_size(size_root)
63 62 size_total_f = h.format_byte_size(size_root + size_hg)
64 63 sys.stdout.write('Repository size .hg:%s repo:%s total:%s\n' \
65 64 % (size_hg_f, size_root_f, size_total_f))
66 65
67 66
68 67 def log_pull_action(ui, repo, **kwargs):
69 68 """Logs user last pull action
70 69
71 70 :param ui:
72 71 :param repo:
73 72 """
74 73
75 74 extra_params = dict(repo.ui.configitems('rhodecode_extras'))
76 75 username = extra_params['username']
77 76 repository = extra_params['repository']
78 77 action = 'pull'
79 78
80 79 action_logger(username, action, repository, extra_params['ip'])
81 80
82 81 return 0
83 82
84 83
85 84 def log_push_action(ui, repo, **kwargs):
86 85 """Maps user last push action to new changeset id, from mercurial
87 86
88 87 :param ui:
89 88 :param repo:
90 89 """
91 90
92 91 extra_params = dict(repo.ui.configitems('rhodecode_extras'))
93 92 username = extra_params['username']
94 93 repository = extra_params['repository']
95 94 action = extra_params['action'] + ':%s'
96 95 node = kwargs['node']
97 96
98 97 def get_revs(repo, rev_opt):
99 98 if rev_opt:
100 99 revs = revrange(repo, rev_opt)
101 100
102 101 if len(revs) == 0:
103 102 return (nullrev, nullrev)
104 103 return (max(revs), min(revs))
105 104 else:
106 105 return (len(repo) - 1, 0)
107 106
108 107 stop, start = get_revs(repo, [node + ':'])
109 108
110 109 revs = (str(repo[r]) for r in xrange(start, stop + 1))
111 110
112 111 action = action % ','.join(revs)
113 112
114 113 action_logger(username, action, repository, extra_params['ip'])
115 114
116 115 return 0
@@ -1,628 +1,603 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.utils
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Utilities library for RhodeCode
7 7
8 8 :created_on: Apr 18, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import logging
28 28 import datetime
29 29 import traceback
30 30 import paste
31 31 import beaker
32 32 from os.path import dirname as dn, join as jn
33 33
34 34 from paste.script.command import Command, BadCommand
35 35
36 36 from UserDict import DictMixin
37 37
38 38 from mercurial import ui, config, hg
39 39 from mercurial.error import RepoError
40 40
41 41 from webhelpers.text import collapse, remove_formatting, strip_tags
42 42
43 43 from vcs.backends.base import BaseChangeset
44 44 from vcs.utils.lazy import LazyProperty
45 45
46 46 from rhodecode.model import meta
47 47 from rhodecode.model.caching_query import FromCache
48 48 from rhodecode.model.db import Repository, User, RhodeCodeUi, UserLog, Group, \
49 49 RhodeCodeSettings
50 50 from rhodecode.model.repo import RepoModel
51 51 from rhodecode.model.user import UserModel
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55
56 56 def recursive_replace(str, replace=' '):
57 57 """Recursive replace of given sign to just one instance
58 58
59 59 :param str: given string
60 60 :param replace: char to find and replace multiple instances
61 61
62 62 Examples::
63 63 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
64 64 'Mighty-Mighty-Bo-sstones'
65 65 """
66 66
67 67 if str.find(replace * 2) == -1:
68 68 return str
69 69 else:
70 70 str = str.replace(replace * 2, replace)
71 71 return recursive_replace(str, replace)
72 72
73 73
74 74 def repo_name_slug(value):
75 75 """Return slug of name of repository
76 76 This function is called on each creation/modification
77 77 of repository to prevent bad names in repo
78 78 """
79 79
80 80 slug = remove_formatting(value)
81 81 slug = strip_tags(slug)
82 82
83 83 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
84 84 slug = slug.replace(c, '-')
85 85 slug = recursive_replace(slug, '-')
86 86 slug = collapse(slug, '-')
87 87 return slug
88 88
89 89
90 90 def get_repo_slug(request):
91 91 return request.environ['pylons.routes_dict'].get('repo_name')
92 92
93 93
94 94 def action_logger(user, action, repo, ipaddr='', sa=None):
95 95 """
96 96 Action logger for various actions made by users
97 97
98 98 :param user: user that made this action, can be a unique username string or
99 99 object containing user_id attribute
100 100 :param action: action to log, should be on of predefined unique actions for
101 101 easy translations
102 102 :param repo: string name of repository or object containing repo_id,
103 103 that action was made on
104 104 :param ipaddr: optional ip address from what the action was made
105 105 :param sa: optional sqlalchemy session
106 106
107 107 """
108 108
109 109 if not sa:
110 110 sa = meta.Session()
111 111
112 112 try:
113 113 um = UserModel()
114 114 if hasattr(user, 'user_id'):
115 115 user_obj = user
116 116 elif isinstance(user, basestring):
117 117 user_obj = um.get_by_username(user, cache=False)
118 118 else:
119 119 raise Exception('You have to provide user object or username')
120 120
121 121 rm = RepoModel()
122 122 if hasattr(repo, 'repo_id'):
123 123 repo_obj = rm.get(repo.repo_id, cache=False)
124 124 repo_name = repo_obj.repo_name
125 125 elif isinstance(repo, basestring):
126 126 repo_name = repo.lstrip('/')
127 127 repo_obj = rm.get_by_repo_name(repo_name, cache=False)
128 128 else:
129 129 raise Exception('You have to provide repository to action logger')
130 130
131 131 user_log = UserLog()
132 132 user_log.user_id = user_obj.user_id
133 133 user_log.action = action
134 134
135 135 user_log.repository_id = repo_obj.repo_id
136 136 user_log.repository_name = repo_name
137 137
138 138 user_log.action_date = datetime.datetime.now()
139 139 user_log.user_ip = ipaddr
140 140 sa.add(user_log)
141 141 sa.commit()
142 142
143 143 log.info('Adding user %s, action %s on %s', user_obj, action, repo)
144 144 except:
145 145 log.error(traceback.format_exc())
146 146 sa.rollback()
147 147
148 148
149 149 def get_repos(path, recursive=False):
150 150 """
151 151 Scans given path for repos and return (name,(type,path)) tuple
152 152
153 153 :param path: path to scann for repositories
154 154 :param recursive: recursive search and return names with subdirs in front
155 155 """
156 156 from vcs.utils.helpers import get_scm
157 157 from vcs.exceptions import VCSError
158 158
159 159 if path.endswith(os.sep):
160 160 #remove ending slash for better results
161 161 path = path[:-1]
162 162
163 163 def _get_repos(p):
164 164 if not os.access(p, os.W_OK):
165 165 return
166 166 for dirpath in os.listdir(p):
167 167 if os.path.isfile(os.path.join(p, dirpath)):
168 168 continue
169 169 cur_path = os.path.join(p, dirpath)
170 170 try:
171 171 scm_info = get_scm(cur_path)
172 172 yield scm_info[1].split(path)[-1].lstrip(os.sep), scm_info
173 173 except VCSError:
174 174 if not recursive:
175 175 continue
176 176 #check if this dir containts other repos for recursive scan
177 177 rec_path = os.path.join(p, dirpath)
178 178 if os.path.isdir(rec_path):
179 179 for inner_scm in _get_repos(rec_path):
180 180 yield inner_scm
181 181
182 182 return _get_repos(path)
183 183
184 184
185 185 def check_repo_fast(repo_name, base_path):
186 186 """
187 187 Check given path for existence of directory
188 188 :param repo_name:
189 189 :param base_path:
190 190
191 191 :return False: if this directory is present
192 192 """
193 193 if os.path.isdir(os.path.join(base_path, repo_name)):
194 194 return False
195 195 return True
196 196
197 197
198 198 def check_repo(repo_name, base_path, verify=True):
199 199
200 200 repo_path = os.path.join(base_path, repo_name)
201 201
202 202 try:
203 203 if not check_repo_fast(repo_name, base_path):
204 204 return False
205 205 r = hg.repository(ui.ui(), repo_path)
206 206 if verify:
207 207 hg.verify(r)
208 208 #here we hnow that repo exists it was verified
209 209 log.info('%s repo is already created', repo_name)
210 210 return False
211 211 except RepoError:
212 212 #it means that there is no valid repo there...
213 213 log.info('%s repo is free for creation', repo_name)
214 214 return True
215 215
216 216
217 217 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
218 218 while True:
219 219 ok = raw_input(prompt)
220 220 if ok in ('y', 'ye', 'yes'):
221 221 return True
222 222 if ok in ('n', 'no', 'nop', 'nope'):
223 223 return False
224 224 retries = retries - 1
225 225 if retries < 0:
226 226 raise IOError
227 227 print complaint
228 228
229 229 #propagated from mercurial documentation
230 230 ui_sections = ['alias', 'auth',
231 231 'decode/encode', 'defaults',
232 232 'diff', 'email',
233 233 'extensions', 'format',
234 234 'merge-patterns', 'merge-tools',
235 235 'hooks', 'http_proxy',
236 236 'smtp', 'patch',
237 237 'paths', 'profiling',
238 238 'server', 'trusted',
239 239 'ui', 'web', ]
240 240
241 241
242 242 def make_ui(read_from='file', path=None, checkpaths=True):
243 243 """A function that will read python rc files or database
244 244 and make an mercurial ui object from read options
245 245
246 246 :param path: path to mercurial config file
247 247 :param checkpaths: check the path
248 248 :param read_from: read from 'file' or 'db'
249 249 """
250 250
251 251 baseui = ui.ui()
252 252
253 253 #clean the baseui object
254 254 baseui._ocfg = config.config()
255 255 baseui._ucfg = config.config()
256 256 baseui._tcfg = config.config()
257 257
258 258 if read_from == 'file':
259 259 if not os.path.isfile(path):
260 260 log.warning('Unable to read config file %s' % path)
261 261 return False
262 262 log.debug('reading hgrc from %s', path)
263 263 cfg = config.config()
264 264 cfg.read(path)
265 265 for section in ui_sections:
266 266 for k, v in cfg.items(section):
267 267 log.debug('settings ui from file[%s]%s:%s', section, k, v)
268 268 baseui.setconfig(section, k, v)
269 269
270 270 elif read_from == 'db':
271 271 sa = meta.Session()
272 272 ret = sa.query(RhodeCodeUi)\
273 273 .options(FromCache("sql_cache_short",
274 274 "get_hg_ui_settings")).all()
275 275
276 276 hg_ui = ret
277 277 for ui_ in hg_ui:
278 278 if ui_.ui_active:
279 279 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
280 280 ui_.ui_key, ui_.ui_value)
281 281 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
282 282
283 283 meta.Session.remove()
284 284 return baseui
285 285
286 286
287 287 def set_rhodecode_config(config):
288 288 """Updates pylons config with new settings from database
289 289
290 290 :param config:
291 291 """
292 292 hgsettings = RhodeCodeSettings.get_app_settings()
293 293
294 294 for k, v in hgsettings.items():
295 295 config[k] = v
296 296
297 297
298 298 def invalidate_cache(cache_key, *args):
299 299 """Puts cache invalidation task into db for
300 300 further global cache invalidation
301 301 """
302 302
303 303 from rhodecode.model.scm import ScmModel
304 304
305 305 if cache_key.startswith('get_repo_cached_'):
306 306 name = cache_key.split('get_repo_cached_')[-1]
307 307 ScmModel().mark_for_invalidation(name)
308 308
309 309
310 310 class EmptyChangeset(BaseChangeset):
311 311 """
312 312 An dummy empty changeset. It's possible to pass hash when creating
313 313 an EmptyChangeset
314 314 """
315 315
316 316 def __init__(self, cs='0' * 40, repo=None):
317 317 self._empty_cs = cs
318 318 self.revision = -1
319 319 self.message = ''
320 320 self.author = ''
321 321 self.date = ''
322 322 self.repository = repo
323 323
324 324 @LazyProperty
325 325 def raw_id(self):
326 326 """Returns raw string identifying this changeset, useful for web
327 327 representation.
328 328 """
329 329
330 330 return self._empty_cs
331 331
332 332 @LazyProperty
333 333 def short_id(self):
334 334 return self.raw_id[:12]
335 335
336 336 def get_file_changeset(self, path):
337 337 return self
338 338
339 339 def get_file_content(self, path):
340 340 return u''
341 341
342 342 def get_file_size(self, path):
343 343 return 0
344 344
345 345
346 346 def map_groups(groups):
347 347 """Checks for groups existence, and creates groups structures.
348 348 It returns last group in structure
349 349
350 350 :param groups: list of groups structure
351 351 """
352 352 sa = meta.Session()
353 353
354 354 parent = None
355 355 group = None
356 356 for lvl, group_name in enumerate(groups[:-1]):
357 357 group = sa.query(Group).filter(Group.group_name == group_name).scalar()
358 358
359 359 if group is None:
360 360 group = Group(group_name, parent)
361 361 sa.add(group)
362 362 sa.commit()
363 363
364 364 parent = group
365 365
366 366 return group
367 367
368 368
369 369 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
370 370 """maps all repos given in initial_repo_list, non existing repositories
371 371 are created, if remove_obsolete is True it also check for db entries
372 372 that are not in initial_repo_list and removes them.
373 373
374 374 :param initial_repo_list: list of repositories found by scanning methods
375 375 :param remove_obsolete: check for obsolete entries in database
376 376 """
377 377
378 378 sa = meta.Session()
379 379 rm = RepoModel()
380 380 user = sa.query(User).filter(User.admin == True).first()
381 381 added = []
382 382 for name, repo in initial_repo_list.items():
383 383 group = map_groups(name.split(os.sep))
384 384 if not rm.get_by_repo_name(name, cache=False):
385 385 log.info('repository %s not found creating default', name)
386 386 added.append(name)
387 387 form_data = {
388 388 'repo_name': name,
389 389 'repo_name_full': name,
390 390 'repo_type': repo.alias,
391 391 'description': repo.description \
392 392 if repo.description != 'unknown' else \
393 393 '%s repository' % name,
394 394 'private': False,
395 395 'group_id': getattr(group, 'group_id', None)
396 396 }
397 397 rm.create(form_data, user, just_db=True)
398 398
399 399 removed = []
400 400 if remove_obsolete:
401 401 #remove from database those repositories that are not in the filesystem
402 402 for repo in sa.query(Repository).all():
403 403 if repo.repo_name not in initial_repo_list.keys():
404 404 removed.append(repo.repo_name)
405 405 sa.delete(repo)
406 406 sa.commit()
407 407
408 408 return added, removed
409 409
410 410 #set cache regions for beaker so celery can utilise it
411 411 def add_cache(settings):
412 412 cache_settings = {'regions': None}
413 413 for key in settings.keys():
414 414 for prefix in ['beaker.cache.', 'cache.']:
415 415 if key.startswith(prefix):
416 416 name = key.split(prefix)[1].strip()
417 417 cache_settings[name] = settings[key].strip()
418 418 if cache_settings['regions']:
419 419 for region in cache_settings['regions'].split(','):
420 420 region = region.strip()
421 421 region_settings = {}
422 422 for key, value in cache_settings.items():
423 423 if key.startswith(region):
424 424 region_settings[key.split('.')[1]] = value
425 425 region_settings['expire'] = int(region_settings.get('expire',
426 426 60))
427 427 region_settings.setdefault('lock_dir',
428 428 cache_settings.get('lock_dir'))
429 429 region_settings.setdefault('data_dir',
430 430 cache_settings.get('data_dir'))
431 431
432 432 if 'type' not in region_settings:
433 433 region_settings['type'] = cache_settings.get('type',
434 434 'memory')
435 435 beaker.cache.cache_regions[region] = region_settings
436 436
437 437
438 438 def get_current_revision():
439 439 """Returns tuple of (number, id) from repository containing this package
440 440 or None if repository could not be found.
441 441 """
442 442
443 443 try:
444 444 from vcs import get_repo
445 445 from vcs.utils.helpers import get_scm
446 446 from vcs.exceptions import RepositoryError, VCSError
447 447 repopath = os.path.join(os.path.dirname(__file__), '..', '..')
448 448 scm = get_scm(repopath)[0]
449 449 repo = get_repo(path=repopath, alias=scm)
450 450 tip = repo.get_changeset()
451 451 return (tip.revision, tip.short_id)
452 452 except (ImportError, RepositoryError, VCSError), err:
453 453 logging.debug("Cannot retrieve rhodecode's revision. Original error "
454 454 "was: %s" % err)
455 455 return None
456 456
457 457
458 458 #==============================================================================
459 459 # TEST FUNCTIONS AND CREATORS
460 460 #==============================================================================
461 461 def create_test_index(repo_location, config, full_index):
462 462 """
463 463 Makes default test index
464 464
465 465 :param config: test config
466 466 :param full_index:
467 467 """
468 468
469 469 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
470 470 from rhodecode.lib.pidlock import DaemonLock, LockHeld
471 471
472 472 repo_location = repo_location
473 473
474 474 index_location = os.path.join(config['app_conf']['index_dir'])
475 475 if not os.path.exists(index_location):
476 476 os.makedirs(index_location)
477 477
478 478 try:
479 479 l = DaemonLock(file=jn(dn(index_location), 'make_index.lock'))
480 480 WhooshIndexingDaemon(index_location=index_location,
481 481 repo_location=repo_location)\
482 482 .run(full_index=full_index)
483 483 l.release()
484 484 except LockHeld:
485 485 pass
486 486
487 487
488 488 def create_test_env(repos_test_path, config):
489 489 """Makes a fresh database and
490 490 install test repository into tmp dir
491 491 """
492 492 from rhodecode.lib.db_manage import DbManage
493 493 from rhodecode.tests import HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, \
494 494 HG_FORK, GIT_FORK, TESTS_TMP_PATH
495 495 import tarfile
496 496 import shutil
497 from os.path import dirname as dn, join as jn, abspath
498
499 log = logging.getLogger('TestEnvCreator')
500 # create logger
501 log.setLevel(logging.DEBUG)
502 log.propagate = True
503 # create console handler and set level to debug
504 ch = logging.StreamHandler()
505 ch.setLevel(logging.DEBUG)
497 from os.path import abspath
506 498
507 # create formatter
508 formatter = logging.Formatter("%(asctime)s - %(name)s -"
509 " %(levelname)s - %(message)s")
510
511 # add formatter to ch
512 ch.setFormatter(formatter)
513
514 # add ch to logger
515 log.addHandler(ch)
516
517 #PART ONE create db
499 # PART ONE create db
518 500 dbconf = config['sqlalchemy.db1.url']
519 501 log.debug('making test db %s', dbconf)
520 502
521 503 # create test dir if it doesn't exist
522 504 if not os.path.isdir(repos_test_path):
523 505 log.debug('Creating testdir %s' % repos_test_path)
524 506 os.makedirs(repos_test_path)
525 507
526 508 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
527 509 tests=True)
528 510 dbmanage.create_tables(override=True)
529 511 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
530 512 dbmanage.create_default_user()
531 513 dbmanage.admin_prompt()
532 514 dbmanage.create_permissions()
533 515 dbmanage.populate_default_permissions()
534 516
535 #PART TWO make test repo
517 # PART TWO make test repo
536 518 log.debug('making test vcs repositories')
537 519
538 #remove old one from previos tests
539 for r in [HG_REPO, GIT_REPO, NEW_HG_REPO, NEW_GIT_REPO, HG_FORK, GIT_FORK]:
540
541 if os.path.isdir(jn(TESTS_TMP_PATH, r)):
542 log.debug('removing %s', r)
543 shutil.rmtree(jn(TESTS_TMP_PATH, r))
544
545 520 idx_path = config['app_conf']['index_dir']
546 521 data_path = config['app_conf']['cache_dir']
547 522
548 523 #clean index and data
549 524 if idx_path and os.path.exists(idx_path):
550 525 log.debug('remove %s' % idx_path)
551 526 shutil.rmtree(idx_path)
552 527
553 528 if data_path and os.path.exists(data_path):
554 529 log.debug('remove %s' % data_path)
555 530 shutil.rmtree(data_path)
556 531
557 532 #CREATE DEFAULT HG REPOSITORY
558 533 cur_dir = dn(dn(abspath(__file__)))
559 534 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
560 535 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
561 536 tar.close()
562 537
563 538
564 539 #==============================================================================
565 540 # PASTER COMMANDS
566 541 #==============================================================================
567 542 class BasePasterCommand(Command):
568 543 """
569 544 Abstract Base Class for paster commands.
570 545
571 546 The celery commands are somewhat aggressive about loading
572 547 celery.conf, and since our module sets the `CELERY_LOADER`
573 548 environment variable to our loader, we have to bootstrap a bit and
574 549 make sure we've had a chance to load the pylons config off of the
575 550 command line, otherwise everything fails.
576 551 """
577 552 min_args = 1
578 553 min_args_error = "Please provide a paster config file as an argument."
579 554 takes_config_file = 1
580 555 requires_config_file = True
581 556
582 557 def notify_msg(self, msg, log=False):
583 558 """Make a notification to user, additionally if logger is passed
584 559 it logs this action using given logger
585 560
586 561 :param msg: message that will be printed to user
587 562 :param log: logging instance, to use to additionally log this message
588 563
589 564 """
590 565 if log and isinstance(log, logging):
591 566 log(msg)
592 567
593 568 def run(self, args):
594 569 """
595 570 Overrides Command.run
596 571
597 572 Checks for a config file argument and loads it.
598 573 """
599 574 if len(args) < self.min_args:
600 575 raise BadCommand(
601 576 self.min_args_error % {'min_args': self.min_args,
602 577 'actual_args': len(args)})
603 578
604 579 # Decrement because we're going to lob off the first argument.
605 580 # @@ This is hacky
606 581 self.min_args -= 1
607 582 self.bootstrap_config(args[0])
608 583 self.update_parser()
609 584 return super(BasePasterCommand, self).run(args[1:])
610 585
611 586 def update_parser(self):
612 587 """
613 588 Abstract method. Allows for the class's parser to be updated
614 589 before the superclass's `run` method is called. Necessary to
615 590 allow options/arguments to be passed through to the underlying
616 591 celery command.
617 592 """
618 593 raise NotImplementedError("Abstract Method.")
619 594
620 595 def bootstrap_config(self, conf):
621 596 """
622 597 Loads the pylons configuration.
623 598 """
624 599 from pylons import config as pylonsconfig
625 600
626 601 path_to_ini_file = os.path.realpath(conf)
627 602 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
628 603 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
@@ -1,81 +1,85 b''
1 1 """Pylons application test package
2 2
3 3 This package assumes the Pylons environment is already loaded, such as
4 4 when this script is imported from the `nosetests --with-pylons=test.ini`
5 5 command.
6 6
7 7 This module initializes the application via ``websetup`` (`paster
8 8 setup-app`) and provides the base testing objects.
9 9 """
10 10 import os
11 11 from os.path import join as jn
12 12
13 13 from unittest import TestCase
14 14
15 15 from paste.deploy import loadapp
16 16 from paste.script.appinstall import SetupCommand
17 17 from pylons import config, url
18 18 from routes.util import URLGenerator
19 19 from webtest import TestApp
20 20
21 21 from rhodecode.model import meta
22 22 import logging
23 23
24 24
25 25 log = logging.getLogger(__name__)
26 26
27 27 import pylons.test
28 28
29 29 __all__ = ['environ', 'url', 'TestController', 'TESTS_TMP_PATH', 'HG_REPO',
30 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK', ]
30 'GIT_REPO', 'NEW_HG_REPO', 'NEW_GIT_REPO', 'HG_FORK', 'GIT_FORK',
31 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS' ]
31 32
32 33 # Invoke websetup with the current config file
33 34 #SetupCommand('setup-app').run([config_file])
34 35
35 36 ##RUNNING DESIRED TESTS
36 #nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
37
37 # nosetests -x rhodecode.tests.functional.test_admin_settings:TestSettingsController.test_my_account
38 # nosetests --pdb --pdb-failures
38 39 environ = {}
39 40
40 41 #SOME GLOBALS FOR TESTS
41 42 from tempfile import _RandomNameSequence
42 43 TESTS_TMP_PATH = jn('/', 'tmp', 'rc_test_%s' % _RandomNameSequence().next())
44 TEST_USER_ADMIN_LOGIN = 'test_admin'
45 TEST_USER_ADMIN_PASS = 'test12'
43 46 HG_REPO = 'vcs_test_hg'
44 47 GIT_REPO = 'vcs_test_git'
45 48
46 49 NEW_HG_REPO = 'vcs_test_hg_new'
47 50 NEW_GIT_REPO = 'vcs_test_git_new'
48 51
49 52 HG_FORK = 'vcs_test_hg_fork'
50 53 GIT_FORK = 'vcs_test_git_fork'
51 54
52 55 class TestController(TestCase):
53 56
54 57 def __init__(self, *args, **kwargs):
55 58 wsgiapp = pylons.test.pylonsapp
56 59 config = wsgiapp.config
57 60
58 61 self.app = TestApp(wsgiapp)
59 62 url._push_object(URLGenerator(config['routes.map'], environ))
60 63 self.sa = meta.Session
61 64 self.index_location = config['app_conf']['index_dir']
62 65 TestCase.__init__(self, *args, **kwargs)
63 66
64 def log_user(self, username='test_admin', password='test12'):
67 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
68 password=TEST_USER_ADMIN_PASS):
65 69 response = self.app.post(url(controller='login', action='index'),
66 70 {'username':username,
67 71 'password':password})
68 72
69 73 if 'invalid user name' in response.body:
70 74 self.fail('could not login using %s %s' % (username, password))
71 75
72 76 self.assertEqual(response.status, '302 Found')
73 77 self.assertEqual(response.session['rhodecode_user'].username, username)
74 78 return response.follow()
75 79
76 80
77 81
78 82 def checkSessionFlash(self, response, msg):
79 83 self.assertTrue('flash' in response.session)
80 84 self.assertTrue(msg in response.session['flash'][0][1])
81 85
@@ -1,94 +1,93 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.tests.test_libs
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6
7 Package for testing varios lib/helper functions in rhodecode
7 Package for testing various lib/helper functions in rhodecode
8 8
9 9 :created_on: Jun 9, 2011
10 10 :copyright: (c) 2011 by marcink.
11 11 :license: LICENSE_NAME, see LICENSE_FILE for more details.
12 12 """
13 13
14 14
15 15
16 16 import unittest
17 17 from rhodecode.tests import *
18 18
19
20 19 proto = 'http'
21 20 TEST_URLS = [
22 21 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
23 22 '%s://127.0.0.1' % proto),
24 23 ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
25 24 '%s://127.0.0.1' % proto),
26 25 ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
27 26 '%s://127.0.0.1' % proto),
28 27 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
29 28 '%s://127.0.0.1:8080' % proto),
30 29 ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
31 30 '%s://domain.org' % proto),
32 31 ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
33 32 '8080'],
34 33 '%s://domain.org:8080' % proto),
35 34 ]
36 35
37 36 proto = 'https'
38 37 TEST_URLS += [
39 38 ('%s://127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
40 39 '%s://127.0.0.1' % proto),
41 40 ('%s://marcink@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
42 41 '%s://127.0.0.1' % proto),
43 42 ('%s://marcink:pass@127.0.0.1' % proto, ['%s://' % proto, '127.0.0.1'],
44 43 '%s://127.0.0.1' % proto),
45 44 ('%s://127.0.0.1:8080' % proto, ['%s://' % proto, '127.0.0.1', '8080'],
46 45 '%s://127.0.0.1:8080' % proto),
47 46 ('%s://domain.org' % proto, ['%s://' % proto, 'domain.org'],
48 47 '%s://domain.org' % proto),
49 48 ('%s://user:pass@domain.org:8080' % proto, ['%s://' % proto, 'domain.org',
50 49 '8080'],
51 50 '%s://domain.org:8080' % proto),
52 51 ]
53 52
54 53
55 54 class TestLibs(unittest.TestCase):
56 55
57 56
58 57 def test_uri_filter(self):
59 58 from rhodecode.lib import uri_filter
60 59
61 60 for url in TEST_URLS:
62 61 self.assertEqual(uri_filter(url[0]), url[1])
63 62
64 63 def test_credentials_filter(self):
65 64 from rhodecode.lib import credentials_filter
66 65
67 66 for url in TEST_URLS:
68 67 self.assertEqual(credentials_filter(url[0]), url[2])
69 68
70 69
71 70 def test_str2bool(self):
72 71 from rhodecode.lib import str2bool
73 72 test_cases = [
74 73 ('t', True),
75 74 ('true', True),
76 75 ('y', True),
77 76 ('yes', True),
78 77 ('on', True),
79 78 ('1', True),
80 79 ('Y', True),
81 80 ('yeS', True),
82 81 ('Y', True),
83 82 ('TRUE', True),
84 83 ('T', True),
85 84 ('False', False),
86 85 ('F', False),
87 86 ('FALSE', False),
88 87 ('0', False),
89 88 ('-1', False),
90 89 ('', False), ]
91 90
92 91 for case in test_cases:
93 92 self.assertEqual(str2bool(case[0]), case[1])
94 93
@@ -1,42 +1,43 b''
1 1 [egg_info]
2 2 tag_build = beta
3 3 tag_svn_revision = true
4 4
5 5 [easy_install]
6 6 find_links = http://www.pylonshq.com/download/
7 7
8 8 [nosetests]
9 verbose=True
9 verbose=False
10 10 verbosity=2
11 11 with-pylons=test.ini
12 detailed-errors=1
12 detailed-errors=0
13 nologcapture=1
13 14
14 15 # Babel configuration
15 16 [compile_catalog]
16 17 domain = rhodecode
17 18 directory = rhodecode/i18n
18 19 statistics = true
19 20
20 21 [extract_messages]
21 22 add_comments = TRANSLATORS:
22 23 output_file = rhodecode/i18n/rhodecode.pot
23 24 width = 80
24 25
25 26 [init_catalog]
26 27 domain = rhodecode
27 28 input_file = rhodecode/i18n/rhodecode.pot
28 29 output_dir = rhodecode/i18n
29 30
30 31 [update_catalog]
31 32 domain = rhodecode
32 33 input_file = rhodecode/i18n/rhodecode.pot
33 34 output_dir = rhodecode/i18n
34 35 previous = true
35 36
36 37 [build_sphinx]
37 38 source-dir = docs/
38 39 build-dir = docs/_build
39 40 all_files = 1
40 41
41 42 [upload_sphinx]
42 43 upload-dir = docs/_build/html No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now