Projet

Général

Profil

0001-utils-soap-allow-zeep-versions-2-and-3-35370.patch

Thomas Noël, 14 janvier 2020 16:07

Télécharger (10,2 ko)

Voir les différences:

Subject: [PATCH 1/2] utils/soap: allow zeep versions 2 and 3 (#35370)

 passerelle/contrib/iparapheur/models.py | 13 ++++++---
 setup.py                                |  2 +-
 tests/data/soap.wsdl                    |  5 ++--
 tests/test_iparapheur.py                | 28 ++++++++++++++-----
 tests/test_soap.py                      | 36 +++++++++++++++++++++++++
 tox.ini                                 |  4 ++-
 6 files changed, 75 insertions(+), 13 deletions(-)
passerelle/contrib/iparapheur/models.py
23 23
from django.http import HttpResponse, Http404
24 24

  
25 25
from zeep.exceptions import Fault as WebFault, TransportError, XMLSyntaxError
26
try:
27
    from zeep import Settings  # zeep version >= 3.x
28
except ImportError:
29
    Settings = None
26 30

  
27 31
from passerelle.base.models import BaseResource, HTTPResource
28 32
from passerelle.utils.api import endpoint
......
97 101
    def get_verbose_name(cls):
98 102
        return cls._meta.verbose_name
99 103

  
100
    def get_client(self, strict_mode=True):
104
    def get_client(self, **kwargs):
101 105
        try:
102
            soap_client = self.soap_client(strict=strict_mode)
106
            soap_client = self.soap_client(**kwargs)
103 107

  
104 108
            # overrides the service port address URL defined in the WSDL.
105 109
            if self.wsdl_endpoint_location:
......
115 119

  
116 120
    def call(self, service_name, *args, **kwargs):
117 121
        strict_mode = kwargs.pop('strict_mode', True)
118
        client = self.get_client(strict_mode=strict_mode)
122
        if Settings is not None:  # zeep version >= 3.x:
123
            client = self.get_client(settings=Settings(strict=strict_mode))
124
        else:
125
            client = self.get_client(strict=strict_mode)
119 126
        try:
120 127
            result = getattr(client.overridden_service, service_name)(*args, **kwargs)
121 128
        except WebFault as exc:
setup.py
104 104
            'python-dateutil',
105 105
            'Pillow',
106 106
            'jsonschema < 3.1',
107
            'zeep < 3.0',
107
            'zeep',
108 108
            'pycrypto',
109 109
            'unidecode',
110 110
            'paramiko',
tests/data/soap.wsdl
48 48
      </element>
49 49
      <element name="TradePrice">
50 50
        <complexType>
51
          <all>
51
          <sequence>
52
            <element name="skipMe" type="float"/>
52 53
            <element name="price" type="float"/>
53
          </all>
54
          </sequence>
54 55
        </complexType>
55 56
      </element>
56 57
      <complexType name="account">
tests/test_iparapheur.py
8 8
import xml.etree.ElementTree as ET
9 9
from dateutil import parser
10 10
from requests import Response
11
from zeep import __version__ as zeep_version
11 12

  
12 13
from requests.exceptions import ConnectionError
13 14
from django.core.urlresolvers import reverse
......
41 42
                    resource_pk=conn.pk)
42 43
    return conn
43 44

  
45
def assert_invalid_xml(err_desc):
46
    if zeep_version < '3':
47
        assert "Server returned HTTP status 200 (<nada>)" in err_desc
48
    else:
49
        assert "Server returned response (200) with invalid XML" in err_desc
50

  
44 51
def xmlmime():
45 52
    return os.path.join(os.path.dirname(__file__), 'data','xmlmime.xml')
46 53

  
......
70 77
def test_call_ping(soap_client, app, conn):
71 78
    service = mock.Mock()
72 79
    service.echo.return_value = 'pong'
73
    mocked_client = mock.Mock(overridden_service=service)
80

  
81
    class MockedSettings(object):
82
        def __init__(self, **kwargs):
83
            pass
84
        def __enter__(self):
85
            pass
86
        def __exit__(self, exc_type, exc_value, traceback):
87
            pass
88

  
89
    mocked_client = mock.Mock(overridden_service=service, settings=MockedSettings)
74 90
    soap_client.return_value = mocked_client
75 91
    url = reverse('generic-endpoint', kwargs={'connector': 'iparapheur',
76 92
                    'endpoint': 'ping', 'slug': conn.slug})
......
187 203
    assert (BASE_URL,) == mocked_post.call_args[0]
188 204
    assert resp.json['err'] == 1
189 205
    assert 'zeep.exceptions.TransportError' in resp.json['err_class']
190
    assert 'Server returned HTTP status 200 (<nada>)' in resp.json['err_desc']
206
    assert_invalid_xml(resp.json['err_desc'])
