##// END OF EJS Templates
hooks: fixed tests
super-admin -
r4874:d7efefeb default
parent child Browse files
Show More
@@ -1,342 +1,342 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2020 RhodeCode GmbH
3 # Copyright (C) 2010-2020 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 json
21 import json
22 import logging
22 import logging
23 from StringIO import StringIO
23 from StringIO import StringIO
24
24
25 import mock
25 import mock
26 import pytest
26 import pytest
27
27
28 from rhodecode.lib import hooks_daemon
28 from rhodecode.lib import hooks_daemon
29 from rhodecode.tests.utils import assert_message_in_log
29 from rhodecode.tests.utils import assert_message_in_log
30
30
31
31
32 class TestDummyHooksCallbackDaemon(object):
32 class TestDummyHooksCallbackDaemon(object):
33 def test_hooks_module_path_set_properly(self):
33 def test_hooks_module_path_set_properly(self):
34 daemon = hooks_daemon.DummyHooksCallbackDaemon()
34 daemon = hooks_daemon.DummyHooksCallbackDaemon()
35 assert daemon.hooks_module == 'rhodecode.lib.hooks_daemon'
35 assert daemon.hooks_module == 'rhodecode.lib.hooks_daemon'
36
36
37 def test_logs_entering_the_hook(self):
37 def test_logs_entering_the_hook(self):
38 daemon = hooks_daemon.DummyHooksCallbackDaemon()
38 daemon = hooks_daemon.DummyHooksCallbackDaemon()
39 with mock.patch.object(hooks_daemon.log, 'debug') as log_mock:
39 with mock.patch.object(hooks_daemon.log, 'debug') as log_mock:
40 with daemon as return_value:
40 with daemon as return_value:
41 log_mock.assert_called_once_with(
41 log_mock.assert_called_once_with(
42 'Running `%s` callback daemon', 'DummyHooksCallbackDaemon')
42 'Running `%s` callback daemon', 'DummyHooksCallbackDaemon')
43 assert return_value == daemon
43 assert return_value == daemon
44
44
45 def test_logs_exiting_the_hook(self):
45 def test_logs_exiting_the_hook(self):
46 daemon = hooks_daemon.DummyHooksCallbackDaemon()
46 daemon = hooks_daemon.DummyHooksCallbackDaemon()
47 with mock.patch.object(hooks_daemon.log, 'debug') as log_mock:
47 with mock.patch.object(hooks_daemon.log, 'debug') as log_mock:
48 with daemon:
48 with daemon:
49 pass
49 pass
50 log_mock.assert_called_with(
50 log_mock.assert_called_with(
51 'Exiting `%s` callback daemon', 'DummyHooksCallbackDaemon')
51 'Exiting `%s` callback daemon', 'DummyHooksCallbackDaemon')
52
52
53
53
54 class TestHooks(object):
54 class TestHooks(object):
55 def test_hooks_can_be_used_as_a_context_processor(self):
55 def test_hooks_can_be_used_as_a_context_processor(self):
56 hooks = hooks_daemon.Hooks()
56 hooks = hooks_daemon.Hooks()
57 with hooks as return_value:
57 with hooks as return_value:
58 pass
58 pass
59 assert hooks == return_value
59 assert hooks == return_value
60
60
61
61
62 class TestHooksHttpHandler(object):
62 class TestHooksHttpHandler(object):
63 def test_read_request_parses_method_name_and_arguments(self):
63 def test_read_request_parses_method_name_and_arguments(self):
64 data = {
64 data = {
65 'method': 'test',
65 'method': 'test',
66 'extras': {
66 'extras': {
67 'param1': 1,
67 'param1': 1,
68 'param2': 'a'
68 'param2': 'a'
69 }
69 }
70 }
70 }
71 request = self._generate_post_request(data)
71 request = self._generate_post_request(data)
72 hooks_patcher = mock.patch.object(
72 hooks_patcher = mock.patch.object(
73 hooks_daemon.Hooks, data['method'], create=True, return_value=1)
73 hooks_daemon.Hooks, data['method'], create=True, return_value=1)
74
74
75 with hooks_patcher as hooks_mock:
75 with hooks_patcher as hooks_mock:
76 MockServer(hooks_daemon.HooksHttpHandler, request)
76 MockServer(hooks_daemon.HooksHttpHandler, request)
77
77
78 hooks_mock.assert_called_once_with(data['extras'])
78 hooks_mock.assert_called_once_with(data['extras'])
79
79
80 def test_hooks_serialized_result_is_returned(self):
80 def test_hooks_serialized_result_is_returned(self):
81 request = self._generate_post_request({})
81 request = self._generate_post_request({})
82 rpc_method = 'test'
82 rpc_method = 'test'
83 hook_result = {
83 hook_result = {
84 'first': 'one',
84 'first': 'one',
85 'second': 2
85 'second': 2
86 }
86 }
87 read_patcher = mock.patch.object(
87 read_patcher = mock.patch.object(
88 hooks_daemon.HooksHttpHandler, '_read_request',
88 hooks_daemon.HooksHttpHandler, '_read_request',
89 return_value=(rpc_method, {}))
89 return_value=(rpc_method, {}))
90 hooks_patcher = mock.patch.object(
90 hooks_patcher = mock.patch.object(
91 hooks_daemon.Hooks, rpc_method, create=True,
91 hooks_daemon.Hooks, rpc_method, create=True,
92 return_value=hook_result)
92 return_value=hook_result)
93
93
94 with read_patcher, hooks_patcher:
94 with read_patcher, hooks_patcher:
95 server = MockServer(hooks_daemon.HooksHttpHandler, request)
95 server = MockServer(hooks_daemon.HooksHttpHandler, request)
96
96
97 expected_result = json.dumps(hook_result)
97 expected_result = json.dumps(hook_result)
98 assert server.request.output_stream.buflist[-1] == expected_result
98 assert server.request.output_stream.buflist[-1] == expected_result
99
99
100 def test_exception_is_returned_in_response(self):
100 def test_exception_is_returned_in_response(self):
101 request = self._generate_post_request({})
101 request = self._generate_post_request({})
102 rpc_method = 'test'
102 rpc_method = 'test'
103 read_patcher = mock.patch.object(
103 read_patcher = mock.patch.object(
104 hooks_daemon.HooksHttpHandler, '_read_request',
104 hooks_daemon.HooksHttpHandler, '_read_request',
105 return_value=(rpc_method, {}))
105 return_value=(rpc_method, {}))
106 hooks_patcher = mock.patch.object(
106 hooks_patcher = mock.patch.object(
107 hooks_daemon.Hooks, rpc_method, create=True,
107 hooks_daemon.Hooks, rpc_method, create=True,
108 side_effect=Exception('Test exception'))
108 side_effect=Exception('Test exception'))
109
109
110 with read_patcher, hooks_patcher:
110 with read_patcher, hooks_patcher:
111 server = MockServer(hooks_daemon.HooksHttpHandler, request)
111 server = MockServer(hooks_daemon.HooksHttpHandler, request)
112
112
113 org_exc = json.loads(server.request.output_stream.buflist[-1])
113 org_exc = json.loads(server.request.output_stream.buflist[-1])
114 expected_result = {
114 expected_result = {
115 'exception': 'Exception',
115 'exception': 'Exception',
116 'exception_traceback': org_exc['exception_traceback'],
116 'exception_traceback': org_exc['exception_traceback'],
117 'exception_args': ['Test exception']
117 'exception_args': ['Test exception']
118 }
118 }
119 assert org_exc == expected_result
119 assert org_exc == expected_result
120
120
121 def test_log_message_writes_to_debug_log(self, caplog):
121 def test_log_message_writes_to_debug_log(self, caplog):
122 ip_port = ('0.0.0.0', 8888)
122 ip_port = ('0.0.0.0', 8888)
123 handler = hooks_daemon.HooksHttpHandler(
123 handler = hooks_daemon.HooksHttpHandler(
124 MockRequest('POST /'), ip_port, mock.Mock())
124 MockRequest('POST /'), ip_port, mock.Mock())
125 fake_date = '1/Nov/2015 00:00:00'
125 fake_date = '1/Nov/2015 00:00:00'
126 date_patcher = mock.patch.object(
126 date_patcher = mock.patch.object(
127 handler, 'log_date_time_string', return_value=fake_date)
127 handler, 'log_date_time_string', return_value=fake_date)
128 with date_patcher, caplog.at_level(logging.DEBUG):
128 with date_patcher, caplog.at_level(logging.DEBUG):
129 handler.log_message('Some message %d, %s', 123, 'string')
129 handler.log_message('Some message %d, %s', 123, 'string')
130
130
131 expected_message = '{} - - [{}] Some message 123, string'.format(
131 expected_message = "HOOKS: {} - - [{}] Some message 123, string".format(ip_port, fake_date)
132 ip_port[0], fake_date)
133 assert_message_in_log(
132 assert_message_in_log(
134 caplog.records, expected_message,
133 caplog.records, expected_message,
135 levelno=logging.DEBUG, module='hooks_daemon')
134 levelno=logging.DEBUG, module='hooks_daemon')
136
135
137 def _generate_post_request(self, data):
136 def _generate_post_request(self, data):
138 payload = json.dumps(data)
137 payload = json.dumps(data)
139 return 'POST / HTTP/1.0\nContent-Length: {}\n\n{}'.format(
138 return 'POST / HTTP/1.0\nContent-Length: {}\n\n{}'.format(
140 len(payload), payload)
139 len(payload), payload)
141
140
142
141
143 class ThreadedHookCallbackDaemon(object):
142 class ThreadedHookCallbackDaemon(object):
144 def test_constructor_calls_prepare(self):
143 def test_constructor_calls_prepare(self):
145 prepare_daemon_patcher = mock.patch.object(
144 prepare_daemon_patcher = mock.patch.object(
146 hooks_daemon.ThreadedHookCallbackDaemon, '_prepare')
145 hooks_daemon.ThreadedHookCallbackDaemon, '_prepare')
147 with prepare_daemon_patcher as prepare_daemon_mock:
146 with prepare_daemon_patcher as prepare_daemon_mock:
148 hooks_daemon.ThreadedHookCallbackDaemon()
147 hooks_daemon.ThreadedHookCallbackDaemon()
149 prepare_daemon_mock.assert_called_once_with()
148 prepare_daemon_mock.assert_called_once_with()
150
149
151 def test_run_is_called_on_context_start(self):
150 def test_run_is_called_on_context_start(self):
152 patchers = mock.patch.multiple(
151 patchers = mock.patch.multiple(
153 hooks_daemon.ThreadedHookCallbackDaemon,
152 hooks_daemon.ThreadedHookCallbackDaemon,
154 _run=mock.DEFAULT, _prepare=mock.DEFAULT, __exit__=mock.DEFAULT)
153 _run=mock.DEFAULT, _prepare=mock.DEFAULT, __exit__=mock.DEFAULT)
155
154
156 with patchers as mocks:
155 with patchers as mocks:
157 daemon = hooks_daemon.ThreadedHookCallbackDaemon()
156 daemon = hooks_daemon.ThreadedHookCallbackDaemon()
158 with daemon as daemon_context:
157 with daemon as daemon_context:
159 pass
158 pass
160 mocks['_run'].assert_called_once_with()
159 mocks['_run'].assert_called_once_with()
161 assert daemon_context == daemon
160 assert daemon_context == daemon
162
161
163 def test_stop_is_called_on_context_exit(self):
162 def test_stop_is_called_on_context_exit(self):
164 patchers = mock.patch.multiple(
163 patchers = mock.patch.multiple(
165 hooks_daemon.ThreadedHookCallbackDaemon,
164 hooks_daemon.ThreadedHookCallbackDaemon,
166 _run=mock.DEFAULT, _prepare=mock.DEFAULT, _stop=mock.DEFAULT)
165 _run=mock.DEFAULT, _prepare=mock.DEFAULT, _stop=mock.DEFAULT)
167
166
168 with patchers as mocks:
167 with patchers as mocks:
169 daemon = hooks_daemon.ThreadedHookCallbackDaemon()
168 daemon = hooks_daemon.ThreadedHookCallbackDaemon()
170 with daemon as daemon_context:
169 with daemon as daemon_context:
171 assert mocks['_stop'].call_count == 0
170 assert mocks['_stop'].call_count == 0
172
171
173 mocks['_stop'].assert_called_once_with()
172 mocks['_stop'].assert_called_once_with()
174 assert daemon_context == daemon
173 assert daemon_context == daemon
175
174
176
175
177 class TestHttpHooksCallbackDaemon(object):
176 class TestHttpHooksCallbackDaemon(object):
178 def test_hooks_callback_generates_new_port(self, caplog):
177 def test_hooks_callback_generates_new_port(self, caplog):
179 with caplog.at_level(logging.DEBUG):
178 with caplog.at_level(logging.DEBUG):
180 daemon = hooks_daemon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
179 daemon = hooks_daemon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
181 assert daemon._daemon.server_address == ('127.0.0.1', 8881)
180 assert daemon._daemon.server_address == ('127.0.0.1', 8881)
182
181
183 with caplog.at_level(logging.DEBUG):
182 with caplog.at_level(logging.DEBUG):
184 daemon = hooks_daemon.HttpHooksCallbackDaemon(host=None, port=None)
183 daemon = hooks_daemon.HttpHooksCallbackDaemon(host=None, port=None)
185 assert daemon._daemon.server_address[1] in range(0, 66000)
184 assert daemon._daemon.server_address[1] in range(0, 66000)
186 assert daemon._daemon.server_address[0] != '127.0.0.1'
185 assert daemon._daemon.server_address[0] != '127.0.0.1'
187
186
188 def test_prepare_inits_daemon_variable(self, tcp_server, caplog):
187 def test_prepare_inits_daemon_variable(self, tcp_server, caplog):
189 with self._tcp_patcher(tcp_server), caplog.at_level(logging.DEBUG):
188 with self._tcp_patcher(tcp_server), caplog.at_level(logging.DEBUG):
190 daemon = hooks_daemon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
189 daemon = hooks_daemon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
191 assert daemon._daemon == tcp_server
190 assert daemon._daemon == tcp_server
192
191
193 _, port = tcp_server.server_address
192 _, port = tcp_server.server_address
194 expected_uri = '{}:{}'.format('127.0.0.1', port)
193 expected_uri = '{}:{}'.format('127.0.0.1', port)
195 msg = 'Preparing HTTP callback daemon at `{}` and ' \
194 msg = 'HOOKS: {} Preparing HTTP callback daemon registering ' \
196 'registering hook object: rhodecode.lib.hooks_daemon.HooksHttpHandler'.format(expected_uri)
195 'hook object: rhodecode.lib.hooks_daemon.HooksHttpHandler'.format(expected_uri)
197 assert_message_in_log(
196 assert_message_in_log(
198 caplog.records, msg, levelno=logging.DEBUG, module='hooks_daemon')
197 caplog.records, msg, levelno=logging.DEBUG, module='hooks_daemon')
199
198
200 def test_prepare_inits_hooks_uri_and_logs_it(
199 def test_prepare_inits_hooks_uri_and_logs_it(
201 self, tcp_server, caplog):
200 self, tcp_server, caplog):
202 with self._tcp_patcher(tcp_server), caplog.at_level(logging.DEBUG):
201 with self._tcp_patcher(tcp_server), caplog.at_level(logging.DEBUG):
203 daemon = hooks_daemon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
202 daemon = hooks_daemon.HttpHooksCallbackDaemon(host='127.0.0.1', port=8881)
204
203
205 _, port = tcp_server.server_address
204 _, port = tcp_server.server_address
206 expected_uri = '{}:{}'.format('127.0.0.1', port)
205 expected_uri = '{}:{}'.format('127.0.0.1', port)
207 assert daemon.hooks_uri == expected_uri
206 assert daemon.hooks_uri == expected_uri
208
207
209 msg = 'Preparing HTTP callback daemon at `{}` and ' \
208 msg = 'HOOKS: {} Preparing HTTP callback daemon registering ' \
210 'registering hook object: rhodecode.lib.hooks_daemon.HooksHttpHandler'.format(expected_uri)
209 'hook object: rhodecode.lib.hooks_daemon.HooksHttpHandler'.format(expected_uri)
211 assert_message_in_log(
210 assert_message_in_log(
212 caplog.records, msg,
211 caplog.records, msg,
213 levelno=logging.DEBUG, module='hooks_daemon')
212 levelno=logging.DEBUG, module='hooks_daemon')
214
213
215 def test_run_creates_a_thread(self, tcp_server):
214 def test_run_creates_a_thread(self, tcp_server):
216 thread = mock.Mock()
215 thread = mock.Mock()
217
216
218 with self._tcp_patcher(tcp_server):
217 with self._tcp_patcher(tcp_server):
219 daemon = hooks_daemon.HttpHooksCallbackDaemon()
218 daemon = hooks_daemon.HttpHooksCallbackDaemon()
220
219
221 with self._thread_patcher(thread) as thread_mock:
220 with self._thread_patcher(thread) as thread_mock:
222 daemon._run()
221 daemon._run()
223
222
224 thread_mock.assert_called_once_with(
223 thread_mock.assert_called_once_with(
225 target=tcp_server.serve_forever,
224 target=tcp_server.serve_forever,
226 kwargs={'poll_interval': daemon.POLL_INTERVAL})
225 kwargs={'poll_interval': daemon.POLL_INTERVAL})
227 assert thread.daemon is True
226 assert thread.daemon is True
228 thread.start.assert_called_once_with()
227 thread.start.assert_called_once_with()
229
228
230 def test_run_logs(self, tcp_server, caplog):
229 def test_run_logs(self, tcp_server, caplog):
231
230
232 with self._tcp_patcher(tcp_server):
231 with self._tcp_patcher(tcp_server):
233 daemon = hooks_daemon.HttpHooksCallbackDaemon()
232 daemon = hooks_daemon.HttpHooksCallbackDaemon()
234
233
235 with self._thread_patcher(mock.Mock()), caplog.at_level(logging.DEBUG):
234 with self._thread_patcher(mock.Mock()), caplog.at_level(logging.DEBUG):
236 daemon._run()
235 daemon._run()
237
236
238 assert_message_in_log(
237 assert_message_in_log(
239 caplog.records,
238 caplog.records,
240 'Running event loop of callback daemon in background thread',
239 'Running event loop of callback daemon in background thread',
241 levelno=logging.DEBUG, module='hooks_daemon')
240 levelno=logging.DEBUG, module='hooks_daemon')
242
241
243 def test_stop_cleans_up_the_connection(self, tcp_server, caplog):
242 def test_stop_cleans_up_the_connection(self, tcp_server, caplog):
244 thread = mock.Mock()
243 thread = mock.Mock()
245
244
246 with self._tcp_patcher(tcp_server):
245 with self._tcp_patcher(tcp_server):
247 daemon = hooks_daemon.HttpHooksCallbackDaemon()
246 daemon = hooks_daemon.HttpHooksCallbackDaemon()
248
247
249 with self._thread_patcher(thread), caplog.at_level(logging.DEBUG):
248 with self._thread_patcher(thread), caplog.at_level(logging.DEBUG):
250 with daemon:
249 with daemon:
251 assert daemon._daemon == tcp_server
250 assert daemon._daemon == tcp_server
252 assert daemon._callback_thread == thread
251 assert daemon._callback_thread == thread
253
252
254 assert daemon._daemon is None
253 assert daemon._daemon is None
255 assert daemon._callback_thread is None
254 assert daemon._callback_thread is None
256 tcp_server.shutdown.assert_called_with()
255 tcp_server.shutdown.assert_called_with()
257 thread.join.assert_called_once_with()
256 thread.join.assert_called_once_with()
258
257
259 assert_message_in_log(
258 assert_message_in_log(
260 caplog.records, 'Waiting for background thread to finish.',
259 caplog.records, 'Waiting for background thread to finish.',
261 levelno=logging.DEBUG, module='hooks_daemon')
260 levelno=logging.DEBUG, module='hooks_daemon')
262
261
263 def _tcp_patcher(self, tcp_server):
262 def _tcp_patcher(self, tcp_server):
264 return mock.patch.object(
263 return mock.patch.object(
265 hooks_daemon, 'TCPServer', return_value=tcp_server)
264 hooks_daemon, 'TCPServer', return_value=tcp_server)
266
265
267 def _thread_patcher(self, thread):
266 def _thread_patcher(self, thread):
268 return mock.patch.object(
267 return mock.patch.object(
269 hooks_daemon.threading, 'Thread', return_value=thread)
268 hooks_daemon.threading, 'Thread', return_value=thread)
270
269
271
270
272 class TestPrepareHooksDaemon(object):
271 class TestPrepareHooksDaemon(object):
273 @pytest.mark.parametrize('protocol', ('http',))
272 @pytest.mark.parametrize('protocol', ('http',))
274 def test_returns_dummy_hooks_callback_daemon_when_using_direct_calls(
273 def test_returns_dummy_hooks_callback_daemon_when_using_direct_calls(
275 self, protocol):
274 self, protocol):
276 expected_extras = {'extra1': 'value1'}
275 expected_extras = {'extra1': 'value1'}
277 callback, extras = hooks_daemon.prepare_callback_daemon(
276 callback, extras = hooks_daemon.prepare_callback_daemon(
278 expected_extras.copy(), protocol=protocol,
277 expected_extras.copy(), protocol=protocol,
279 host='127.0.0.1', use_direct_calls=True)
278 host='127.0.0.1', use_direct_calls=True)
280 assert isinstance(callback, hooks_daemon.DummyHooksCallbackDaemon)
279 assert isinstance(callback, hooks_daemon.DummyHooksCallbackDaemon)
281 expected_extras['hooks_module'] = 'rhodecode.lib.hooks_daemon'
280 expected_extras['hooks_module'] = 'rhodecode.lib.hooks_daemon'
282 expected_extras['time'] = extras['time']
281 expected_extras['time'] = extras['time']
283 assert 'extra1' in extras
282 assert 'extra1' in extras
284
283
285 @pytest.mark.parametrize('protocol, expected_class', (
284 @pytest.mark.parametrize('protocol, expected_class', (
286 ('http', hooks_daemon.HttpHooksCallbackDaemon),
285 ('http', hooks_daemon.HttpHooksCallbackDaemon),
287 ))
286 ))
288 def test_returns_real_hooks_callback_daemon_when_protocol_is_specified(
287 def test_returns_real_hooks_callback_daemon_when_protocol_is_specified(
289 self, protocol, expected_class):
288 self, protocol, expected_class):
290 expected_extras = {
289 expected_extras = {
291 'extra1': 'value1',
290 'extra1': 'value1',
292 'txn_id': 'txnid2',
291 'txn_id': 'txnid2',
293 'hooks_protocol': protocol.lower()
292 'hooks_protocol': protocol.lower()
294 }
293 }
295 callback, extras = hooks_daemon.prepare_callback_daemon(
294 callback, extras = hooks_daemon.prepare_callback_daemon(
296 expected_extras.copy(), protocol=protocol, host='127.0.0.1',
295 expected_extras.copy(), protocol=protocol, host='127.0.0.1',
297 use_direct_calls=False,
296 use_direct_calls=False,
298 txn_id='txnid2')
297 txn_id='txnid2')
299 assert isinstance(callback, expected_class)
298 assert isinstance(callback, expected_class)
300 extras.pop('hooks_uri')
299 extras.pop('hooks_uri')
301 expected_extras['time'] = extras['time']
300 expected_extras['time'] = extras['time']
302 assert extras == expected_extras
301 assert extras == expected_extras
303
302
304 @pytest.mark.parametrize('protocol', (
303 @pytest.mark.parametrize('protocol', (
305 'invalid',
304 'invalid',
306 'Http',
305 'Http',
307 'HTTP',
306 'HTTP',
308 ))
307 ))
309 def test_raises_on_invalid_protocol(self, protocol):
308 def test_raises_on_invalid_protocol(self, protocol):
310 expected_extras = {
309 expected_extras = {
311 'extra1': 'value1',
310 'extra1': 'value1',
312 'hooks_protocol': protocol.lower()
311 'hooks_protocol': protocol.lower()
313 }
312 }
314 with pytest.raises(Exception):
313 with pytest.raises(Exception):
315 callback, extras = hooks_daemon.prepare_callback_daemon(
314 callback, extras = hooks_daemon.prepare_callback_daemon(
316 expected_extras.copy(),
315 expected_extras.copy(),
317 protocol=protocol, host='127.0.0.1',
316 protocol=protocol, host='127.0.0.1',
318 use_direct_calls=False)
317 use_direct_calls=False)
319
318
320
319
321 class MockRequest(object):
320 class MockRequest(object):
322 def __init__(self, request):
321 def __init__(self, request):
323 self.request = request
322 self.request = request
324 self.input_stream = StringIO(b'{}'.format(self.request))
323 self.input_stream = StringIO(b'{}'.format(self.request))
325 self.output_stream = StringIO()
324 self.output_stream = StringIO()
326
325
327 def makefile(self, mode, *args, **kwargs):
326 def makefile(self, mode, *args, **kwargs):
328 return self.output_stream if mode == 'wb' else self.input_stream
327 return self.output_stream if mode == 'wb' else self.input_stream
329
328
330
329
331 class MockServer(object):
330 class MockServer(object):
332 def __init__(self, Handler, request):
331 def __init__(self, handler_cls, request):
333 ip_port = ('0.0.0.0', 8888)
332 ip_port = ('0.0.0.0', 8888)
334 self.request = MockRequest(request)
333 self.request = MockRequest(request)
335 self.handler = Handler(self.request, ip_port, self)
334 self.server_address = ip_port
335 self.handler = handler_cls(self.request, ip_port, self)
336
336
337
337
338 @pytest.fixture()
338 @pytest.fixture()
339 def tcp_server():
339 def tcp_server():
340 server = mock.Mock()
340 server = mock.Mock()
341 server.server_address = ('127.0.0.1', 8881)
341 server.server_address = ('127.0.0.1', 8881)
342 return server
342 return server
General Comments 0
You need to be logged in to leave comments. Login now