##// 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 async-timeout==4.0.3
3 async-timeout==4.0.3
4 atomicwrites==1.4.1
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 contextlib2==21.6.0
25 contextlib2==21.6.0
6 cov-core==1.15.0
26 cov-core==1.15.0
7 coverage==7.2.3
27 coverage==7.2.3
@@ -27,6 +27,7 b' import dataclasses'
27 import pygit2
27 import pygit2
28
28
29 import http.client
29 import http.client
30 from celery import Celery
30
31
31
32
32 import mercurial.scmutil
33 import mercurial.scmutil
@@ -37,6 +38,7 b' from vcsserver import exceptions, subpro'
37 from vcsserver.str_utils import ascii_str, safe_str
38 from vcsserver.str_utils import ascii_str, safe_str
38 from vcsserver.remote.git_remote import Repository
39 from vcsserver.remote.git_remote import Repository
39
40
41 celery_app = Celery()
40 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
41
43
42
44
@@ -88,14 +90,24 b' class HooksHttpClient:'
88 return headers, msgpack.packb(data)
90 return headers, msgpack.packb(data)
89
91
90
92
91 class HooksDummyClient:
93 class HooksCeleryClient:
92 def __init__(self, hooks_module):
94 TASK_TIMEOUT = 60 # time in seconds
93 log.debug('HooksDummyClient import: %s', hooks_module)
94 self._hooks_module = importlib.import_module(hooks_module)
95
95
96 def __call__(self, hook_name, extras):
96 def __init__(self, queue, backend):
97 with self._hooks_module.Hooks() as hooks:
97 celery_app.config_from_object({'broker_url': queue, 'result_backend': backend,
98 return getattr(hooks, hook_name)(extras)
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 class HooksShadowRepoClient:
113 class HooksShadowRepoClient:
@@ -167,19 +179,18 b' def _handle_exception(result):'
167
179
168 def _get_hooks_client(extras):
180 def _get_hooks_client(extras):
169 hooks_uri = extras.get('hooks_uri')
181 hooks_uri = extras.get('hooks_uri')
182 task_queue = extras.get('task_queue')
183 task_backend = extras.get('task_backend')
170 is_shadow_repo = extras.get('is_shadow_repo')
184 is_shadow_repo = extras.get('is_shadow_repo')
171
185
172 if hooks_uri:
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 elif is_shadow_repo:
190 elif is_shadow_repo:
175 return HooksShadowRepoClient()
191 return HooksShadowRepoClient()
176 else:
192 else:
177 try:
193 raise Exception("Hooks client not found!")
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)
183
194
184
195
185 def _call_hook(hook_name, extras, writer):
196 def _call_hook(hook_name, extras, writer):
@@ -132,18 +132,14 b' class TestGetHooksClient:'
132 assert isinstance(result, hooks.HooksHttpClient)
132 assert isinstance(result, hooks.HooksHttpClient)
133 assert result.hooks_uri == hooks_uri
133 assert result.hooks_uri == hooks_uri
134
134
135 def test_returns_dummy_client_when_hooks_uri_not_specified(self):
135 def test_return_celery_client_when_queue_and_backend_provided(self):
136 fake_module = mock.Mock()
136 task_queue = 'redis://task_queue:0'
137 import_patcher = mock.patch.object(
137 task_backend = task_queue
138 hooks.importlib, 'import_module', return_value=fake_module)
138 result = hooks._get_hooks_client({
139 fake_module_name = 'fake.module'
139 'task_queue': task_queue,
140 with import_patcher as import_mock:
140 'task_backend': task_backend
141 result = hooks._get_hooks_client(
141 })
142 {'hooks_module': fake_module_name})
142 assert isinstance(result, hooks.HooksCeleryClient)
143
144 import_mock.assert_called_once_with(fake_module_name)
145 assert isinstance(result, hooks.HooksDummyClient)
146 assert result._hooks_module == fake_module
147
143
148
144
149 class TestHooksHttpClient:
145 class TestHooksHttpClient:
@@ -182,31 +178,6 b' class TestHooksHttpClient:'
182 assert result == expected_result
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 @pytest.fixture
181 @pytest.fixture
211 def http_mirror(request):
182 def http_mirror(request):
212 server = MirrorHttpServer()
183 server = MirrorHttpServer()
General Comments 0
You need to be logged in to leave comments. Login now