191 207

  
192 208
    # Unknown value for "visibility"
193 209
    err_data = data.copy()
......
211 227
    assert (BASE_URL,) == mocked_post.call_args[0]
212 228
    assert resp.json['err'] == 1
213 229
    assert 'zeep.exceptions.TransportError' in resp.json['err_class']
214
    assert 'Server returned HTTP status 200 (<nada>)' in resp.json['err_desc']
230
    assert_invalid_xml(resp.json['err_desc'])
215 231

  
216 232
@mock.patch('passerelle.utils.Request.get', side_effect=iph_mocked_get)
217 233
@mock.patch('passerelle.utils.Request.post')
......
300 316
    assert resp.json['err'] == 1
301 317
    #assert 'zeep.exceptions.TransportError' in resp.json['err_class']
302 318
    assert 'passerelle.utils.jsonresponse.APIError' in resp.json['err_class']
303
    assert 'Server returned HTTP status 200 (<nada>)' in resp.json['err_desc']
319
    assert_invalid_xml(resp.json['err_desc'])
304 320

  
305 321
@mock.patch('passerelle.utils.Request.get', side_effect=iph_mocked_get)
306 322
@mock.patch('passerelle.utils.Request.post')
......
325 341
    assert resp.body == 'Test Document'
326 342

  
327 343
    # KO
328
    soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><CreerDossierResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"><MessageRetour><codeRetour>KO</codeRetour><message>KOmessage</message><severite>INFO</severite></MessageRetour></CreerDossierResponse></S:Body></S:Envelope>"""
344
    soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><GetDossierResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"><MessageRetour><codeRetour>KO</codeRetour><message>KOmessage</message><severite>INFO</severite></MessageRetour></GetDossierResponse></S:Body></S:Envelope>"""
329 345
    response._content = soap_response
330 346
    mocked_post.return_value = response
331 347
    resp = app.get(url, status=500)
......
334 350
    assert resp.json['err_desc'] == 'KOmessage'
335 351

  
336 352
    # unknown response
337
    soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><CreerDossierResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"></CreerDossierResponse></S:Body></S:Envelope>"""
353
    soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><GetDossierResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"></GetDossierResponse></S:Body></S:Envelope>"""
338 354
    response._content = soap_response
339 355
    mocked_post.return_value = response
340 356
    resp = app.get(url, status=500)
tests/test_soap.py
1
import pytest
2
import mock
1 3
import requests
2 4
from zeep.plugins import Plugin
5
from zeep.exceptions import XMLParseError
6
try:
7
    from zeep import Settings  # zeep version >= 3.x
8
except ImportError:
9
    Settings = None
3 10

  
4 11
from passerelle.utils.soap import SOAPClient
5 12

  
......
30 37
    assert client.transport.session == soap_resource.requests
31 38
    assert client.transport.cache
32 39
    assert client.plugins == plugins
40

  
41
@mock.patch('requests.sessions.Session.post')
42
def test_disable_strict_mode(mocked_post):
43
    response = requests.Response()
44
    response.status_code = 200
45
    response._content = '''<?xml version='1.0' encoding='utf-8'?>
46
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
47
  <soap-env:Body>
48
    <ns0:TradePrice xmlns:ns0="http://example.com/stockquote.xsd">
49
      <price>4.20</price>
50
    </ns0:TradePrice>
51
  </soap-env:Body>
52
</soap-env:Envelope>'''
53
    mocked_post.return_value = response
54

  
55
    soap_resource = SOAPResource()
56
    client = SOAPClient(soap_resource)
57
    with pytest.raises(
58
            XMLParseError, match="Unexpected element u'price', expected u'skipMe'"):
59
        client.service.GetLastTradePrice(tickerSymbol='banana')
60

  
61
    if Settings is not None:  # zeep version >= 3.x:
62
        client = SOAPClient(soap_resource, settings=Settings(strict=False))
63
    else:
64
        client = SOAPClient(soap_resource, strict=False)
65
    result = client.service.GetLastTradePrice(tickerSymbol='banana')
66
    assert len(result) == 2
67
    assert result['skipMe'] == None
68
    assert result['price'] == 4.2
tox.ini
1 1
[tox]
2 2
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/passerelle/{env:BRANCH_NAME:}
3
envlist = django111-pg
3
envlist = django111-pg-zeep2
4 4

  
5 5
[testenv]
6 6
usedevelop = True
......
36 36
  vobject
37 37
  django-ratelimit
38 38
  pyquery
39
  zeep2: zeep < 3.0
40
  zeep3: zeep >= 3.0
39 41
commands =
40 42
  ./get_wcs.sh
41 43
  django111: py.test {posargs: {env:FAST:} --junitxml=test_{envname}_results.xml --cov-report xml --cov-report html --cov=passerelle/ --cov-config .coveragerc tests/}
42
-