##// END OF EJS Templates
tests: Make return values of stub vcs controller editable.
Martin Bornhold -
r912:04974cb2 default
parent child Browse files
Show More
@@ -1,311 +1,310 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import base64
22 22
23 23 import mock
24 24 import pytest
25 25 import webtest.app
26 26
27 27 from rhodecode.lib.caching_query import FromCache
28 28 from rhodecode.lib.hooks_daemon import DummyHooksCallbackDaemon
29 29 from rhodecode.lib.middleware import simplevcs
30 30 from rhodecode.lib.middleware.https_fixup import HttpsFixup
31 31 from rhodecode.lib.middleware.utils import scm_app
32 32 from rhodecode.model.db import User, _hash_key
33 33 from rhodecode.model.meta import Session
34 34 from rhodecode.tests import (
35 35 HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
36 36 from rhodecode.tests.lib.middleware import mock_scm_app
37 37 from rhodecode.tests.utils import set_anonymous_access
38 38
39 39
40 40 class StubVCSController(simplevcs.SimpleVCS):
41 41
42 42 SCM = 'hg'
43 43 stub_response_body = tuple()
44 44
45 45 def __init__(self, *args, **kwargs):
46 46 super(StubVCSController, self).__init__(*args, **kwargs)
47 self.acl_repo_name = HG_REPO
48 self.url_repo_name = HG_REPO
49 self.vcs_repo_name = HG_REPO
50 self.is_shadow_repo = False
47 self._action = 'pull'
48 self._name = HG_REPO
49 self.set_repo_names(None)
51 50
52 51 def _get_repository_name(self, environ):
53 return HG_REPO
52 return self._name
54 53
55 54 def _get_action(self, environ):
56 return "pull"
55 return self._action
57 56
58 57 def _create_wsgi_app(self, repo_path, repo_name, config):
59 58 def fake_app(environ, start_response):
60 59 start_response('200 OK', [])
61 60 return self.stub_response_body
62 61 return fake_app
63 62
64 63 def _create_config(self, extras, repo_name):
65 64 return None
66 65
67 66
68 67 @pytest.fixture
69 68 def vcscontroller(pylonsapp, config_stub):
70 69 config_stub.testing_securitypolicy()
71 70 config_stub.include('rhodecode.authentication')
72 71
73 72 set_anonymous_access(True)
74 73 controller = StubVCSController(pylonsapp, pylonsapp.config, None)
75 74 app = HttpsFixup(controller, pylonsapp.config)
76 75 app = webtest.app.TestApp(app)
77 76
78 77 _remove_default_user_from_query_cache()
79 78
80 79 # Sanity checks that things are set up correctly
81 80 app.get('/' + HG_REPO, status=200)
82 81
83 82 app.controller = controller
84 83 return app
85 84
86 85
87 86 def _remove_default_user_from_query_cache():
88 87 user = User.get_default_user(cache=True)
89 88 query = Session().query(User).filter(User.username == user.username)
90 89 query = query.options(FromCache(
91 90 "sql_cache_short", "get_user_%s" % _hash_key(user.username)))
92 91 query.invalidate()
93 92 Session().expire(user)
94 93
95 94
96 95 @pytest.fixture
97 96 def disable_anonymous_user(request, pylonsapp):
98 97 set_anonymous_access(False)
99 98
100 99 @request.addfinalizer
101 100 def cleanup():
102 101 set_anonymous_access(True)
103 102
104 103
105 104 def test_handles_exceptions_during_permissions_checks(
106 105 vcscontroller, disable_anonymous_user):
107 106 user_and_pass = '%s:%s' % (TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
108 107 auth_password = base64.encodestring(user_and_pass).strip()
109 108 extra_environ = {
110 109 'AUTH_TYPE': 'Basic',
111 110 'HTTP_AUTHORIZATION': 'Basic %s' % auth_password,
112 111 'REMOTE_USER': TEST_USER_ADMIN_LOGIN,
113 112 }
114 113
115 114 # Verify that things are hooked up correctly
116 115 vcscontroller.get('/', status=200, extra_environ=extra_environ)
117 116
118 117 # Simulate trouble during permission checks
119 118 with mock.patch('rhodecode.model.db.User.get_by_username',
120 119 side_effect=Exception) as get_user:
121 120 # Verify that a correct 500 is returned and check that the expected
122 121 # code path was hit.
123 122 vcscontroller.get('/', status=500, extra_environ=extra_environ)
124 123 assert get_user.called
125 124
126 125
127 126 def test_returns_forbidden_if_no_anonymous_access(
128 127 vcscontroller, disable_anonymous_user):
129 128 vcscontroller.get('/', status=401)
130 129
131 130
132 131 class StubFailVCSController(simplevcs.SimpleVCS):
133 132 def _handle_request(self, environ, start_response):
134 133 raise Exception("BOOM")
135 134
136 135
137 136 @pytest.fixture(scope='module')
138 137 def fail_controller(pylonsapp):
139 138 controller = StubFailVCSController(pylonsapp, pylonsapp.config, None)
140 139 controller = HttpsFixup(controller, pylonsapp.config)
141 140 controller = webtest.app.TestApp(controller)
142 141 return controller
143 142
144 143
145 144 def test_handles_exceptions_as_internal_server_error(fail_controller):
146 145 fail_controller.get('/', status=500)
147 146
148 147
149 148 def test_provides_traceback_for_appenlight(fail_controller):
150 149 response = fail_controller.get(
151 150 '/', status=500, extra_environ={'appenlight.client': 'fake'})
152 151 assert 'appenlight.__traceback' in response.request.environ
153 152
154 153
155 154 def test_provides_utils_scm_app_as_scm_app_by_default(pylonsapp):
156 155 controller = StubVCSController(pylonsapp, pylonsapp.config, None)
157 156 assert controller.scm_app is scm_app
158 157
159 158
160 159 def test_allows_to_override_scm_app_via_config(pylonsapp):
161 160 config = pylonsapp.config.copy()
162 161 config['vcs.scm_app_implementation'] = (
163 162 'rhodecode.tests.lib.middleware.mock_scm_app')
164 163 controller = StubVCSController(pylonsapp, config, None)
165 164 assert controller.scm_app is mock_scm_app
166 165
167 166
168 167 @pytest.mark.parametrize('query_string, expected', [
169 168 ('cmd=stub_command', True),
170 169 ('cmd=listkeys', False),
171 170 ])
172 171 def test_should_check_locking(query_string, expected):
173 172 result = simplevcs._should_check_locking(query_string)
174 173 assert result == expected
175 174
176 175
177 176 @mock.patch.multiple(
178 177 'Pyro4.config', SERVERTYPE='multiplex', POLLTIMEOUT=0.01)
179 178 class TestGenerateVcsResponse:
180 179
181 180 def test_ensures_that_start_response_is_called_early_enough(self):
182 181 self.call_controller_with_response_body(iter(['a', 'b']))
183 182 assert self.start_response.called
184 183
185 184 def test_invalidates_cache_after_body_is_consumed(self):
186 185 result = self.call_controller_with_response_body(iter(['a', 'b']))
187 186 assert not self.was_cache_invalidated()
188 187 # Consume the result
189 188 list(result)
190 189 assert self.was_cache_invalidated()
191 190
192 191 @mock.patch('rhodecode.lib.middleware.simplevcs.HTTPLockedRC')
193 192 def test_handles_locking_exception(self, http_locked_rc):
194 193 result = self.call_controller_with_response_body(
195 194 self.raise_result_iter(vcs_kind='repo_locked'))
196 195 assert not http_locked_rc.called
197 196 # Consume the result
198 197 list(result)
199 198 assert http_locked_rc.called
200 199
201 200 @mock.patch('rhodecode.lib.middleware.simplevcs.HTTPRequirementError')
202 201 def test_handles_requirement_exception(self, http_requirement):
203 202 result = self.call_controller_with_response_body(
204 203 self.raise_result_iter(vcs_kind='requirement'))
205 204 assert not http_requirement.called
206 205 # Consume the result
207 206 list(result)
208 207 assert http_requirement.called
209 208
210 209 @mock.patch('rhodecode.lib.middleware.simplevcs.HTTPLockedRC')
211 210 def test_handles_locking_exception_in_app_call(self, http_locked_rc):
212 211 app_factory_patcher = mock.patch.object(
213 212 StubVCSController, '_create_wsgi_app')
214 213 with app_factory_patcher as app_factory:
215 214 app_factory().side_effect = self.vcs_exception()
216 215 result = self.call_controller_with_response_body(['a'])
217 216 list(result)
218 217 assert http_locked_rc.called
219 218
220 219 def test_raises_unknown_exceptions(self):
221 220 result = self.call_controller_with_response_body(
222 221 self.raise_result_iter(vcs_kind='unknown'))
223 222 with pytest.raises(Exception):
224 223 list(result)
225 224
226 225 def test_prepare_callback_daemon_is_called(self):
227 226 def side_effect(extras):
228 227 return DummyHooksCallbackDaemon(), extras
229 228
230 229 prepare_patcher = mock.patch.object(
231 230 StubVCSController, '_prepare_callback_daemon')
232 231 with prepare_patcher as prepare_mock:
233 232 prepare_mock.side_effect = side_effect
234 233 self.call_controller_with_response_body(iter(['a', 'b']))
235 234 assert prepare_mock.called
236 235 assert prepare_mock.call_count == 1
237 236
238 237 def call_controller_with_response_body(self, response_body):
239 238 settings = {
240 239 'base_path': 'fake_base_path',
241 240 'vcs.hooks.protocol': 'http',
242 241 'vcs.hooks.direct_calls': False,
243 242 }
244 243 controller = StubVCSController(None, settings, None)
245 244 controller._invalidate_cache = mock.Mock()
246 245 controller.stub_response_body = response_body
247 246 self.start_response = mock.Mock()
248 247 result = controller._generate_vcs_response(
249 248 environ={}, start_response=self.start_response,
250 249 repo_path='fake_repo_path',
251 250 repo_name='fake_repo_name',
252 251 extras={}, action='push')
253 252 self.controller = controller
254 253 return result
255 254
256 255 def raise_result_iter(self, vcs_kind='repo_locked'):
257 256 """
258 257 Simulates an exception due to a vcs raised exception if kind vcs_kind
259 258 """
260 259 raise self.vcs_exception(vcs_kind=vcs_kind)
261 260 yield "never_reached"
262 261
263 262 def vcs_exception(self, vcs_kind='repo_locked'):
264 263 locked_exception = Exception('TEST_MESSAGE')
265 264 locked_exception._vcs_kind = vcs_kind
266 265 return locked_exception
267 266
268 267 def was_cache_invalidated(self):
269 268 return self.controller._invalidate_cache.called
270 269
271 270
272 271 class TestInitializeGenerator:
273 272
274 273 def test_drains_first_element(self):
275 274 gen = self.factory(['__init__', 1, 2])
276 275 result = list(gen)
277 276 assert result == [1, 2]
278 277
279 278 @pytest.mark.parametrize('values', [
280 279 [],
281 280 [1, 2],
282 281 ])
283 282 def test_raises_value_error(self, values):
284 283 with pytest.raises(ValueError):
285 284 self.factory(values)
286 285
287 286 @simplevcs.initialize_generator
288 287 def factory(self, iterable):
289 288 for elem in iterable:
290 289 yield elem
291 290
292 291
293 292 class TestPrepareHooksDaemon(object):
294 293 def test_calls_imported_prepare_callback_daemon(self, app_settings):
295 294 expected_extras = {'extra1': 'value1'}
296 295 daemon = DummyHooksCallbackDaemon()
297 296
298 297 controller = StubVCSController(None, app_settings, None)
299 298 prepare_patcher = mock.patch.object(
300 299 simplevcs, 'prepare_callback_daemon',
301 300 return_value=(daemon, expected_extras))
302 301 with prepare_patcher as prepare_mock:
303 302 callback_daemon, extras = controller._prepare_callback_daemon(
304 303 expected_extras.copy())
305 304 prepare_mock.assert_called_once_with(
306 305 expected_extras,
307 306 protocol=app_settings['vcs.hooks.protocol'],
308 307 use_direct_calls=app_settings['vcs.hooks.direct_calls'])
309 308
310 309 assert callback_daemon == daemon
311 310 assert extras == extras
General Comments 0
You need to be logged in to leave comments. Login now