##// END OF EJS Templates
core: deprecated http based callback deamon....
super-admin -
r1315:910dabad default
parent child Browse files
Show More
@@ -71,7 +71,7 b' def VcsException(org_exc=None):'
71 return _make_exception_wrapper
71 return _make_exception_wrapper
72
72
73
73
74 def RepositoryLockedException(org_exc=None):
74 def LockedRepoException(org_exc=None):
75 def _make_exception_wrapper(*args):
75 def _make_exception_wrapper(*args):
76 return _make_exception('repo_locked', org_exc, *args)
76 return _make_exception('repo_locked', org_exc, *args)
77 return _make_exception_wrapper
77 return _make_exception_wrapper
@@ -41,54 +41,6 b" celery_app = Celery('__vcsserver__')"
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43
43
44 class HooksHttpClient:
45 proto = 'msgpack.v1'
46 connection = None
47
48 def __init__(self, hooks_uri):
49 self.hooks_uri = hooks_uri
50
51 def __repr__(self):
52 return f'{self.__class__}(hook_uri={self.hooks_uri}, proto={self.proto})'
53
54 def __call__(self, method, extras):
55 connection = http.client.HTTPConnection(self.hooks_uri)
56 # binary msgpack body
57 headers, body = self._serialize(method, extras)
58 log.debug('Doing a new hooks call using HTTPConnection to %s', self.hooks_uri)
59
60 try:
61 try:
62 connection.request('POST', '/', body, headers)
63 except Exception as error:
64 log.error('Hooks calling Connection failed on %s, org error: %s', connection.__dict__, error)
65 raise
66
67 response = connection.getresponse()
68 try:
69 return msgpack.load(response)
70 except Exception:
71 response_data = response.read()
72 log.exception('Failed to decode hook response json data. '
73 'response_code:%s, raw_data:%s',
74 response.status, response_data)
75 raise
76 finally:
77 connection.close()
78
79 @classmethod
80 def _serialize(cls, hook_name, extras):
81 data = {
82 'method': hook_name,
83 'extras': extras
84 }
85 headers = {
86 "rc-hooks-protocol": cls.proto,
87 "Connection": "keep-alive"
88 }
89 return headers, msgpack.packb(data)
90
91
92 class HooksCeleryClient:
44 class HooksCeleryClient:
93 TASK_TIMEOUT = 60 # time in seconds
45 TASK_TIMEOUT = 60 # time in seconds
94
46
@@ -160,17 +112,20 b' class SvnMessageWriter(RemoteMessageWrit'
160
112
161
113
162 def _maybe_handle_exception(result):
114 def _maybe_handle_exception(result):
115
116
163 exception_class = result.get('exception')
117 exception_class = result.get('exception')
164 exception_traceback = result.get('exception_traceback')
118 exception_traceback = result.get('exception_traceback')
165 if not (exception_class and exception_traceback):
119 if not exception_class:
166 return
120 return
121
167 log.debug('Handling hook-call exception: %s', exception_class)
122 log.debug('Handling hook-call exception: %s', exception_class)
168
123
169 if exception_traceback:
124 if exception_traceback:
170 log.error('Got traceback from remote call:%s', exception_traceback)
125 log.error('Got traceback from remote call:%s', exception_traceback)
171
126
172 if exception_class == 'HTTPLockedRC':
127 if exception_class == 'HTTPLockedRepo':
173 raise exceptions.RepositoryLockedException()(*result['exception_args'])
128 raise exceptions.LockedRepoException()(*result['exception_args'])
174 elif exception_class == 'ClientNotSupportedError':
129 elif exception_class == 'ClientNotSupportedError':
175 raise exceptions.ClientNotSupportedException()(*result['exception_args'])
130 raise exceptions.ClientNotSupportedException()(*result['exception_args'])
176 elif exception_class == 'HTTPBranchProtected':
131 elif exception_class == 'HTTPBranchProtected':
@@ -184,14 +139,11 b' def _maybe_handle_exception(result):'
184
139
185
140
186 def _get_hooks_client(extras):
141 def _get_hooks_client(extras):
187 hooks_uri = extras.get('hooks_uri')
188 task_queue = extras.get('task_queue')
142 task_queue = extras.get('task_queue')
189 task_backend = extras.get('task_backend')
143 task_backend = extras.get('task_backend')
190 is_shadow_repo = extras.get('is_shadow_repo')
144 is_shadow_repo = extras.get('is_shadow_repo')
191
145
192 if hooks_uri:
146 if task_queue and task_backend:
193 return HooksHttpClient(hooks_uri)
194 elif task_queue and task_backend:
195 return HooksCeleryClient(task_queue, task_backend)
147 return HooksCeleryClient(task_queue, task_backend)
196 elif is_shadow_repo:
148 elif is_shadow_repo:
197 return HooksShadowRepoClient()
149 return HooksShadowRepoClient()
@@ -15,17 +15,11 b''
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import threading
18 import pytest
19 import msgpack
20
21 from http.server import BaseHTTPRequestHandler
22 from socketserver import TCPServer
23
19
24 import mercurial.ui
20 import mercurial.ui
25 import mock
21 import mock
26 import pytest
27
22
28 from vcsserver.hooks import HooksHttpClient
29 from vcsserver.lib.ext_json import json
23 from vcsserver.lib.ext_json import json
30 from vcsserver import hooks
24 from vcsserver import hooks
31
25
@@ -41,7 +35,6 b' def get_hg_ui(extras=None):'
41 'make_lock': '',
35 'make_lock': '',
42 'action': '',
36 'action': '',
43 'ip': '',
37 'ip': '',
44 'hooks_uri': 'fake_hooks_uri',
45 }
38 }
46 required_extras.update(extras)
39 required_extras.update(extras)
47 hg_ui = mercurial.ui.ui()
40 hg_ui = mercurial.ui.ui()
@@ -123,15 +116,6 b' def test_git_post_pull_is_disabled():'
123
116
124 class TestGetHooksClient:
117 class TestGetHooksClient:
125
118
126 def test_returns_http_client_when_protocol_matches(self):
127 hooks_uri = 'localhost:8000'
128 result = hooks._get_hooks_client({
129 'hooks_uri': hooks_uri,
130 'hooks_protocol': 'http'
131 })
132 assert isinstance(result, hooks.HooksHttpClient)
133 assert result.hooks_uri == hooks_uri
134
135 def test_return_celery_client_when_queue_and_backend_provided(self):
119 def test_return_celery_client_when_queue_and_backend_provided(self):
136 task_queue = 'redis://task_queue:0'
120 task_queue = 'redis://task_queue:0'
137 task_backend = task_queue
121 task_backend = task_queue
@@ -142,116 +126,10 b' class TestGetHooksClient:'
142 assert isinstance(result, hooks.HooksCeleryClient)
126 assert isinstance(result, hooks.HooksCeleryClient)
143
127
144
128
145 class TestHooksHttpClient:
129 class TestHooksCeleryClient:
146 def test_init_sets_hooks_uri(self):
147 uri = 'localhost:3000'
148 client = hooks.HooksHttpClient(uri)
149 assert client.hooks_uri == uri
150
151 def test_serialize_returns_serialized_string(self):
152 client = hooks.HooksHttpClient('localhost:3000')
153 hook_name = 'test'
154 extras = {
155 'first': 1,
156 'second': 'two'
157 }
158 hooks_proto, result = client._serialize(hook_name, extras)
159 expected_result = msgpack.packb({
160 'method': hook_name,
161 'extras': extras,
162 })
163 assert hooks_proto == {'rc-hooks-protocol': 'msgpack.v1', 'Connection': 'keep-alive'}
164 assert result == expected_result
165
166 def test_call_queries_http_server(self, http_mirror):
167 client = hooks.HooksHttpClient(http_mirror.uri)
168 hook_name = 'test'
169 extras = {
170 'first': 1,
171 'second': 'two'
172 }
173 result = client(hook_name, extras)
174 expected_result = msgpack.unpackb(msgpack.packb({
175 'method': hook_name,
176 'extras': extras
177 }), raw=False)
178 assert result == expected_result
179
180
181 @pytest.fixture
182 def http_mirror(request):
183 server = MirrorHttpServer()
184 request.addfinalizer(server.stop)
185 return server
186
187
188 class MirrorHttpHandler(BaseHTTPRequestHandler):
189
190 def do_POST(self):
191 length = int(self.headers['Content-Length'])
192 body = self.rfile.read(length)
193 self.send_response(200)
194 self.end_headers()
195 self.wfile.write(body)
196
197
198 class MirrorHttpServer:
199 ip_address = '127.0.0.1'
200 port = 0
201
130
202 def __init__(self):
131 def test_hooks_http_client_init(self):
203 self._daemon = TCPServer((self.ip_address, 0), MirrorHttpHandler)
132 queue = 'redis://redis:6379/0'
204 _, self.port = self._daemon.server_address
133 backend = 'redis://redis:6379/0'
205 self._thread = threading.Thread(target=self._daemon.serve_forever)
134 client = hooks.HooksCeleryClient(queue, backend)
206 self._thread.daemon = True
135 assert client.celery_app.conf.broker_url == queue
207 self._thread.start()
208
209 def stop(self):
210 self._daemon.shutdown()
211 self._thread.join()
212 self._daemon = None
213 self._thread = None
214
215 @property
216 def uri(self):
217 return '{}:{}'.format(self.ip_address, self.port)
218
219
220 def test_hooks_http_client_init():
221 hooks_uri = 'http://localhost:8000'
222 client = HooksHttpClient(hooks_uri)
223 assert client.hooks_uri == hooks_uri
224
225
226 def test_hooks_http_client_call():
227 hooks_uri = 'http://localhost:8000'
228
229 method = 'test_method'
230 extras = {'key': 'value'}
231
232 with \
233 mock.patch('http.client.HTTPConnection') as mock_connection,\
234 mock.patch('msgpack.load') as mock_load:
235
236 client = HooksHttpClient(hooks_uri)
237
238 mock_load.return_value = {'result': 'success'}
239 response = mock.MagicMock()
240 response.status = 200
241 mock_connection.request.side_effect = None
242 mock_connection.getresponse.return_value = response
243
244 result = client(method, extras)
245
246 mock_connection.assert_called_with(hooks_uri)
247 mock_connection.return_value.request.assert_called_once()
248 assert result == {'result': 'success'}
249
250
251 def test_hooks_http_client_serialize():
252 method = 'test_method'
253 extras = {'key': 'value'}
254 headers, body = HooksHttpClient._serialize(method, extras)
255
256 assert headers == {'rc-hooks-protocol': HooksHttpClient.proto, 'Connection': 'keep-alive'}
257 assert msgpack.unpackb(body) == {'method': method, 'extras': extras}
General Comments 0
You need to be logged in to leave comments. Login now