Projet

Général

Profil

0002-base-resource-add-automatic-up-endpoint-21978.patch

Lauréline Guérin, 11 octobre 2019 14:37

Télécharger (5,47 ko)

Voir les différences:

Subject: [PATCH 2/3] base resource: add automatic 'up' endpoint (#21978)

if method 'check_status' is defined, provide a 'up' endpoint
 passerelle/base/models.py      | 14 ++++++++
 passerelle/views.py            |  3 ++
 tests/test_generic_endpoint.py | 65 ++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
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
-