##// END OF EJS Templates
tests: improve debugging of failed flash messages.
marcink -
r1312:c1381149 default
parent child Browse files
Show More
@@ -1,260 +1,262 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22 import time
22 import time
23 import logging
23 import logging
24 import datetime
24 import datetime
25 import hashlib
25 import hashlib
26 import tempfile
26 import tempfile
27 from os.path import join as jn
27 from os.path import join as jn
28
28
29 from tempfile import _RandomNameSequence
29 from tempfile import _RandomNameSequence
30
30
31 from paste.deploy import loadapp
31 from paste.deploy import loadapp
32 from paste.script.appinstall import SetupCommand
32 from paste.script.appinstall import SetupCommand
33
33
34 import pylons
34 import pylons
35 import pylons.test
35 import pylons.test
36 from pylons import config, url
36 from pylons import config, url
37 from pylons.i18n.translation import _get_translator
37 from pylons.i18n.translation import _get_translator
38 from pylons.util import ContextObj
38 from pylons.util import ContextObj
39
39
40 from routes.util import URLGenerator
40 from routes.util import URLGenerator
41 from nose.plugins.skip import SkipTest
41 from nose.plugins.skip import SkipTest
42 import pytest
42 import pytest
43
43
44 from rhodecode import is_windows
44 from rhodecode import is_windows
45 from rhodecode.config.routing import ADMIN_PREFIX
45 from rhodecode.config.routing import ADMIN_PREFIX
46 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
47 from rhodecode.model.db import User
47 from rhodecode.model.db import User
48 from rhodecode.lib import auth
48 from rhodecode.lib import auth
49 from rhodecode.lib.helpers import flash, link_to
49 from rhodecode.lib.helpers import flash, link_to
50 from rhodecode.lib.utils2 import safe_unicode, safe_str
50 from rhodecode.lib.utils2 import safe_unicode, safe_str
51 from rhodecode.tests.utils import get_session_from_response
51 from rhodecode.tests.utils import get_session_from_response
52
52
53 # TODO: johbo: Solve time zone related issues and remove this tweak
53 # TODO: johbo: Solve time zone related issues and remove this tweak
54 os.environ['TZ'] = 'UTC'
54 os.environ['TZ'] = 'UTC'
55 if not is_windows:
55 if not is_windows:
56 time.tzset()
56 time.tzset()
57
57
58 log = logging.getLogger(__name__)
58 log = logging.getLogger(__name__)
59
59
60 __all__ = [
60 __all__ = [
61 'get_new_dir', 'TestController', 'SkipTest',
61 'get_new_dir', 'TestController', 'SkipTest',
62 'url', 'link_to', 'ldap_lib_installed', 'clear_all_caches',
62 'url', 'link_to', 'ldap_lib_installed', 'clear_all_caches',
63 'assert_session_flash', 'login_user',
63 'assert_session_flash', 'login_user',
64 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'SVN_REPO',
64 'TESTS_TMP_PATH', 'HG_REPO', 'GIT_REPO', 'SVN_REPO',
65 'NEW_HG_REPO', 'NEW_GIT_REPO',
65 'NEW_HG_REPO', 'NEW_GIT_REPO',
66 'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
66 'HG_FORK', 'GIT_FORK', 'TEST_USER_ADMIN_LOGIN', 'TEST_USER_ADMIN_PASS',
67 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
67 'TEST_USER_REGULAR_LOGIN', 'TEST_USER_REGULAR_PASS',
68 'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
68 'TEST_USER_REGULAR_EMAIL', 'TEST_USER_REGULAR2_LOGIN',
69 'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
69 'TEST_USER_REGULAR2_PASS', 'TEST_USER_REGULAR2_EMAIL', 'TEST_HG_REPO',
70 'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
70 'TEST_HG_REPO_CLONE', 'TEST_HG_REPO_PULL', 'TEST_GIT_REPO',
71 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'SCM_TESTS',
71 'TEST_GIT_REPO_CLONE', 'TEST_GIT_REPO_PULL', 'SCM_TESTS',
72 ]
72 ]
73
73
74 # Invoke websetup with the current config file
74 # Invoke websetup with the current config file
75 # SetupCommand('setup-app').run([config_file])
75 # SetupCommand('setup-app').run([config_file])
76
76
77 # SOME GLOBALS FOR TESTS
77 # SOME GLOBALS FOR TESTS
78 TEST_DIR = tempfile.gettempdir()
78 TEST_DIR = tempfile.gettempdir()
79
79
80 TESTS_TMP_PATH = jn(TEST_DIR, 'rc_test_%s' % _RandomNameSequence().next())
80 TESTS_TMP_PATH = jn(TEST_DIR, 'rc_test_%s' % _RandomNameSequence().next())
81 TEST_USER_ADMIN_LOGIN = 'test_admin'
81 TEST_USER_ADMIN_LOGIN = 'test_admin'
82 TEST_USER_ADMIN_PASS = 'test12'
82 TEST_USER_ADMIN_PASS = 'test12'
83 TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com'
83 TEST_USER_ADMIN_EMAIL = 'test_admin@mail.com'
84
84
85 TEST_USER_REGULAR_LOGIN = 'test_regular'
85 TEST_USER_REGULAR_LOGIN = 'test_regular'
86 TEST_USER_REGULAR_PASS = 'test12'
86 TEST_USER_REGULAR_PASS = 'test12'
87 TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com'
87 TEST_USER_REGULAR_EMAIL = 'test_regular@mail.com'
88
88
89 TEST_USER_REGULAR2_LOGIN = 'test_regular2'
89 TEST_USER_REGULAR2_LOGIN = 'test_regular2'
90 TEST_USER_REGULAR2_PASS = 'test12'
90 TEST_USER_REGULAR2_PASS = 'test12'
91 TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com'
91 TEST_USER_REGULAR2_EMAIL = 'test_regular2@mail.com'
92
92
93 HG_REPO = 'vcs_test_hg'
93 HG_REPO = 'vcs_test_hg'
94 GIT_REPO = 'vcs_test_git'
94 GIT_REPO = 'vcs_test_git'
95 SVN_REPO = 'vcs_test_svn'
95 SVN_REPO = 'vcs_test_svn'
96
96
97 NEW_HG_REPO = 'vcs_test_hg_new'
97 NEW_HG_REPO = 'vcs_test_hg_new'
98 NEW_GIT_REPO = 'vcs_test_git_new'
98 NEW_GIT_REPO = 'vcs_test_git_new'
99
99
100 HG_FORK = 'vcs_test_hg_fork'
100 HG_FORK = 'vcs_test_hg_fork'
101 GIT_FORK = 'vcs_test_git_fork'
101 GIT_FORK = 'vcs_test_git_fork'
102
102
103 ## VCS
103 ## VCS
104 SCM_TESTS = ['hg', 'git']
104 SCM_TESTS = ['hg', 'git']
105 uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
105 uniq_suffix = str(int(time.mktime(datetime.datetime.now().timetuple())))
106
106
107 TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
107 TEST_GIT_REPO = jn(TESTS_TMP_PATH, GIT_REPO)
108 TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
108 TEST_GIT_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcsgitclone%s' % uniq_suffix)
109 TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
109 TEST_GIT_REPO_PULL = jn(TESTS_TMP_PATH, 'vcsgitpull%s' % uniq_suffix)
110
110
111 TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
111 TEST_HG_REPO = jn(TESTS_TMP_PATH, HG_REPO)
112 TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix)
112 TEST_HG_REPO_CLONE = jn(TESTS_TMP_PATH, 'vcshgclone%s' % uniq_suffix)
113 TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix)
113 TEST_HG_REPO_PULL = jn(TESTS_TMP_PATH, 'vcshgpull%s' % uniq_suffix)
114
114
115 TEST_REPO_PREFIX = 'vcs-test'
115 TEST_REPO_PREFIX = 'vcs-test'
116
116
117
117
118 # skip ldap tests if LDAP lib is not installed
118 # skip ldap tests if LDAP lib is not installed
119 ldap_lib_installed = False
119 ldap_lib_installed = False
120 try:
120 try:
121 import ldap
121 import ldap
122 ldap_lib_installed = True
122 ldap_lib_installed = True
123 except ImportError:
123 except ImportError:
124 # means that python-ldap is not installed
124 # means that python-ldap is not installed
125 pass
125 pass
126
126
127
127
128 def clear_all_caches():
128 def clear_all_caches():
129 from beaker.cache import cache_managers
129 from beaker.cache import cache_managers
130 for _cache in cache_managers.values():
130 for _cache in cache_managers.values():
131 _cache.clear()
131 _cache.clear()
132
132
133
133
134 def get_new_dir(title):
134 def get_new_dir(title):
135 """
135 """
136 Returns always new directory path.
136 Returns always new directory path.
137 """
137 """
138 from rhodecode.tests.vcs.utils import get_normalized_path
138 from rhodecode.tests.vcs.utils import get_normalized_path
139 name_parts = [TEST_REPO_PREFIX]
139 name_parts = [TEST_REPO_PREFIX]
140 if title:
140 if title:
141 name_parts.append(title)
141 name_parts.append(title)
142 hex_str = hashlib.sha1('%s %s' % (os.getpid(), time.time())).hexdigest()
142 hex_str = hashlib.sha1('%s %s' % (os.getpid(), time.time())).hexdigest()
143 name_parts.append(hex_str)
143 name_parts.append(hex_str)
144 name = '-'.join(name_parts)
144 name = '-'.join(name_parts)
145 path = os.path.join(TEST_DIR, name)
145 path = os.path.join(TEST_DIR, name)
146 return get_normalized_path(path)
146 return get_normalized_path(path)
147
147
148
148
149 @pytest.mark.usefixtures('app', 'index_location')
149 @pytest.mark.usefixtures('app', 'index_location')
150 class TestController(object):
150 class TestController(object):
151
151
152 maxDiff = None
152 maxDiff = None
153
153
154 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
154 def log_user(self, username=TEST_USER_ADMIN_LOGIN,
155 password=TEST_USER_ADMIN_PASS):
155 password=TEST_USER_ADMIN_PASS):
156 self._logged_username = username
156 self._logged_username = username
157 self._session = login_user_session(self.app, username, password)
157 self._session = login_user_session(self.app, username, password)
158 self.csrf_token = auth.get_csrf_token(self._session)
158 self.csrf_token = auth.get_csrf_token(self._session)
159
159
160 return self._session['rhodecode_user']
160 return self._session['rhodecode_user']
161
161
162 def logout_user(self):
162 def logout_user(self):
163 logout_user_session(self.app, auth.get_csrf_token(self._session))
163 logout_user_session(self.app, auth.get_csrf_token(self._session))
164 self.csrf_token = None
164 self.csrf_token = None
165 self._logged_username = None
165 self._logged_username = None
166 self._session = None
166 self._session = None
167
167
168 def _get_logged_user(self):
168 def _get_logged_user(self):
169 return User.get_by_username(self._logged_username)
169 return User.get_by_username(self._logged_username)
170
170
171 # TODO: remove, use plain assert in tests
171 # TODO: remove, use plain assert in tests
172 def assertEqual(self, a, b, msg=None):
172 def assertEqual(self, a, b, msg=None):
173 if msg:
173 if msg:
174 assert a == b, msg
174 assert a == b, msg
175 else:
175 else:
176 assert a == b
176 assert a == b
177
177
178
178
179 def login_user_session(
179 def login_user_session(
180 app, username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS):
180 app, username=TEST_USER_ADMIN_LOGIN, password=TEST_USER_ADMIN_PASS):
181 from rhodecode.tests.functional.test_login import login_url
181 from rhodecode.tests.functional.test_login import login_url
182 response = app.post(
182 response = app.post(
183 login_url,
183 login_url,
184 {'username': username, 'password': password})
184 {'username': username, 'password': password})
185 if 'invalid user name' in response.body:
185 if 'invalid user name' in response.body:
186 pytest.fail('could not login using %s %s' % (username, password))
186 pytest.fail('could not login using %s %s' % (username, password))
187
187
188 assert response.status == '302 Found'
188 assert response.status == '302 Found'
189 response = response.follow()
189 response = response.follow()
190 assert response.status == '200 OK'
190 assert response.status == '200 OK'
191
191
192 session = get_session_from_response(response)
192 session = get_session_from_response(response)
193 assert 'rhodecode_user' in session
193 assert 'rhodecode_user' in session
194 rc_user = session['rhodecode_user']
194 rc_user = session['rhodecode_user']
195 assert rc_user.get('username') == username
195 assert rc_user.get('username') == username
196 assert rc_user.get('is_authenticated')
196 assert rc_user.get('is_authenticated')
197
197
198 return session
198 return session
199
199
200
200
201 def logout_user_session(app, csrf_token):
201 def logout_user_session(app, csrf_token):
202 from rhodecode.tests.functional.test_login import logut_url
202 from rhodecode.tests.functional.test_login import logut_url
203 app.post(logut_url, {'csrf_token': csrf_token}, status=302)
203 app.post(logut_url, {'csrf_token': csrf_token}, status=302)
204
204
205
205
206 def login_user(app, username=TEST_USER_ADMIN_LOGIN,
206 def login_user(app, username=TEST_USER_ADMIN_LOGIN,
207 password=TEST_USER_ADMIN_PASS):
207 password=TEST_USER_ADMIN_PASS):
208 return login_user_session(app, username, password)['rhodecode_user']
208 return login_user_session(app, username, password)['rhodecode_user']
209
209
210
210
211 def assert_session_flash(response=None, msg=None, category=None):
211 def assert_session_flash(response=None, msg=None, category=None):
212 """
212 """
213 Assert on a flash message in the current session.
213 Assert on a flash message in the current session.
214
214
215 :param msg: Required. The expected message. Will be evaluated if a
215 :param msg: Required. The expected message. Will be evaluated if a
216 :class:`LazyString` is passed in.
216 :class:`LazyString` is passed in.
217 :param response: Optional. For functional testing, pass in the response
217 :param response: Optional. For functional testing, pass in the response
218 object. Otherwise don't pass in any value.
218 object. Otherwise don't pass in any value.
219 :param category: Optional. If passed, the message category will be
219 :param category: Optional. If passed, the message category will be
220 checked as well.
220 checked as well.
221 """
221 """
222 if msg is None:
222 if msg is None:
223 raise ValueError("Parameter msg is required.")
223 raise ValueError("Parameter msg is required.")
224
224
225 messages = flash.pop_messages()
225 messages = flash.pop_messages()
226 msg = _eval_if_lazy(msg)
226 msg = _eval_if_lazy(msg)
227
227
228 assert messages, 'unable to find message `%s` in empty flash list' % msg
228 assert messages, 'unable to find message `%s` in empty flash list' % msg
229 message = messages[0]
229 message = messages[0]
230
230
231 message_text = _eval_if_lazy(message.message)
231 message_text = _eval_if_lazy(message.message)
232
232
233 if msg not in message_text:
233 if msg not in message_text:
234 msg = u'msg `%s` not found in session flash: got `%s` instead' % (
234 fail_msg = u'msg `%s` not found in session ' \
235 msg, message_text)
235 u'flash: got `%s` (type:%s) instead' % (
236 pytest.fail(safe_str(msg))
236 msg, message_text, type(message_text))
237
238 pytest.fail(safe_str(fail_msg))
237 if category:
239 if category:
238 assert category == message.category
240 assert category == message.category
239
241
240
242
241 def _eval_if_lazy(value):
243 def _eval_if_lazy(value):
242 return value.eval() if hasattr(value, 'eval') else value
244 return value.eval() if hasattr(value, 'eval') else value
243
245
244
246
245 def assert_not_in_session_flash(response, msg, category=None):
247 def assert_not_in_session_flash(response, msg, category=None):
246 assert 'flash' in response.session, 'Response session has no flash key'
248 assert 'flash' in response.session, 'Response session has no flash key'
247 message_category, message_text = response.session['flash'][0]
249 message_category, message_text = response.session['flash'][0]
248 if msg in message_text:
250 if msg in message_text:
249 msg = u'msg `%s` found in session flash: got `%s` instead' % (
251 msg = u'msg `%s` found in session flash: got `%s` instead' % (
250 msg, message_text)
252 msg, message_text)
251 pytest.fail(safe_str(msg))
253 pytest.fail(safe_str(msg))
252 if category:
254 if category:
253 assert category == message_category
255 assert category == message_category
254
256
255
257
256 def assert_session_flash_is_empty(response):
258 def assert_session_flash_is_empty(response):
257 if 'flash' in response.session:
259 if 'flash' in response.session:
258 msg = 'flash messages are present in session:%s' % \
260 msg = 'flash messages are present in session:%s' % \
259 response.session['flash'][0]
261 response.session['flash'][0]
260 pytest.fail(safe_str(msg))
262 pytest.fail(safe_str(msg))
General Comments 0
You need to be logged in to leave comments. Login now