Projet

Général

Profil

0002-iparapheur-add-handling-of-invalid-response-content.patch

Josué Kouka, 20 juillet 2017 14:44

Télécharger (9,01 ko)

Voir les différences:

Subject: [PATCH 2/2] iparapheur: add handling of invalid response content

 passerelle/contrib/iparapheur/models.py | 41 ++++++++++++++++---------
 passerelle/contrib/iparapheur/soap.py   | 19 +++++++++---
 tests/test_iparapheur.py                | 53 +++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+), 18 deletions(-)
passerelle/contrib/iparapheur/models.py
24 24
from django.utils.translation import ugettext_lazy as _
25 25
from django.http import HttpResponse, Http404
26 26

  
27
from suds import WebFault
28

  
27 29
from passerelle.base.models import BaseResource
28 30
from passerelle.utils.api import endpoint
29 31
from passerelle.utils.jsonresponse import APIError
......
37 39
    except ConnectionError as e:
38 40
        raise APIError('i-Parapheur error: %s' % e)
39 41

  
42

  
40 43
def format_type(t):
41 44
    return {'id': unicode(t), 'text': unicode(t)}
42 45

  
......
75 78
    def get_verbose_name(cls):
76 79
        return cls._meta.verbose_name
77 80

  
81
    def call(self, service_name, *args, **kwargs):
82
        client = get_client(self)
83
        try:
84
            result = getattr(client.service, service_name)(*args, **kwargs)
85
        except(WebFault,) as exc:
86
            # Remote Service Error: <SOAP-ENV:Fault> in response
87
            raise APIError('ServiceError: %s' % exc)
88
        except(Exception,) as exc:
89
            # Exception different from suds.tranport.TransportError
90
            if not exc.args or not isinstance(exc.args[0], tuple):
91
                raise exc
92
            # TransportError Exception
93
            raise APIError('Transport Error: %s' % exc)
94
        return result
95

  
78 96
    @endpoint(perm='can_access')
79 97
    def types(self, request):
80
        c = get_client(self)
81
        return {'data': [format_type(t) for t in c.service.GetListeTypes()]}
98
        return {'data': [format_type(t) for t in self.call('GetListeTypes')]}
82 99

  
83 100
    @endpoint(perm='can_access')
84 101
    def ping(self, request):
85
        c = get_client(self)
86
        return {'data': c.service.echo('ping')}
102
        return {'data': self.call('echo', 'ping')}
87 103

  
88 104
    @endpoint(perm='can_access')
89 105
    def subtypes(self, request, type=None):
90
        c = get_client(self)
91 106
        if type:
92
            return {'data': [format_type(t) for t in c.service.GetListeSousTypes(type)]}
93
        return {'data': [format_type(t) for t in c.service.GetListeSousTypes()]}
107
            return {'data': [format_type(t) for t in self.call('GetListeSousTypes', type)]}
108
        return {'data': [format_type(t) for t in self.call('GetListeSousTypes')]}
94 109

  
95 110
    @endpoint(perm='can_access')
96 111
    def files(self, request, status=None):
97
        c = get_client(self)
98 112
        if status:
99
            return {'data': [format_file(f) for f in c.service.RechercherDossiers(Status=status)]}
100
        return {'data': [format_file(f) for f in c.service.RechercherDossiers()]}
113
            return {'data': [format_file(f) for f in self.call('RechercherDossiers', Status=status)]}
114
        return {'data': [format_file(f) for f in self.call('RechercherDossiers')]}
101 115

  
102 116
    @endpoint(perm='can_access', name='create-file', methods=['post'])
103 117
    def create_file(self, request, email=None):
......
134 148

  
135 149
    @endpoint(perm='can_access', name='get-file', pattern='(?P<file_id>[\w-]+)')
136 150
    def get_file(self, request, file_id, appendix=None):
137
        client = get_client(self)
138
        resp = client.service.GetDossier(file_id)
151
        resp = self.call('GetDossier', file_id)
139 152
        filename = None
153

  
140 154
        if resp.MessageRetour.codeRetour == 'KO':
141 155
            if 'inconnu' in resp.MessageRetour.message:
142 156
                raise Http404(resp.MessageRetour.message)
......
171 185

  
172 186
    @endpoint(perm='can_access', name='get-file-status', pattern='(?P<file_id>[\w-]+)')
173 187
    def get_file_status(self, request, file_id):
174
        c = get_client(self)
175
        resp = c.service.GetHistoDossier(file_id)
188
        resp = self.call('GetHistoDossier', file_id)
176 189
        if resp.MessageRetour.codeRetour == 'KO':
