0001-utils-soap-upgrade-zeep-soap-library-version-35370.patch
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 |
|
28 |
zeep_version = 3 |
|
29 |
except ImportError: |
|
30 |
zeep_version = 2 |
|
26 | 31 | |
27 | 32 |
from passerelle.base.models import BaseResource, HTTPResource |
28 | 33 |
from passerelle.utils.api import endpoint |
... | ... | |
107 | 112 |
def get_verbose_name(cls): |
108 | 113 |
return cls._meta.verbose_name |
109 | 114 | |
110 |
def get_client(self, strict_mode=True):
|
|
115 |
def get_client(self, **kwargs):
|
|
111 | 116 |
try: |
112 |
soap_client = self.soap_client(strict=strict_mode)
|
|
117 |
soap_client = self.soap_client(**kwargs)
|
|
113 | 118 | |
114 | 119 |
# overrides the service port address URL defined in the WSDL. |
115 | 120 |
if self.wsdl_endpoint_location: |
... | ... | |
125 | 130 | |
126 | 131 |
def call(self, service_name, *args, **kwargs): |
127 | 132 |
strict_mode = kwargs.pop('strict_mode', True) |
128 |
client = self.get_client(strict_mode=strict_mode) |
|
129 | 133 |
try: |
130 |
result = getattr(client.overridden_service, service_name)(*args, **kwargs) |
|
134 |
if zeep_version == 2: |
|
135 |
client = self.get_client(strict=strict_mode) |
|
136 |
result = getattr(client.overridden_service, service_name)(*args, **kwargs) |
|
137 |
else: |
|
138 |
client = self.get_client() |
|
139 |
with client.settings(strict=strict_mode): |
|
140 |
result = getattr(client.overridden_service, service_name)(*args, **kwargs) |
|
131 | 141 |
except WebFault as exc: |
132 | 142 |
# Remote Service Error: <SOAP-ENV:Fault> in response |
133 | 143 |
raise APIError('ServiceError: %s' % 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 |
|
8 |
zeep_version = 3 |
|
9 |
except ImportError: |
|
10 |
zeep_version = 2 |
|
3 | 11 | |
4 | 12 |
from passerelle.utils.soap import SOAPClient |
5 | 13 | |
... | ... | |
30 | 38 |
assert client.transport.session == soap_resource.requests |
31 | 39 |
assert client.transport.cache |
32 | 40 |
assert client.plugins == plugins |
41 | ||
42 |
@mock.patch('requests.sessions.Session.post') |
|
43 |
def test_disable_strict_mode(mocked_post): |
|
44 |
response = requests.Response() |
|
45 |
response.status_code = 200 |
|
46 |
response._content = '''<?xml version='1.0' encoding='utf-8'?> |
|
47 |
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> |
|
48 |
<soap-env:Body> |
|
49 |
<ns0:TradePrice xmlns:ns0="http://example.com/stockquote.xsd"> |
|
50 |
<price>4.20</price> |
|
51 |
</ns0:TradePrice> |
|
52 |
</soap-env:Body> |
|
53 |
</soap-env:Envelope>''' |
|
54 |
mocked_post.return_value = response |
|
55 | ||
56 |
soap_resource = SOAPResource() |
|
57 |
client = SOAPClient(soap_resource) |
|
58 |
with pytest.raises( |
|
59 |
XMLParseError, match="Unexpected element u'price', expected u'skipMe'"): |
|
60 |
client.service.GetLastTradePrice(tickerSymbol='banana') |
|
61 | ||
62 |
if zeep_version == 2: |
|
63 |
client = SOAPClient(soap_resource, strict=False) |
|
64 |
result = client.service.GetLastTradePrice(tickerSymbol='banana') |
|
65 |
else: |
|
66 |
client = SOAPClient(soap_resource) |
|
67 |
with client.settings(strict=False): |
|
68 |
result = client.service.GetLastTradePrice(tickerSymbol='banana') |
|
69 |
assert len(result) == 2 |
|
70 |
assert result['skipMe'] == None |
|
71 |
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 |
- |