##// END OF EJS Templates
feat(celery-hooks): added HooksCeleryClient, removed support od HooksDummyClient, updated tests. Fixes: RCCE-55
ilin.s -
r1204:79967b24 default
parent child Browse files
Show More
@@ -2,6 +2,26 b''
2 2
3 3 async-timeout==4.0.3
4 4 atomicwrites==1.4.1
5 celery==5.3.4
6 billiard==4.1.0
7 click==8.1.3
8 click-didyoumean==0.3.0
9 click==8.1.3
10 click-plugins==1.1.1
11 click==8.1.3
12 click-repl==0.2.0
13 click==8.1.3
14 prompt-toolkit==3.0.38
15 wcwidth==0.2.6
16 six==1.16.0
17 kombu==5.3.2
18 amqp==5.1.1
19 vine==5.1.0
20 vine==5.1.0
21 python-dateutil==2.8.2
22 six==1.16.0
23 tzdata==2023.4
24 vine==5.1.0
5 25 contextlib2==21.6.0
6 26 cov-core==1.15.0
7 27 coverage==7.2.3
@@ -27,6 +27,7 b' import dataclasses'
27 27 import pygit2
28 28
29 29 import http.client
30 from celery import Celery
30 31
31 32
32 33 import mercurial.scmutil
@@ -37,6 +38,7 b' from vcsserver import exceptions, subpro'
37 38 from vcsserver.str_utils import ascii_str, safe_str
38 39 from vcsserver.remote.git_remote import Repository
39 40
41 celery_app = Celery()
40 42 log = logging.getLogger(__name__)
41 43
42 44
@@ -88,14 +90,24 b' class HooksHttpClient:'
88 90 return headers, msgpack.packb(data)
89 91
90 92
91 class HooksDummyClient:
92 def __init__(self, hooks_module):
93 log.debug('HooksDummyClient import: %s', hooks_module)
94 self._hooks_module = importlib.import_module(hooks_module)
93 class HooksCeleryClient:
94 TASK_TIMEOUT = 60 # time in seconds
95 95
96 def __call__(self, hook_name, extras):
97 with self._hooks_module.Hooks() as hooks:
98 return getattr(hooks, hook_name)(extras)
96 def __init__(self, queue, backend):
97 celery_app.config_from_object({'broker_url': queue, 'result_backend': backend,
98 'broker_connection_retry_on_startup': True,
99 'task_serializer': 'msgpack',
100 'accept_content': ['json', 'msgpack'],
101 'result_serializer': 'msgpack',
102 'result_accept_content': ['json', 'msgpack']
103 })
104 self.celery_app = celery_app
105
106 def __call__(self, method, extras):
107 inquired_task = self.celery_app.signature(
108 f'rhodecode.lib.celerylib.tasks.{method}'
109 )
110 return inquired_task.delay(extras).get(timeout=self.TASK_TIMEOUT)
99 111
100 112
101 113 class HooksShadowRepoClient:
@@ -167,19 +179,18 b' def _handle_exception(result):'
167 179
168 180 def _get_hooks_client(extras):
169 181 hooks_uri = extras.get('hooks_uri')
182 task_queue = extras.get('task_queue')
183 task_backend = extras.get('task_backend')
170 184 is_shadow_repo = extras.get('is_shadow_repo')
171 185
172 186 if hooks_uri:
173 return HooksHttpClient(extras['hooks_uri'])
187 return HooksHttpClient(hooks_uri)
188 elif task_queue and task_backend:
189 return HooksCeleryClient(task_queue, task_backend)
174 190 elif is_shadow_repo:
175 191 return HooksShadowRepoClient()
176 192 else:
177 try:
178 import_module = extras['hooks_module']
179 except KeyError:
180 log.error('Failed to get "hooks_module" from extras: %s', extras)
181 raise
182 return HooksDummyClient(import_module)
193 raise Exception("Hooks client not found!")
183 194
184 195
185 196 def _call_hook(hook_name, extras, writer):
@@ -132,18 +132,14 b' class TestGetHooksClient:'
132 132 assert isinstance(result, hooks.HooksHttpClient)
133 133 assert result.hooks_uri == hooks_uri
134 134
135 def test_returns_dummy_client_when_hooks_uri_not_specified(self):
136 fake_module = mock.Mock()
137 import_patcher = mock.patch.object(
138 hooks.importlib, 'import_module', return_value=fake_module)
139 fake_module_name = 'fake.module'
140 with import_patcher as import_mock:
141 result = hooks._get_hooks_client(
142 {'hooks_module': fake_module_name})
143
144 import_mock.assert_called_once_with(fake_module_name)
145 assert isinstance(result, hooks.HooksDummyClient)
146 assert result._hooks_module == fake_module
135 def test_return_celery_client_when_queue_and_backend_provided(self):
136 task_queue = 'redis://task_queue:0'
137 task_backend = task_queue
138 result = hooks._get_hooks_client({
139 'task_queue': task_queue,
140 'task_backend': task_backend
141 })
142 assert isinstance(result, hooks.HooksCeleryClient)
147 143
148 144
149 145 class TestHooksHttpClient:
@@ -182,31 +178,6 b' class TestHooksHttpClient:'
182 178 assert result == expected_result
183 179
184 180
185 class TestHooksDummyClient:
186 def test_init_imports_hooks_module(self):
187 hooks_module_name = 'rhodecode.fake.module'
188 hooks_module = mock.MagicMock()
189
190 import_patcher = mock.patch.object(
191 hooks.importlib, 'import_module', return_value=hooks_module)
192 with import_patcher as import_mock:
193 client = hooks.HooksDummyClient(hooks_module_name)
194 import_mock.assert_called_once_with(hooks_module_name)
195 assert client._hooks_module == hooks_module
196
197 def test_call_returns_hook_result(self):
198 hooks_module_name = 'rhodecode.fake.module'
199 hooks_module = mock.MagicMock()
200 import_patcher = mock.patch.object(
201 hooks.importlib, 'import_module', return_value=hooks_module)
202 with import_patcher:
203 client = hooks.HooksDummyClient(hooks_module_name)
204
205 result = client('post_push', {})
206 hooks_module.Hooks.assert_called_once_with()
207 assert result == hooks_module.Hooks().__enter__().post_push()
208
209
210 181 @pytest.fixture
211 182 def http_mirror(request):
212 183 server = MirrorHttpServer()
General Comments 0
You need to be logged in to leave comments. Login now