177 190
            if 'inconnu' in resp.MessageRetour.message:
178 191
                raise Http404(resp.MessageRetour.message)
passerelle/contrib/iparapheur/soap.py
22 22

  
23 23
from suds.client import Client
24 24
from suds.transport.http import HttpAuthenticated
25
from suds.transport import Reply
25
from suds.transport import Reply, TransportError
26 26
from suds.plugin import MessagePlugin, DocumentPlugin
27 27

  
28
from suds.sudsobject import asdict
28
from requests.exceptions import RequestException
29 29

  
30 30

  
31 31
class Filter(MessagePlugin):
......
72 72
    def send(self, request):
73 73
        request.message = request.message.replace("contentType", "xm:contentType")
74 74
        self.addcredentials(request)
75
        resp = self.model.requests.post(request.url, data=request.message,
75
        try:
76
            resp = self.model.requests.post(request.url, data=request.message,
76 77
                headers=request.headers, **self.get_requests_kwargs())
77
        return Reply(resp.status_code, resp.headers, resp.content)
78
        except(RequestException,) as e:
79
            raise TransportError(e.message.message, None)
80

  
81
        if resp.status_code in (202, 204):
82
            return None
83
        elif not resp.ok:
84
            raise TransportError(
85
                resp.reason,
86
                resp.status_code, fp=StringIO.StringIO(resp.content))
87
        else:
88
            return Reply(resp.status_code, resp.headers, resp.content)
78 89

  
79 90
def get_client(instance):
80 91
    transport = Transport(instance)
tests/test_iparapheur.py
275 275
    assert 'filename=iParapheur_impression_dossier.pdf' in resp.headers['Content-Disposition']
276 276
    assert 'filename*=UTF-8\'\'iParapheur_impression_dossier.pdf' in resp.headers['Content-Disposition']
277 277
    assert resp.body == 'Test Document Appendix'
278

  
279

  
280
@mock.patch('passerelle.utils.LoggedRequest.get')
281
@mock.patch('passerelle.utils.LoggedRequest.post')
282
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open')
283
def test_invalid_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file):
284
    app, conn = setup
285
    file_id = str(uuid.uuid4())
286

  
287
    http_open.return_value = file(xmlmime)
288
    mocked_get.return_value = mock.Mock(content=file(wsdl_file).read(),
289
                                        status_code=200)
290
    mocked_post.return_value = mock.Mock(status_code=502,
291
            content='<p>Bad Gateway</p>', reason='Bad Gateway', ok=False)
292
    url = reverse('generic-endpoint', kwargs={'slug': conn.slug,
293
                  'connector': 'iparapheur', 'endpoint': 'get-file-status', 'rest': file_id})
294
    url += '?apikey=%s' % API_KEY
295
    resp = app.get(url)
296
    assert resp.json['err_desc'] == "Transport Error: (502, u'Bad Gateway')"
297

  
298

  
299
@mock.patch('passerelle.utils.LoggedRequest.get')
300
@mock.patch('passerelle.utils.LoggedRequest.post')
301
@mock.patch('passerelle.contrib.iparapheur.soap.HttpAuthenticated.open')
302
def test_webfault_response(http_open, mocked_post, mocked_get, setup, xmlmime, wsdl_file):
303
    app, conn = setup
304
    file_id = str(uuid.uuid4())
305
    url = reverse('generic-endpoint', kwargs={'slug': conn.slug,
306
                  'connector': 'iparapheur', 'endpoint': 'get-file-status', 'rest': file_id})
307
    url += '?apikey=%s' % API_KEY
308

  
309
    http_open.return_value = file(xmlmime)
310
    mocked_get.return_value = mock.Mock(content=file(wsdl_file).read(),
311
                                        status_code=200)
312
    webfault_response = """
313
    <?xml version='1.0' encoding='UTF-8'?>
314
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
315
        <SOAP-ENV:Body>
316
            <SOAP-ENV:Fault>
317
                <faultcode xsi:type="xsd:string">SOAP-ENV:Client</faultcode>
318
                    <faultstring xsi:type="xsd:string">
319
                        Test server error
320
                   </faultstring>
321
           </SOAP-ENV:Fault>
322
        </SOAP-ENV:Body>
323
     </SOAP-ENV:Envelope>"""
324

  
325
    mocked_post.return_value = mock.Mock(
326
        status_code=200, content=webfault_response,
327
        ok=True)
328
    resp = app.get(url)
329
    assert 'ServiceError' in resp.json['err_desc']
330
    assert 'Test server error' in resp.json['err_desc']
278
-