0002-base-resource-add-automatic-up-endpoint-21978.patch
passerelle/base/models.py | ||
---|---|---|
34 | 34 | |
35 | 35 |
import passerelle |
36 | 36 |
import requests |
37 |
from passerelle.utils.api import endpoint |
|
38 |
from passerelle.utils.jsonresponse import APIError |
|
37 | 39 | |
38 | 40 |
KEYTYPE_CHOICES = ( |
39 | 41 |
('API', _('API Key')), |
... | ... | |
231 | 233 |
for name, method in inspect.getmembers(self, predicate=inspect.ismethod): |
232 | 234 |
if hasattr(method, 'endpoint_info'): |
233 | 235 |
method.endpoint_info.object = self |
236 |
endpoint_name = method.endpoint_info.name |
|
237 |
if endpoint_name == 'up' and hasattr(self.check_status, 'not_implemented'): |
|
238 |
# hide automatic up endpoint if check_status method is not implemented |
|
239 |
continue |
|
234 | 240 |
for http_method in method.endpoint_info.methods: |
235 | 241 |
# duplicate information to give each method its own entry |
236 | 242 |
endpoint_info = copy.copy(method.endpoint_info) |
... | ... | |
395 | 401 |
raise NotImplementedError |
396 | 402 |
check_status.not_implemented = True |
397 | 403 | |
404 |
@endpoint(description=_('Check service availability')) |
|
405 |
def up(self, request, **kwargs): |
|
406 |
try: |
|
407 |
self.check_status() |
|
408 |
except Exception as e: |
|
409 |
raise APIError('service not available: %s' % e) |
|
410 |
return {'err': 0} |
|
411 | ||
398 | 412 |
def availability(self): |
399 | 413 |
# "availability" cron job to update service statuses |
400 | 414 |
passerelle/views.py | ||
---|---|---|
364 | 364 |
self.endpoint = method |
365 | 365 |
if not self.endpoint: |
366 | 366 |
raise Http404() |
367 |
if kwargs.get('endpoint') == 'up' and hasattr(connector.check_status, 'not_implemented'): |
|
368 |
# hide automatic up endpoint if check_status method is not implemented |
|
369 |
raise Http404() |
|
367 | 370 |
return super(GenericEndpointView, self).dispatch(request, *args, **kwargs) |
368 | 371 | |
369 | 372 |
def _allowed_methods(self): |
tests/test_generic_endpoint.py | ||
---|---|---|
27 | 27 | |
28 | 28 |
import utils |
29 | 29 | |
30 |
from django.core.urlresolvers import reverse |
|
31 | ||
30 | 32 |
from passerelle.apps.arcgis.models import ArcGIS |
31 | 33 |
from passerelle.base.models import ResourceLog, ProxyLogger, BaseResource, HTTPResource |
32 | 34 |
from passerelle.apps.mdel.models import MDEL |
... | ... | |
403 | 405 |
json_res = app.get('/stub-invoices/fake/httpcall?floating=', status=400).json |
404 | 406 |
assert json_res['err'] == 1 |
405 | 407 |
assert json_res['err_desc'] == 'invalid value for parameter "floating"' |
408 | ||
409 | ||
410 |
class DummyConnectorBase(BaseResource): |
|
411 |
class Meta: |
|
412 |
app_label = 'dummy' |
|
413 |
abstract = True |
|
414 | ||
415 | ||
416 |
class DummyConnectorWithCheckStatus(DummyConnectorBase): |
|
417 |
def check_status(self): |
|
418 |
return |
|
419 | ||
420 | ||
421 |
class DummyConnectorWithCheckStatusFailure(DummyConnectorBase): |
|
422 |
def check_status(self): |
|
423 |
raise Exception('dummy reason') |
|
424 | ||
425 | ||
426 |
class DummyConnectorWithoutCheckStatus(DummyConnectorBase): |
|
427 |
pass |
|
428 | ||
429 | ||
430 |
@pytest.mark.parametrize('connector_class, expected_status, expected_response', [ |
|
431 |
(DummyConnectorWithCheckStatus, 200, {'err': 0}), |
|
432 |
(DummyConnectorWithCheckStatusFailure, 200, |
|
433 |
{'err_class': 'passerelle.utils.jsonresponse.APIError', |
|
434 |
'err_desc': 'service not available: dummy reason', 'data': None, 'err': 1}), |
|
435 |
(DummyConnectorWithoutCheckStatus, 404, None), |
|
436 |
]) |
|
437 |
def test_generic_up_endpoint(db, app, connector_class, expected_status, expected_response): |
|
438 |
connector = connector_class() |
|
439 |
connector.id = 42 |
|
440 | ||
441 |
url = reverse('generic-endpoint', kwargs={ |
|
442 |
'connector': 'foo', |
|
443 |
'slug': 'foo', |
|
444 |
'endpoint': 'up', |
|
445 |
}) |
|
446 |
patch_init = mock.patch('passerelle.views.GenericConnectorMixin.init_stuff') |
|
447 |
patch_object = mock.patch('passerelle.views.GenericEndpointView.get_object', |
|
448 |
return_value=connector) |
|
449 |
with patch_init, patch_object: |
|
450 |
response = app.get(url, status=expected_status) |
|
451 |
if expected_response is not None: |
|
452 |
assert response.json == expected_response |
|
453 | ||
454 | ||
455 |
@pytest.mark.parametrize('connector_class, expected', [ |
|
456 |
(DummyConnectorWithCheckStatus, True), |
|
457 |
(DummyConnectorWithCheckStatusFailure, True), |
|
458 |
(DummyConnectorWithoutCheckStatus, False), |
|
459 |
]) |
|
460 |
def test_generic_up_in_endpoints_infos(db, app, connector_class, expected): |
|
461 |
connector = connector_class() |
|
462 |
connector.id = 42 |
|
463 | ||
464 |
up_endpoints = [ |
|
465 |
ep for ep in connector.get_endpoints_infos() |
|
466 |
if ep.name == 'up'] |
|
467 |
if expected: |
|
468 |
assert len(up_endpoints) == 1 |
|
469 |
else: |
|
470 |
assert up_endpoints == [] |
|
406 |
- |