Projet

Général

Profil

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

Josué Kouka, 20 juillet 2017 14:31

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
25 25
from django.utils.translation import ugettext_lazy as _
26 26
from django.http import HttpResponse, Http404
27 27

  
28
from suds import WebFault
29

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

  
43

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

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

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

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

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

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

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

  
103 117
    @endpoint(perm='can_access', name='create-file', methods=['post'])
104 118
    def create_file(self, request, email=None):
......
135 149

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

  
141 155
        if resp.MessageRetour.codeRetour == 'KO':
142 156
            if 'inconnu' in resp.MessageRetour.message:
143 157
                raise Http404(resp.MessageRetour.message)
......
173 187

  
174 188
    @endpoint(perm='can_access', name='get-file-status', pattern='(?P<file_id>[\w-]+)')
175 189
    def get_file_status(self, request, file_id):
176
        c = get_client(self)
177
        resp = c.service.GetHistoDossier(file_id)
190
        resp = self.call('GetHistoDossier', file_id)
178 191
        if resp.MessageRetour.codeRetour == 'KO':
179 192
            if 'inconnu' in resp.MessageRetour.message:
180 193
                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
-