From 8c243828eb5ba034f99aa73ba2ebde87ee63f495 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Wed, 6 Mar 2019 19:02:50 +0100 Subject: [PATCH 5/5] let requests handle HTTP errors (#31114) --- passerelle/apps/api_particulier/models.py | 37 +- passerelle/apps/arcgis/models.py | 9 +- passerelle/apps/arpege_ecp/models.py | 18 +- passerelle/apps/base_adresse/models.py | 10 +- passerelle/apps/bdp/models.py | 13 +- passerelle/apps/okina/models.py | 21 +- passerelle/apps/opengis/models.py | 8 +- passerelle/apps/solis/models.py | 24 +- passerelle/apps/vivaticket/models.py | 39 +- passerelle/contrib/gdema/models.py | 19 +- passerelle/contrib/greco/models.py | 6 +- passerelle/contrib/mdph13/models.py | 3 +- passerelle/contrib/planitech/models.py | 22 +- passerelle/contrib/solis_apa/models.py | 30 +- passerelle/contrib/teamnet_axel/soap.py | 5 +- passerelle/soap.py | 1 + tests/conftest.py | 100 ++++ tests/test_api_particulier.py | 2 +- tests/test_arpege_ecp.py | 68 +-- tests/test_gdema.py | 177 +++--- tests/test_generic_endpoint.py | 8 +- tests/test_okina.py | 400 ++++++------- tests/test_opengis.py | 162 +++-- tests/test_planitech.py | 41 +- tests/test_requests.py | 167 +++--- tests/test_solis.py | 687 ++++++++++------------ tests/test_vivaticket.py | 142 +++-- 27 files changed, 1127 insertions(+), 1092 deletions(-) diff --git a/passerelle/apps/api_particulier/models.py b/passerelle/apps/api_particulier/models.py index f3c036f..5ce158a 100644 --- a/passerelle/apps/api_particulier/models.py +++ b/passerelle/apps/api_particulier/models.py @@ -73,10 +73,29 @@ class APIParticulier(BaseResource): url, headers=headers, **kwargs) + except requests.HTTPError as e: + msg = u'API-particulier platform "%s" request error %s' % (self.platform, e) + try: + data = e.response.json() + if data.get('error') == 'not_found': + return { + 'err': 1, + 'err_desc': data.get('message', 'not_found'), + } + msg += ': %s' % data + except ValueError: + pass + raise APIError( + msg, + (self.platform, e), + data={ + 'platform': self.platform, + 'error': six.text_type(e), + }) except requests.RequestException as e: raise APIError( - u'API-particulier platform "%s" connection error: %s' % - (self.platform, response.status_code), + u'API-particulier platform "%s" request error: %s' % + (self.platform, e), data={ 'platform': self.platform, 'error': six.text_type(e), @@ -94,20 +113,6 @@ class APIParticulier(BaseResource): 'platform': self.platform, 'content': content, }) - if response.status_code != 200: - if data.get('error') == 'not_found': - return { - 'err': 1, - 'err_desc': data.get('message', 'not-found'), - } - raise APIError( - u'API-particulier platform "%s" returned a non 200 status %s: %s' % - (self.platform, response.status_code, data), - data={ - 'status_code': response.status_code, - 'platform': self.platform, - 'content': data, - }) return { 'err': 0, 'data': data, diff --git a/passerelle/apps/arcgis/models.py b/passerelle/apps/arcgis/models.py index 8721f83..aff743f 100644 --- a/passerelle/apps/arcgis/models.py +++ b/passerelle/apps/arcgis/models.py @@ -16,6 +16,8 @@ import urlparse +import requests + from django.db import models from django.template import Template, Context from django.utils.translation import ugettext_lazy as _ @@ -113,11 +115,12 @@ class ArcGIS(BaseResource, HTTPResource): if 'distance' in params and 'units' not in params: params['units'] = 'esriSRUnit_Meter' - response = self.requests.get(url, params=params) + try: + response = self.requests.get(url, params=params) + except requests.RequestException as e: + raise ArcGISError('ArcGIS request error %s' % e) # errors - if response.status_code // 100 != 2: - raise ArcGISError('ArcGIS returned status code %s' % response.status_code) try: infos = response.json() except (ValueError,): diff --git a/passerelle/apps/arpege_ecp/models.py b/passerelle/apps/arpege_ecp/models.py index 31c216e..556458d 100644 --- a/passerelle/apps/arpege_ecp/models.py +++ b/passerelle/apps/arpege_ecp/models.py @@ -17,6 +17,8 @@ import json import urlparse +import requests + from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.dateparse import parse_date, parse_time @@ -47,10 +49,11 @@ class ArpegeECP(BaseResource): def get_access_token(self, NameID): url = urlparse.urljoin(self.webservice_base_url, 'LoginParSubOIDC') - response = self.requests.post(url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key), - json={'subOIDC': NameID}) - if response.status_code // 100 != 2: - raise APIError(u'HTTP error: %s' % response.status_code) + try: + response = self.requests.post(url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key), + json={'subOIDC': NameID}) + except requests.RequestException as e: + raise APIError(u'Request error: %s' % e) try: result = response.json() except ValueError: @@ -69,10 +72,11 @@ class ArpegeECP(BaseResource): url = urlparse.urljoin(self.webservice_base_url, 'DemandesUsager') params = {'scope': 'data_administratives'} auth = HawkAuth(self.hawk_auth_id, self.hawk_auth_key, ext=access_token) - response = self.requests.get(url, params=params, auth=auth) + try: + response = self.requests.get(url, params=params, auth=auth) + except requests.RequestException as e: + raise APIError(u'Request error: %s' % e) data = [] - if response.status_code // 100 != 2: - raise APIError(u'HTTP error: %s' % response.status_code) try: result = response.json() except ValueError: diff --git a/passerelle/apps/base_adresse/models.py b/passerelle/apps/base_adresse/models.py index c32b536..fe44f68 100644 --- a/passerelle/apps/base_adresse/models.py +++ b/passerelle/apps/base_adresse/models.py @@ -5,6 +5,7 @@ import urlparse import unicodedata import six +import requests from django.db import connection, models from django.db.models import Q @@ -161,10 +162,13 @@ class BaseAdresse(BaseResource): departments.add(zipcode[:2]) for department in departments: - ban_file = self.requests.get( - 'http://bano.openstreetmap.fr/BAN_odbl/BAN_odbl_{}-json.bz2'.format(department)) - if ban_file.status_code != 200: + try: + ban_file = self.requests.get( + 'http://bano.openstreetmap.fr/BAN_odbl/BAN_odbl_{}-json.bz2'.format(department)) + except requests.HTTPError: continue + except requests.RequestException: + raise for line in bz2.decompress(ban_file.content).splitlines(): street_info = json.loads(line) diff --git a/passerelle/apps/bdp/models.py b/passerelle/apps/bdp/models.py index 4aa467e..1dd9529 100644 --- a/passerelle/apps/bdp/models.py +++ b/passerelle/apps/bdp/models.py @@ -32,24 +32,25 @@ class Bdp(BaseResource): options = {} if self.keystore: options['cert'] = (self.keystore.path, self.keystore.path) - if not self.verify_cert: - options['verify'] = False + options['verify'] = self.verify_cert if self.username: options['auth'] = HTTPBasicAuth(self.username, self.password) return options def get_api(self, endpoint, **params): options = self.requests_options() - return requests.get(self.service_url + '/api/' + endpoint, - params=params, **options).json() + return self.requests.get(self.service_url + '/api/' + endpoint, params=params, **options).json() def post_api(self, endpoint, obj): data = json.dumps(obj) headers = {'Content-Type': 'application/json'} options = self.requests_options() - request = requests.post( + request = self.requests.post( self.service_url + '/api/' + endpoint, - data=data, headers=headers, **options) + data=data, headers=headers, + raise_for_status=False, + raise_for_redirect=False, + **options) result = { 'status_code': request.status_code, 'x_request_id': request.headers.get('x-request-id'), diff --git a/passerelle/apps/okina/models.py b/passerelle/apps/okina/models.py index afdef6f..3dee14c 100644 --- a/passerelle/apps/okina/models.py +++ b/passerelle/apps/okina/models.py @@ -16,6 +16,8 @@ import json +import requests + from django.db import models from django.http import HttpResponse from django.utils.translation import ugettext_lazy as _ @@ -42,14 +44,17 @@ class Okina(BaseResource): headers = {} if result_is_json: headers['Accept'] = 'application/json' - if payload is None: - result = self.requests.get(url, auth=auth, headers=headers) - else: - headers['Content-Type'] = 'application/json' - data = json.dumps(payload) - result = self.requests.post(url, data=data, auth=auth, headers=headers) - if result.status_code in (401, 403): - raise APIError(result.json()['message'], http_status=500) + try: + if payload is None: + result = self.requests.get(url, auth=auth, headers=headers) + else: + headers['Content-Type'] = 'application/json' + data = json.dumps(payload) + result = self.requests.post(url, data=data, auth=auth, headers=headers) + except requests.HTTPError as e: + if e.response.status_code in (401, 403): + raise APIError(e.response.json()['message'], http_status=500) + result = e.response if result_is_json: return result.json() else: diff --git a/passerelle/apps/opengis/models.py b/passerelle/apps/opengis/models.py index a930398..616148d 100644 --- a/passerelle/apps/opengis/models.py +++ b/passerelle/apps/opengis/models.py @@ -19,6 +19,7 @@ import xml.etree.ElementTree as ET from HTMLParser import HTMLParser import six +import requests import pyproj @@ -302,9 +303,10 @@ class OpenGIS(BaseResource): 'OUTPUTFORMAT': 'json', 'CQL_FILTER': cql_filter } - response = self.requests.get(self.wfs_service_url, params=params) - if not response.ok: - raise APIError('Webservice returned status code %s' % response.status_code) + try: + response = self.requests.get(self.wfs_service_url, params=params) + except requests.HTTPError as e: + raise APIError('Webservice returned status code %s' % e.response.status_code) closest_feature = {} min_delta = None for feature in response.json().get('features'): diff --git a/passerelle/apps/solis/models.py b/passerelle/apps/solis/models.py index d2486cc..ba90e05 100644 --- a/passerelle/apps/solis/models.py +++ b/passerelle/apps/solis/models.py @@ -19,6 +19,8 @@ import json import re import unicodedata +import requests + from django.db import models from django.template.loader import get_template from django.utils.translation import ugettext_lazy as _ @@ -105,21 +107,21 @@ class Solis(BaseResource): def request(self, endpoint, data=None, files=None): url = self.service_url + endpoint headers = {'Accept': 'application/json'} - if data is not None: - response = self.requests.post(url, json=data, headers=headers) - elif files is not None: - response = self.requests.post(url, files=files, headers=headers) - else: - response = self.requests.get(url, headers=headers) - - if response.status_code // 100 != 2: + try: + if data is not None: + response = self.requests.post(url, json=data, headers=headers) + elif files is not None: + response = self.requests.post(url, files=files, headers=headers) + else: + response = self.requests.get(url, headers=headers) + except requests.HTTPError as e: try: - json_content = response.json() + json_content = e.response.json() except ValueError: json_content = None raise APIError('error status:%s %r, content:%r' % - (response.status_code, response.reason, response.content[:1024]), - data={'status_code': response.status_code, + (e.response.status_code, e.response.reason, e.response.content[:1024]), + data={'status_code': e.response.status_code, 'json_content': json_content}) if response.status_code == 204: # 204 No Content diff --git a/passerelle/apps/vivaticket/models.py b/passerelle/apps/vivaticket/models.py index 462417d..e70e4ec 100644 --- a/passerelle/apps/vivaticket/models.py +++ b/passerelle/apps/vivaticket/models.py @@ -17,6 +17,8 @@ import hashlib import urlparse +import requests + from django.core.cache import cache from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -86,8 +88,7 @@ class VivaTicket(BaseResource): return cls._meta.verbose_name def check_status(self): - response = self.requests.get(urlparse.urljoin(self.url, 'Settings/GetVersion')) - response.raise_for_status() + self.requests.get(urlparse.urljoin(self.url, 'Settings/GetVersion')) def get_apikey(self, renew=False): cache_key_name = 'vivaticket-%s-key' % self.id @@ -95,9 +96,10 @@ class VivaTicket(BaseResource): return cache.get(cache_key_name) url = urlparse.urljoin(self.url, 'Connect/PostConnect') payload = {'Login': self.login, 'Password': self.password} - response = self.requests.post(url, json=payload) - if not response.ok: - raise APIError(response.content) + try: + response = self.requests.post(url, json=payload) + except requests.HTTPError as e: + raise APIError(e.response.content) api_key = response.json()['Key'] # api key is available for 30 minutes cache.set(cache_key_name, api_key, 60 * 30) @@ -107,23 +109,26 @@ class VivaTicket(BaseResource): url = urlparse.urljoin(self.url, endpoint) params = {'key': self.get_apikey()} params.update(kwargs) - response = self.requests.get(url, params=params) - # api key is expired - if response.status_code == 401: - params['key'] = self.get_apikey(True) - else: - return response - return self.requests.get(url, params=params) + try: + return self.requests.get(url, params=params) + except requests.HTTPError as e: + # api key is expired + if e.response.status_code == 401: + params['key'] = self.get_apikey(True) + return self.requests.get(url, params=params) + return e.response def post(self, endpoint, payload): url = urlparse.urljoin(self.url, endpoint) payload.update({'Key': self.get_apikey()}) - response = self.requests.post(url, json=payload) - # api key is expired - if response.status_code == 401: - payload['key'] = self.get_apikey(True) + try: return self.requests.post(url, json=payload) - return response + except requests.HTTPError as e: + # api key is expired + if e.response.status_code == 401: + payload['key'] = self.get_apikey(True) + return self.requests.post(url, json=payload) + raise def get_setting(self, endpoint, **kwargs): response = self.get(endpoint, **kwargs) diff --git a/passerelle/contrib/gdema/models.py b/passerelle/contrib/gdema/models.py index 983c0fd..6dd48c5 100644 --- a/passerelle/contrib/gdema/models.py +++ b/passerelle/contrib/gdema/models.py @@ -18,6 +18,8 @@ import datetime import json import re +import requests + from django.db import models from django.utils.timezone import get_fixed_timezone, utc, is_naive, make_aware from django.utils.dateparse import parse_date, parse_datetime @@ -162,14 +164,15 @@ class Gdema(BaseResource): auth = None headers = {} headers['Accept'] = 'application/json' - if payload is None: - result = self.requests.get(url, auth=auth, headers=headers) - else: - headers['Content-Type'] = 'application/json' - data = json.dumps(payload) - result = self.requests.post(url, data=data, auth=auth, headers=headers) - if result.status_code < 200 or result.status_code >= 300: - raise APIError('GDEMA returns HTTP status %s' % result.status_code) + try: + if payload is None: + result = self.requests.get(url, auth=auth, headers=headers) + else: + headers['Content-Type'] = 'application/json' + data = json.dumps(payload) + result = self.requests.post(url, data=data, auth=auth, headers=headers) + except requests.RequestException as e: + raise APIError('GDEMA request failed %s' % e) return result.json() def get_services(self): diff --git a/passerelle/contrib/greco/models.py b/passerelle/contrib/greco/models.py index 5e040c5..5d45338 100644 --- a/passerelle/contrib/greco/models.py +++ b/passerelle/contrib/greco/models.py @@ -23,6 +23,8 @@ from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText +import requests + from suds.client import Client from suds.transport import Reply from suds.transport.http import HttpAuthenticated @@ -155,7 +157,9 @@ class Greco(BaseResource): request.headers['Authorization'] = self.instance.get_token() resp = self.instance.requests.post(request.url, data=request.message, headers=request.headers, - verify=self.instance.verify_cert) + verify=self.instance.verify_cert, + raise_for_status=False, + raise_for_redirect=False) if resp.status_code == 401: # ask for a new token, and retry request.headers['Authorization'] = self.instance.get_token(renew=True) diff --git a/passerelle/contrib/mdph13/models.py b/passerelle/contrib/mdph13/models.py index 88f5051..199bfa9 100644 --- a/passerelle/contrib/mdph13/models.py +++ b/passerelle/contrib/mdph13/models.py @@ -46,11 +46,10 @@ class MDPH13Resource(BaseResource, HTTPResource): def url_get(self, *args, **kwargs): try: - response = None response = self.requests.get(*args, **kwargs) - response.raise_for_status() except requests.RequestException as e: data = {'exception': six.text_type(e)} + response = getattr(e, 'response', None) if response is not None: try: if response.json(): diff --git a/passerelle/contrib/planitech/models.py b/passerelle/contrib/planitech/models.py index 2114bfa..249087e 100644 --- a/passerelle/contrib/planitech/models.py +++ b/passerelle/contrib/planitech/models.py @@ -21,13 +21,14 @@ import re import urlparse import uuid +import requests + from django.core.cache import cache from django.db import models, transaction from django.utils import dateformat from django.utils import dateparse from django.utils.translation import ugettext_lazy as _ from jsonfield import JSONField -from requests.exceptions import RequestException from passerelle.base.models import BaseResource from passerelle.contrib.planitech import mste @@ -208,17 +209,19 @@ class PlanitechConnector(BaseResource): kwargs = {} if params is not None: kwargs['data'] = json.dumps(mste.encode(params)) - response = session_meth(urlparse.urljoin(self.url, endpoint), **kwargs) - if response.status_code != 200: - error_msg = "Planitech error %s" % response.status_code + try: + response = session_meth(urlparse.urljoin(self.url, endpoint), **kwargs) + except requests.HTTPError as e: + error_msg = "Planitech error %s" % e.response.status_code try: - data = mste.decode(response.json()) + data = mste.decode(e.response.json()) + except TypeError: + pass + else: if hasattr(data, 'get'): error = data.get('errors') if error: error_msg += " - %s" % error - except TypeError: - pass raise APIError(error_msg) return mste.decode(response.json()) @@ -317,10 +320,9 @@ class PlanitechConnector(BaseResource): tmp_hash = compute_hash(self.password, hardness1, salt1) hash_pass = compute_hash(tmp_hash, hardness2, salt2) response = self.requests.get(auth_url, headers={'MH-PASSWORD': hash_pass}) - response.raise_for_status() # the last response should have set a cookie which will be used for authentication - except RequestException as e: - raise APIError("Authentication to Planitech failed: %s" % str(e)) + except requests.RequestException as e: + raise APIError("Authentication to Planitech failed: %s" % e) @endpoint( perm='can_access', diff --git a/passerelle/contrib/solis_apa/models.py b/passerelle/contrib/solis_apa/models.py index ad0fe59..63ca531 100644 --- a/passerelle/contrib/solis_apa/models.py +++ b/passerelle/contrib/solis_apa/models.py @@ -18,6 +18,8 @@ import re import json import urlparse +import requests + from django.db import models from django.core.cache import cache from django.core.urlresolvers import reverse @@ -100,9 +102,10 @@ class SolisAPA(BaseResource): } data = json.dumps(data) - response = self.requests.post(url, data=data, headers=HEADERS) - if response.status_code != 200: - raise ValueError('referential ws: error code %d' % response.status_code) + try: + response = self.requests.post(url, data=data, headers=HEADERS) + except requests.RequestException as e: + raise ValueError('referential request failed %s' % e) ret = self._check_requests_response(response) @@ -123,9 +126,10 @@ class SolisAPA(BaseResource): url = self.get_resource_url(uri) name = config['block']['name'].lower() data = json.dumps(conciliation.conciliation_payload(config, **data)) - response = self.requests.post(url, data=data, headers=HEADERS) - if response.status_code != 200: - raise ValueError('conciliation ws: error code %d' % response.status_code) + try: + response = self.requests.post(url, data=data, headers=HEADERS) + except requests.RequestException as e: + raise ValueError('conciliation ws failed: %s' % e) ret = self._check_requests_response(response) @@ -299,9 +303,10 @@ class SolisAPA(BaseResource): payload = suivi.render_payload(suivi_type, datedebut, datefin) payload = json.dumps(payload) - response = self.requests.post(url, data=payload, headers=HEADERS, timeout=300) - if response.status_code != 200: - raise ValueError('suivi %s ws: error code %d' %(suivi_type, response.status_code)) + try: + response = self.requests.post(url, data=payload, headers=HEADERS, timeout=300) + except requests.RequestException as e: + raise ValueError('suivi %s ws: error code %e' % (suivi_type, e)) response = self._check_requests_response(response) @@ -315,9 +320,10 @@ class SolisAPA(BaseResource): data = {'ImportInputWSDemandeApa': integration.build_message(json.loads(data))} data = json.dumps(data) self.logger.debug('Demande APA: %s' % data, extra={'solis_apa_demande': data}) - response = self.requests.post(url, data=data, headers=HEADERS) - if response.status_code != 200: - raise ValueError('integration ws: error code %d' %(response.status_code)) + try: + response = self.requests.post(url, data=data, headers=HEADERS) + except requests.RequestException as e: + raise ValueError('integration ws: error code %s' % e) response = self._check_requests_response(response) diff --git a/passerelle/contrib/teamnet_axel/soap.py b/passerelle/contrib/teamnet_axel/soap.py index 44b0ef1..4274d5b 100644 --- a/passerelle/contrib/teamnet_axel/soap.py +++ b/passerelle/contrib/teamnet_axel/soap.py @@ -53,7 +53,10 @@ class Transport(HttpAuthenticated): self.addcredentials(request) resp = self.model.requests.post( request.url, data=request.message, - headers=request.headers, **self.get_requests_kwargs()) + headers=request.headers, + raise_for_status=False, + raise_for_redirect=False, + **self.get_requests_kwargs()) result = Reply(resp.status_code, resp.headers, resp.content) return result diff --git a/passerelle/soap.py b/passerelle/soap.py index c47cccd..f1f1a30 100644 --- a/passerelle/soap.py +++ b/passerelle/soap.py @@ -44,6 +44,7 @@ class Transport(HttpAuthenticated): def send(self, request): resp = requests.post(request.url, data=request.message, headers=request.headers, + raise_for_status=False, raise_for_redirect=False, **self.get_requests_kwargs(request)) return Reply(resp.status_code, resp.headers, resp.content) diff --git a/tests/conftest.py b/tests/conftest.py index 75fe8e8..d18a8f6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,14 @@ +from io import BytesIO +import json as json_module +import base64 +from django.utils.six.moves.urllib import parse as urlparse + import pytest from httmock import urlmatch, HTTMock, response import django_webtest + from django.core.files import File from django.core.cache import cache from io import BytesIO @@ -170,3 +176,97 @@ CipherString = ALL''') del os.environ['OPENSSL_CONF'] else: os.environ['OPENSSL_CONF'] = old_value + + +@pytest.fixture +def fake_http(): + class MockHttp(object): + def __init__(self): + self.requests = [] + self.responses = [] + + def reset(self): + assert len(self.responses) == len(self.requests), 'all responses have not been consumed' + self.requests = [] + self.responses = [] + + def set_response(self, *args, **kwargs): + self.reset() + self.add_response(*args, **kwargs) + + def add_response(self, status_code=200, reason=None, content=None, + json=None, headers=None, method=None, url=None): + response = {'status_code': status_code} + if not content and json: + content = json_module.dumps(json) + headers = headers or {} + for key in headers: + if key.lower() == 'content-type': + break + else: + headers['content-type'] = 'application/json' + if reason: + response['reason'] = reason + if content: + response['content'] = content + if headers: + response['headers'] = headers + if method: + response['request_method'] = method + if url: + response['request_url'] = url + self.responses.append(response) + + @property + def last_request(self): + return self.requests[-1] + + def request_handler(self, url, request): + from django.http.request import QueryDict + from django.http.multipartparser import MultiPartParser + from django.core.files.uploadhandler import TemporaryFileUploadHandler + + idx = len(self.requests) + + url_parsed = urlparse.urlparse(request.url) + request.path = url_parsed.path + request.GET = QueryDict(query_string=url_parsed.query) + + if ('content-type' in request.headers + and request.headers['content-type'].split(';')[0] == 'application/json'): + request.json = json_module.loads(request.body) + else: + request.json = None + + if ('content-type' in request.headers + and request.headers['content-type'].split(';')[0] == 'multipart/form-data'): + data = BytesIO(request.body) + META = {'CONTENT_TYPE': request.headers['content-type'], 'CONTENT_LENGTH': request.headers['content-length']} + request.POST, request.FILES = MultiPartParser(META, data, [TemporaryFileUploadHandler()]).parse() + else: + request.POST = QueryDict() + request.FILES = QueryDict() + + if ('authorization' in request.headers + and request.headers['authorization'].split()[0] == 'Basic'): + header = request.headers['authorization'] + request.basic_auth = base64.b64decode(header.split()[1]).split(':') + self.requests.append(request) + assert idx < len(self.responses), ('unexpected request', request) + response = self.responses[idx] + + if 'request_method' in response: + assert request.method == response['request_method'] + + if 'request_url' in response: + if hasattr(response['request_url'], 'match'): + assert response['request_url'].match(request.url) + else: + assert response['request_url'] == request.url + + return response + + mock_http = MockHttp() + with HTTMock(urlmatch()(mock_http.request_handler)): + yield mock_http + assert len(mock_http.responses) == len(mock_http.requests), 'all responses have not been consumed' diff --git a/tests/test_api_particulier.py b/tests/test_api_particulier.py index ba13c70..d714791 100644 --- a/tests/test_api_particulier.py +++ b/tests/test_api_particulier.py @@ -195,7 +195,7 @@ def test_error(app, resource, mock_api_particulier): params=params) assert resp.status_code == 200 assert resp.json['err'] == 1 - assert resp.json['data']['status_code'] == 500 + assert '500 Server Error' in resp.json['err_desc'] vector = [ (['impots_svair', 'impots_adresse'], { 'numero_fiscal': 12, diff --git a/tests/test_arpege_ecp.py b/tests/test_arpege_ecp.py index dd896a7..cca2f6f 100644 --- a/tests/test_arpege_ecp.py +++ b/tests/test_arpege_ecp.py @@ -60,66 +60,66 @@ FAKE_USER_DEMANDS_RESPONSE = """{ } }""" + @pytest.fixture def connector(db): - resource = ArpegeECP.objects.create(slug='test', - webservice_base_url = 'http://arpege.net', - hawk_auth_id = 'id', hawk_auth_key = 'secret') + resource = ArpegeECP.objects.create( + slug='test', + webservice_base_url='http://arpege.net', + hawk_auth_id='id', + hawk_auth_key='secret') return utils.setup_access_rights(resource) -@mock.patch('passerelle.utils.Request.get') -def test_check_status(mocked_get, connector): - mocked_get.return_value = utils.FakedResponse(content=FAKE_HELLO_RESPONSE, status_code=200) + +def test_check_status_ok(fake_http, connector): + fake_http.add_response(200, content=FAKE_HELLO_RESPONSE) resp = connector.check_status() assert resp['data'] == u'InteropAPI v1 (c) Arpège 2017' -@mock.patch('passerelle.utils.Request.get') -def test_check_status(mocked_get, connector): + +def test_check_status_nok(fake_http, connector): hello_response = json.loads(FAKE_HELLO_RESPONSE) del hello_response['Data'] - mocked_get.return_value = utils.FakedResponse(content=json.dumps(hello_response), status_code=200) + fake_http.add_response(200, content=json.dumps(hello_response)) with pytest.raises(Exception) as error: - resp = connector.check_status() + connector.check_status() assert str(error.value) == 'Invalid credentials' -@mock.patch('passerelle.utils.Request.post') -def test_get_access_token(mocked_post, connector): - mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200) + +def test_get_access_token(fake_http, connector): + fake_http.add_response(200, content=FAKE_LOGIN_OIDC_RESPONSE) token = connector.get_access_token('nameid') assert token == '0f86353f2d87b8b78aaaacc2ecc763e287ded44f773289a5e336546a251718b3' - mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=404) + fake_http.add_response(404, content=FAKE_LOGIN_OIDC_RESPONSE) with pytest.raises(APIError) as error: token = connector.get_access_token('nameid') - assert str(error.value) == 'HTTP error: 404' + assert '404' in str(error.value) - mocked_post.return_value = utils.FakedResponse(content="content", status_code=200) + fake_http.add_response(200, content="content") with pytest.raises(APIError) as error: token = connector.get_access_token('nameid') assert str(error.value) == 'No JSON content returned: \'content\'' - mocked_post.return_value = utils.FakedResponse(content="content", status_code=200) + fake_http.add_response(200, content="content") with pytest.raises(APIError) as error: token = connector.get_access_token('nameid') assert str(error.value) == 'No JSON content returned: \'content\'' - mocked_post.return_value = utils.FakedResponse(content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Auth FAIL"}', - status_code=200) + fake_http.add_response(200, content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Auth FAIL"}') with pytest.raises(APIError) as error: token = connector.get_access_token('nameid') assert str(error.value) == 'Auth FAIL (Fail)' -@mock.patch('passerelle.utils.Request.get') -@mock.patch('passerelle.utils.Request.post') -def test_get_user_forms(mocked_post, mocked_get, app, connector): +def test_get_user_forms(fake_http, app, connector): endpoint = reverse('generic-endpoint', kwargs={ 'connector': 'arpege-ecp', 'slug': connector.slug, 'endpoint': 'api', 'rest': 'users/nameid/forms'}) assert endpoint == '/arpege-ecp/test/api/users/nameid/forms' - mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200) - mocked_get.return_value = utils.FakedResponse(content=FAKE_USER_DEMANDS_RESPONSE, status_code=200) + fake_http.add_response(200, content=FAKE_LOGIN_OIDC_RESPONSE) + fake_http.add_response(200, content=FAKE_USER_DEMANDS_RESPONSE) resp = app.get(endpoint) result = resp.json assert resp.json['data'] @@ -134,33 +134,29 @@ def test_get_user_forms(mocked_post, mocked_get, app, connector): assert item['form_status_is_endpoint'] == False -@mock.patch('passerelle.utils.Request.get') -@mock.patch('passerelle.utils.Request.post') -def test_get_user_forms_failure(mocked_post, mocked_get, app, connector): +def test_get_user_forms_failure(fake_http, app, connector): endpoint = reverse('generic-endpoint', kwargs={ 'connector': 'arpege-ecp', 'slug': connector.slug, 'endpoint': 'api', 'rest': 'users/nameid/forms'}) - mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200) - mocked_get.return_value = utils.FakedResponse(content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Failed to get demands"}', - status_code=200) + fake_http.add_response(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200) + fake_http.add_response(content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Failed to get demands"}', + status_code=200) resp = app.get(endpoint) result = resp.json assert result['err'] == 1 assert result['err_desc'] == 'Failed to get demands (Fail)' -@mock.patch('passerelle.utils.Request.get') -@mock.patch('passerelle.utils.Request.post') -def test_get_user_forms_failure_404(mocked_post, mocked_get, app, connector): +def test_get_user_forms_failure_404(fake_http, app, connector): endpoint = reverse('generic-endpoint', kwargs={ 'connector': 'arpege-ecp', 'slug': connector.slug, 'endpoint': 'api', 'rest': 'users/nameid/forms'}) - mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200) - mocked_get.return_value = utils.FakedResponse(content=FAKE_USER_DEMANDS_RESPONSE, status_code=404) + fake_http.add_response(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200) + fake_http.add_response(content=FAKE_USER_DEMANDS_RESPONSE, status_code=404) resp = app.get(endpoint) result = resp.json assert result['err'] == 1 - assert result['err_desc'] == 'HTTP error: 404' + assert '404 Client Error' in result['err_desc'] @mock.patch('passerelle.utils.Request.get') diff --git a/tests/test_gdema.py b/tests/test_gdema.py index fba3820..97b915e 100644 --- a/tests/test_gdema.py +++ b/tests/test_gdema.py @@ -75,111 +75,94 @@ def gdema(db): return gdema -def test_gdema_services_and_typologies(app, gdema): +def test_gdema_services_and_typologies(fake_http, app, gdema): endpoint = utils.generic_endpoint_url('gdema', 'referentiel', slug=gdema.slug) assert endpoint == '/gdema/test/referentiel' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=SERVICES, - status_code=200) - resp = app.get(endpoint + '/service/', status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/referentiel/service' - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 3 - assert resp.json['data'][0]['id'] == '16151' - assert resp.json['data'][0]['text'] == u'DMT - Mobilité et transports' - - resp = app.get(endpoint + '/typology/', status=200) - assert requests_get.call_count == 2 - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 12 - assert resp.json['data'][0]['id'] == '13067' - assert resp.json['data'][0]['text'] == u'Maintenance Cie' - assert resp.json['data'][0]['service_id'] == '10173' - assert resp.json['data'][0]['service_text'] == u'DESPU - Administration Direction environnement et services publics urbains' - - resp = app.get(endpoint + '/typology/?service_id=10426', status=200) - assert requests_get.call_count == 3 - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 7 - assert resp.json['data'][0]['id'] == '10804' - assert resp.json['data'][0]['text'] == u'Activités périscolaires' - assert resp.json['data'][0]['service_id'] == '10426' - assert resp.json['data'][0]['service_text'] == u'DEE - Périscolaire et éducatif' - - -def test_gdema_referentiel(app, gdema): + fake_http.add_response(content=SERVICES, status_code=200) + resp = app.get(endpoint + '/service/', status=200) + assert fake_http.last_request.url == 'https://gdema.example.net/api/referentiel/service' + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 3 + assert resp.json['data'][0]['id'] == '16151' + assert resp.json['data'][0]['text'] == u'DMT - Mobilité et transports' + + fake_http.add_response(content=SERVICES, status_code=200) + resp = app.get(endpoint + '/typology/', status=200) + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 12 + assert resp.json['data'][0]['id'] == '13067' + assert resp.json['data'][0]['text'] == u'Maintenance Cie' + assert resp.json['data'][0]['service_id'] == '10173' + assert resp.json['data'][0]['service_text'] == u'DESPU - Administration Direction environnement et services publics urbains' + + fake_http.add_response(content=SERVICES, status_code=200) + resp = app.get(endpoint + '/typology/?service_id=10426', status=200) + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 7 + assert resp.json['data'][0]['id'] == '10804' + assert resp.json['data'][0]['text'] == u'Activités périscolaires' + assert resp.json['data'][0]['service_id'] == '10426' + assert resp.json['data'][0]['service_text'] == u'DEE - Périscolaire et éducatif' + + +def test_gdema_referentiel(fake_http, app, gdema): endpoint = utils.generic_endpoint_url('gdema', 'referentiel', slug=gdema.slug) assert endpoint == '/gdema/test/referentiel' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=CIVILITY, - status_code=200) - resp = app.get(endpoint + '/civility/', status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/referentiel/civility' - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 3 - assert resp.json['data'][0]['id'] == '1' - assert resp.json['data'][0]['text'] == 'Monsieur' - - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content='404', status_code=404) - resp = app.get(endpoint + '/nothing/', status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/referentiel/nothing' - assert 'data' in resp.json - assert resp.json['err'] == 1 - assert resp.json['data'] is None - assert resp.json['err_class'].endswith('.APIError') - assert '404' in resp.json['err_desc'] - - -def test_gdema_get_request(app, gdema): + fake_http.add_response(content=CIVILITY, status_code=200) + resp = app.get(endpoint + '/civility/', status=200) + assert fake_http.last_request.url == 'https://gdema.example.net/api/referentiel/civility' + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 3 + assert resp.json['data'][0]['id'] == '1' + assert resp.json['data'][0]['text'] == 'Monsieur' + + fake_http.add_response(content='404', status_code=404) + resp = app.get(endpoint + '/nothing/', status=200) + assert fake_http.last_request.url == 'https://gdema.example.net/api/referentiel/nothing' + assert 'data' in resp.json + assert resp.json['err'] == 1 + assert resp.json['data'] is None + assert resp.json['err_class'].endswith('.APIError') + assert '404' in resp.json['err_desc'] + + +def test_gdema_get_request(fake_http, app, gdema): endpoint = utils.generic_endpoint_url('gdema', 'get-request', slug=gdema.slug) assert endpoint == '/gdema/test/get-request' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=REQUEST, - status_code=200) - resp = app.get(endpoint + '/1/', status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/request/1' - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert resp.json['data']['Id'] == '1' - assert resp.json['data']['AnswerToProvide'] is True - assert resp.json['data']['Description'].startswith(u'contrôle') - assert resp.json['data']['ExpectedDate'] is None - assert resp.json['data']['Files'] == [] - assert resp.json['data']['Handler']['CivilityId'] == '0' - assert resp.json['data']['ReceptDate'] == '2006-12-13T00:00:00+01:00' + fake_http.add_response(content=REQUEST, status_code=200) + resp = app.get(endpoint + '/1/', status=200) + assert fake_http.last_request.url == 'https://gdema.example.net/api/request/1' + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert resp.json['data']['Id'] == '1' + assert resp.json['data']['AnswerToProvide'] is True + assert resp.json['data']['Description'].startswith(u'contrôle') + assert resp.json['data']['ExpectedDate'] is None + assert resp.json['data']['Files'] == [] + assert resp.json['data']['Handler']['CivilityId'] == '0' + assert resp.json['data']['ReceptDate'] == '2006-12-13T00:00:00+01:00' endpoint = utils.generic_endpoint_url('gdema', 'get-request-state', slug=gdema.slug) assert endpoint == '/gdema/test/get-request-state' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=REQUEST_STATE, - status_code=200) - resp = app.get(endpoint + '/1/', status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/request/1/state' - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert resp.json['data'] == {'Id': '1', 'State': '64', 'StateLabel': u'Cloturée'} - - -def test_gdema_create_request(app, gdema): + fake_http.add_response(content=REQUEST_STATE, status_code=200) + resp = app.get(endpoint + '/1/', status=200) + assert fake_http.last_request.url == 'https://gdema.example.net/api/request/1/state' + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert resp.json['data'] == {'Id': '1', 'State': '64', 'StateLabel': u'Cloturée'} + + +def test_gdema_create_request(fake_http, app, gdema): endpoint = utils.generic_endpoint_url('gdema', 'create-request', slug=gdema.slug) assert endpoint == '/gdema/test/create-request' - with mock.patch('passerelle.utils.Request.post') as requests_post: - requests_post.return_value = utils.FakedResponse(content=REQUEST, - status_code=200) - resp = app.post_json(endpoint + '?raise=1', params=CREATE_INPUT, status=200) - assert requests_post.call_count == 1 - assert requests_post.call_args[0][0] == 'https://gdema.example.net/api/request/create' - assert json.loads(requests_post.call_args[1]['data']) == CONVERTED_INPUT - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert resp.json['data']['Id'] == '1' + fake_http.add_response(content=REQUEST, status_code=200) + resp = app.post_json(endpoint + '?raise=1', params=CREATE_INPUT, status=200) + assert fake_http.last_request.url == 'https://gdema.example.net/api/request/create' + assert fake_http.last_request.json == CONVERTED_INPUT + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert resp.json['data']['Id'] == '1' diff --git a/tests/test_generic_endpoint.py b/tests/test_generic_endpoint.py index 9e07033..d3b19fa 100644 --- a/tests/test_generic_endpoint.py +++ b/tests/test_generic_endpoint.py @@ -309,7 +309,9 @@ def test_endpoint_cookies(app, db, monkeypatch, httpbin): @endpoint(methods=['get']) def httpcall(obj, request): - response = obj.requests.get(httpbin.url + '/cookies/set?foo=bar', allow_redirects=False) + response = obj.requests.get(httpbin.url + '/cookies/set?foo=bar', + raise_for_redirect=False, + allow_redirects=False) cookie1 = response.request.headers.get('Cookie') response = obj.requests.get(httpbin.url + '/get') cookie2 = response.request.headers.get('Cookie') @@ -339,8 +341,8 @@ def test_https_warnings(app, db, monkeypatch, httpbin_secure, relax_openssl): resource = utils.make_resource(Maarch, wsdl_url='https://example.com/', slug='slug', verify_cert=True) with pytest.raises(SSLError): - resource.requests.get(httpbin_secure.join('/get/')) + resource.requests.get(httpbin_secure.join('/get')) resource.verify_cert = False with warnings.catch_warnings(): warnings.simplefilter('error') - resource.requests.get(httpbin_secure.join('/get/')) + resource.requests.get(httpbin_secure.join('/get')) diff --git a/tests/test_okina.py b/tests/test_okina.py index 6faf924..142be12 100644 --- a/tests/test_okina.py +++ b/tests/test_okina.py @@ -1339,200 +1339,192 @@ def okina(db): password='userpass') -def test_okina_cities(app, okina): +def test_okina_cities(fake_http, app, okina): endpoint = utils.generic_endpoint_url('okina', 'cities', slug=okina.slug) assert endpoint == '/okina/test/cities' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=CITIES, - status_code=200) - resp = app.get(endpoint, status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/cities' - assert requests_get.call_args[1]['auth'] == ('usertest', 'userpass') - assert 'data' in resp.json - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert resp.json['data'][0]['id'] == '83355' - assert resp.json['data'][0]['insee'] == '36005' - assert resp.json['data'][0]['text'] == 'ARDENTES (36120)' + fake_http.set_response(content=CITIES, status_code=200) + resp = app.get(endpoint, status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/cities' + assert fake_http.last_request.basic_auth == ['usertest', 'userpass'] + assert 'data' in resp.json + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert resp.json['data'][0]['id'] == '83355' + assert resp.json['data'][0]['insee'] == '36005' + assert resp.json['data'][0]['text'] == 'ARDENTES (36120)' + -def test_okina_classes(app, okina): +def test_okina_classes(fake_http, app, okina): endpoint = utils.generic_endpoint_url('okina', 'classes', slug=okina.slug) assert endpoint == '/okina/test/classes' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=CLASSES, - status_code=200) - resp = app.get(endpoint, status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/classes' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 4 - assert resp.json['data'][0]['id'] == '1' - assert resp.json['data'][0]['text'] == u'École maternelle - Petite section' + fake_http.set_response(content=CLASSES, status_code=200) + resp = app.get(endpoint, status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/classes' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 4 + assert resp.json['data'][0]['id'] == '1' + assert resp.json['data'][0]['text'] == u'École maternelle - Petite section' -def test_okina_institutions(app, okina): + +def test_okina_institutions(fake_http, app, okina): endpoint = utils.generic_endpoint_url('okina', 'institutions', slug=okina.slug) assert endpoint == '/okina/test/institutions' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=INSTITUTIONS, - status_code=200) - resp = app.get(endpoint, status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/institutions' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert resp.json['data'][0]['id'] == '277' - assert resp.json['data'][0]['text'] == u'Collège Touvent' + fake_http.set_response(content=INSTITUTIONS, status_code=200) + resp = app.get(endpoint, status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/institutions' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert resp.json['data'][0]['id'] == '277' + assert resp.json['data'][0]['text'] == u'Collège Touvent' - resp = app.get(endpoint + '/from-city/36005/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/institutions/subscriberCity/36005' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert resp.json['data'][0]['id'] == '277' - assert resp.json['data'][0]['text'] == u'Collège Touvent' + fake_http.set_response(content=INSTITUTIONS, status_code=200) + resp = app.get(endpoint + '/from-city/36005/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/institutions/subscriberCity/36005' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert resp.json['data'][0]['id'] == '277' + assert resp.json['data'][0]['text'] == u'Collège Touvent' -def test_okina_stops_area(app, okina): + +def test_okina_stops_area(fake_http, app, okina): endpoint = utils.generic_endpoint_url('okina', 'stop-areas', slug=okina.slug) assert endpoint == '/okina/test/stop-areas' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=STOPS, - status_code=200) - resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/stop-areas/subscriberCity/36005/institution/276' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 3 - assert resp.json['data'][0]['id'] == '3281' - assert resp.json['data'][0]['text'] == u'Les Loges de Dressais' + fake_http.set_response(content=STOPS, status_code=200) + resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/stop-areas/subscriberCity/36005/institution/276' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 3 + assert resp.json['data'][0]['id'] == '3281' + assert resp.json['data'][0]['text'] == u'Les Loges de Dressais' + -def test_okina_ods(app, okina): +def test_okina_ods(fake_http, app, okina): endpoint = utils.generic_endpoint_url('okina', 'origin-destinations', slug=okina.slug) assert endpoint == '/okina/test/origin-destinations' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=ODS, status_code=200) - resp = app.get(endpoint, status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' - assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' - assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' - assert resp.json['data'][0]['vehicle_journey_id'] == '84' + fake_http.set_response(content=ODS, status_code=200) + resp = app.get(endpoint, status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' + assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' + assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' + assert resp.json['data'][0]['vehicle_journey_id'] == '84' - requests_get.return_value = utils.FakedResponse(content=ODS, status_code=200) - resp = app.get(endpoint + '/to-institution/276/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/institution/276' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' - assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' - assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' - assert resp.json['data'][0]['vehicle_journey_id'] == '84' + fake_http.set_response(content=ODS, status_code=200) + resp = app.get(endpoint + '/to-institution/276/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/institution/276' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' + assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' + assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' + assert resp.json['data'][0]['vehicle_journey_id'] == '84' - requests_get.return_value = utils.FakedResponse(content=ODS_LINES, status_code=200) - resp = app.get(endpoint + '/from-stop-area/3282/to-institution/276/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/institution/276/stop-area/3282' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 3 - assert resp.json['data'][0]['id'] == '1' - assert resp.json['data'][0]['text'] == 'LIGNE 24' - assert len(resp.json['data'][0]['lines']) == 1 - assert resp.json['data'][0]['lines'][0]['id'] == '24' - assert resp.json['data'][0]['lines'][0]['text'] == 'LIGNE 24' - assert resp.json['data'][1]['id'] == '2' - assert resp.json['data'][1]['text'] == 'LIGNE 22' - assert len(resp.json['data'][1]['lines']) == 1 - assert resp.json['data'][1]['lines'][0]['id'] == '22' - assert resp.json['data'][1]['lines'][0]['text'] == 'LIGNE 22' - assert resp.json['data'][2]['id'] == '3' - assert resp.json['data'][2]['text'] == 'LIGNE 24 + LIGNE 23' - assert len(resp.json['data'][2]['lines']) == 2 - assert resp.json['data'][2]['lines'][0]['id'] == '24' - assert resp.json['data'][2]['lines'][0]['text'] == 'LIGNE 24' - assert resp.json['data'][2]['lines'][1]['id'] == '23' - assert resp.json['data'][2]['lines'][1]['text'] == 'LIGNE 23' + fake_http.set_response(content=ODS_LINES, status_code=200) + resp = app.get(endpoint + '/from-stop-area/3282/to-institution/276/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/institution/276/stop-area/3282' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 3 + assert resp.json['data'][0]['id'] == '1' + assert resp.json['data'][0]['text'] == 'LIGNE 24' + assert len(resp.json['data'][0]['lines']) == 1 + assert resp.json['data'][0]['lines'][0]['id'] == '24' + assert resp.json['data'][0]['lines'][0]['text'] == 'LIGNE 24' + assert resp.json['data'][1]['id'] == '2' + assert resp.json['data'][1]['text'] == 'LIGNE 22' + assert len(resp.json['data'][1]['lines']) == 1 + assert resp.json['data'][1]['lines'][0]['id'] == '22' + assert resp.json['data'][1]['lines'][0]['text'] == 'LIGNE 22' + assert resp.json['data'][2]['id'] == '3' + assert resp.json['data'][2]['text'] == 'LIGNE 24 + LIGNE 23' + assert len(resp.json['data'][2]['lines']) == 2 + assert resp.json['data'][2]['lines'][0]['id'] == '24' + assert resp.json['data'][2]['lines'][0]['text'] == 'LIGNE 24' + assert resp.json['data'][2]['lines'][1]['id'] == '23' + assert resp.json['data'][2]['lines'][1]['text'] == 'LIGNE 23' - requests_get.return_value = utils.FakedResponse(content=ODS_FULL, status_code=200) - resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/institution/276/subscriberCity/36005' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 1 - assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' - assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent' - assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' - assert resp.json['data'][0]['vehicle_journey_id'] == '84' + fake_http.set_response(content=ODS_FULL, status_code=200) + resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/institution/276/subscriberCity/36005' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 1 + assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' + assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent' + assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' + assert resp.json['data'][0]['vehicle_journey_id'] == '84' + + fake_http.set_response(content=ODS_FULL, status_code=200) + resp = app.get(endpoint + '/from-city/36005/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/subscriberCity/36005' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 1 + assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' + assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent' + assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' + assert resp.json['data'][0]['vehicle_journey_id'] == '84' - requests_get.return_value = utils.FakedResponse(content=ODS_FULL, status_code=200) - resp = app.get(endpoint + '/from-city/36005/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/subscriberCity/36005' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 1 - assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84' - assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent' - assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)' - assert resp.json['data'][0]['vehicle_journey_id'] == '84' -def test_okina_topology(app, okina): +def test_okina_topology(fake_http, app, okina): endpoint = utils.generic_endpoint_url('okina', 'topology', slug=okina.slug) assert endpoint == '/okina/test/topology' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=LINES, status_code=200) - resp = app.get(endpoint + '/lines/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/topology/lines' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 3 - assert resp.json['data'][0]['id'] == '45' - assert resp.json['data'][0]['text'] == '019 - 02 - VELLES LYCEES DE CHATEAUROUX' + fake_http.set_response(content=LINES, status_code=200) + resp = app.get(endpoint + '/lines/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/topology/lines' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 3 + assert resp.json['data'][0]['id'] == '45' + assert resp.json['data'][0]['text'] == '019 - 02 - VELLES LYCEES DE CHATEAUROUX' - requests_get.return_value = utils.FakedResponse(content=NETWORKS, status_code=200) - resp = app.get(endpoint + '/networks/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/topology/networks' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 1 - assert resp.json['data'][0]['id'] == '2' - assert resp.json['data'][0]['text'] == u'réseau scolaire' + fake_http.set_response(content=NETWORKS, status_code=200) + resp = app.get(endpoint + '/networks/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/topology/networks' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 1 + assert resp.json['data'][0]['id'] == '2' + assert resp.json['data'][0]['text'] == u'réseau scolaire' - requests_get.return_value = utils.FakedResponse(content=VEHICLE_JOURNEYS, status_code=200) - resp = app.get(endpoint + '/vehicle-journeys/', status=200) - assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/topology/vehicle-journeys' - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 3 - assert resp.json['data'][0]['id'] == '306' - assert resp.json['data'][0]['text'] == u'019 02 - VELLES LYCEES DE CHATEAUROUX' + fake_http.set_response(content=VEHICLE_JOURNEYS, status_code=200) + resp = app.get(endpoint + '/vehicle-journeys/', status=200) + assert fake_http.last_request.url == 'https://okina.example.net/b2b/topology/vehicle-journeys' + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 3 + assert resp.json['data'][0]['id'] == '306' + assert resp.json['data'][0]['text'] == u'019 02 - VELLES LYCEES DE CHATEAUROUX' -def test_okina_errors(app, okina): - with mock.patch('passerelle.utils.Request.get') as requests_get: - for response in ((200, '{"foo": "bar"}'), # not a list - (200, '{["foo": "bar"]}'), # list of malformatted dict - (200, '

Welcome

'), # bad json - (403, '

Bad creds

'), - (404, '

Not Found

'), - (500, '

Crash

'), - ): - requests_get.return_value = utils.FakedResponse(content=response[1], - status_code=response[0]) - resp = app.get('/okina/test/cities', status=500) - assert resp.json['err'] == 1 - assert resp.json['data'] == None - # "normal" 401/403 response, ie problem with login/password - for status_code in (401, 403): - requests_get.return_value = utils.FakedResponse(content='''{"message": "Invalid credentials", - "code": 4, "status" : %d}''' % status_code, status_code=status_code) - resp = app.get('/okina/test/cities', status=500) - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == "Invalid credentials" - assert resp.json['data'] is None +def test_okina_errors(fake_http, app, okina): + for status_code, content in ( + (200, '{"foo": "bar"}'), # not a list + (200, '{["foo": "bar"]}'), # list of malformatted dict + (200, '

Welcome

'), # bad json + (403, '

Bad creds

'), + (404, '

Not Found

'), + (500, '

Crash

')): + fake_http.set_response(status_code=status_code, content=content) + resp = app.get('/okina/test/cities', status=500) + assert resp.json['err'] == 1 + assert resp.json['data'] is None -def test_okina_suscribe(app, okina): + # "normal" 401/403 response, ie problem with login/password + for status_code in (401, 403): + fake_http.set_response(content='''{"message": "Invalid credentials", "code": 4, "status" : %d}''' % status_code, + status_code=status_code) + resp = app.get('/okina/test/cities', status=500) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == "Invalid credentials" + assert resp.json['data'] is None + + +def test_okina_suscribe(fake_http, app, okina): for service in ('subscriber', 'subscription'): endpoint = utils.generic_endpoint_url('okina', service, slug=okina.slug) assert endpoint == '/okina/test/%s' % service - with mock.patch('passerelle.utils.Request.get') as requests_get: - resp = app.post(endpoint, status=403) - assert requests_get.call_count == 0 - assert resp.json['err'] == 1 - assert resp.json['err_class'] == 'django.core.exceptions.PermissionDenied' + resp = app.post(endpoint, status=403) + assert resp.json['err'] == 1 + assert resp.json['err_class'] == 'django.core.exceptions.PermissionDenied' + # open access api = ApiUser.objects.create(username='all', keytype='', key='') obj_type = ContentType.objects.get_for_model(okina) @@ -1541,56 +1533,46 @@ def test_okina_suscribe(app, okina): for service in ('subscriber', 'subscription'): endpoint = utils.generic_endpoint_url('okina', service, slug=okina.slug) assert endpoint == '/okina/test/%s' % service - with mock.patch('passerelle.utils.Request.post') as requests_get: - resp = app.post(endpoint, status=400) # no payload - assert requests_get.call_count == 0 - assert resp.json['err'] == 1 - assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' - assert resp.json['err_desc'] == 'payload must be a JSON object' + resp = app.post(endpoint, status=400) # no payload + assert resp.json['err'] == 1 + assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' + assert resp.json['err_desc'] == 'payload must be a JSON object' - resp = app.post_json(endpoint, params=[], status=400) # bad payload - assert requests_get.call_count == 0 - assert resp.json['err'] == 1 - assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' - assert resp.json['err_desc'] == 'payload must be a dict' + resp = app.post_json(endpoint, params=[], status=400) # bad payload + assert resp.json['err'] == 1 + assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError' + assert resp.json['err_desc'] == 'payload must be a dict' - requests_get.return_value = utils.FakedResponse(content='{"foo":"bar"}', status_code=200) - resp = app.post_json(endpoint, params={'x':'y'}) - assert requests_get.call_count == 1 - assert resp.json['err'] == 0 - assert resp.json['data'] == {'foo': 'bar'} + fake_http.set_response(content='{"foo":"bar"}', status_code=200) + resp = app.post_json(endpoint, params={'x': 'y'}) + assert resp.json['err'] == 0 + assert resp.json['data'] == {'foo': 'bar'} # qrcode endpoint = '/okina/test/subscriber/123/qrcode' - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content='PNGfoo', - headers={'Content-Type': 'image/png'}, - status_code=200) - resp = app.get(endpoint) - assert requests_get.call_count == 1 - assert resp.headers['content-type'] == 'image/png' - assert resp.content == 'PNGfoo' + fake_http.set_response(content='PNGfoo', headers={'Content-Type': 'image/png'}, status_code=200) + resp = app.get(endpoint) + assert resp.headers['content-type'] == 'image/png' + assert resp.content == 'PNGfoo' - requests_get.return_value = utils.FakedResponse(content=QRCODE_400, - headers={'Content-Type': 'application/json' }, - status_code=400) - resp = app.get(endpoint, status=400) - assert requests_get.call_count == 2 - assert resp.json == { - u'err': 1, - u'err_class': u'passerelle.utils.jsonresponse.APIError', - u'err_desc': u'Subscriber with ID 123 has no passcard number to generate qr code from.', - u'data': None, - } + fake_http.set_response(content=QRCODE_400, + headers={'Content-Type': 'application/json' }, + status_code=400) + resp = app.get(endpoint, status=400) + assert resp.json == { + u'err': 1, + u'err_class': u'passerelle.utils.jsonresponse.APIError', + u'err_desc': u'Subscriber with ID 123 has no passcard number to generate qr code from.', + u'data': None, + } - requests_get.return_value = utils.FakedResponse(content=QRCODE_404, - headers={'Content-Type': 'application/json' }, - status_code=404) - resp = app.get(endpoint, status=404) - assert requests_get.call_count == 3 - assert resp.json == { - u'err': 1, - u'err_class': u'passerelle.utils.jsonresponse.APIError', - u'err_desc': u'Subscriber with ID 123 not found.', - u'data': None, - } + fake_http.set_response(content=QRCODE_404, + headers={'Content-Type': 'application/json' }, + status_code=404) + resp = app.get(endpoint, status=404) + assert resp.json == { + u'err': 1, + u'err_class': u'passerelle.utils.jsonresponse.APIError', + u'err_desc': u'Subscriber with ID 123 not found.', + u'data': None, + } diff --git a/tests/test_opengis.py b/tests/test_opengis.py index 1feb36a..8bfb6d6 100644 --- a/tests/test_opengis.py +++ b/tests/test_opengis.py @@ -222,32 +222,14 @@ def connector(db): wfs_service_url='http://example.net/wfs')) -def geoserver_responses(url, **kwargs): - if kwargs['params'].get('request') == 'GetCapabilities': - return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES) - return utils.FakedResponse(status_code=200, content=FAKE_FEATURES_JSON) - - -def geoserver_responses_errors(url, **kwargs): - if kwargs['params'].get('request') == 'GetCapabilities': - return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES) - return utils.FakedResponse(status_code=200, content=FAKE_ERROR) - - -def geoserver_responses_errors_unparsable(url, **kwargs): - if kwargs['params'].get('request') == 'GetCapabilities': - return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES) - return utils.FakedResponse(status_code=200, content=FAKE_ERROR[:10]) - - -@mock.patch('passerelle.utils.Request.get') -def test_feature_info(mocked_get, app, connector): +def test_feature_info(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'feature_info', slug=connector.slug) assert endpoint == '/opengis/test/feature_info' - mocked_get.return_value = utils.FakedResponse(content=FAKE_FEATURE_INFO, status_code=200) + + fake_http.set_response(content=FAKE_FEATURE_INFO, status_code=200) resp = app.get(endpoint, params={'lat': '45.796890', 'lon': '4.784140'}) - assert mocked_get.call_args[1]['params']['BBOX'] == '5747860.22776,532568.028684,5748179.56467,532790.667665' - assert mocked_get.call_args[1]['params']['CRS'] == 'EPSG:3857' + assert fake_http.last_request.GET['BBOX'] == '5747860.22776,532568.028684,5748179.56467,532790.667665' + assert fake_http.last_request.GET['CRS'] == 'EPSG:3857' assert (resp.json['data'] ['cad_cadastrecadparcelle_layer'] ['cad_cadastrecadparcelle_feature'] @@ -255,152 +237,161 @@ def test_feature_info(mocked_get, app, connector): == 'Particulier') connector.projection = 'EPSG:4326' connector.save() + + fake_http.set_response(content=FAKE_FEATURE_INFO, status_code=200) resp = app.get(endpoint, params={'lat': '45.796890', 'lon': '4.784140'}) - assert mocked_get.call_args[1]['params']['BBOX'] == '45.796890,4.784140,45.79889,4.78614' - assert mocked_get.call_args[1]['params']['CRS'] == 'EPSG:4326' + assert fake_http.last_request.GET['BBOX'] == '45.796890,4.784140,45.79889,4.78614' + assert fake_http.last_request.GET['CRS'] == 'EPSG:4326' -@mock.patch('passerelle.utils.Request.get') -def test_tile(mocked_get, app, connector): +def test_tile(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'tile', slug=connector.slug) assert endpoint == '/opengis/test/tile' - mocked_get.return_value = utils.FakedResponse(content='\x89PNG\r\n\x1a\n\x00\x00...', status_code=200) + + fake_http.set_response(content='\x89PNG\r\n\x1a\n\x00\x00...', status_code=200) resp = app.get(endpoint + '/16/33650/23378.png') - assert mocked_get.call_args[1]['params']['SRS'] == 'EPSG:3857' - assert mocked_get.call_args[1]['params']['BBOX'] == '539339.67158,5741338.06856,539951.167806,5741949.56478' + assert fake_http.last_request.GET['SRS'] == 'EPSG:3857' + assert fake_http.last_request.GET['BBOX'] == '539339.67158,5741338.06856,539951.167806,5741949.56478' connector.projection = 'EPSG:4326' connector.save() + + fake_http.set_response(content='\x89PNG\r\n\x1a\n\x00\x00...', status_code=200) resp = app.get(endpoint + '/16/33650/23378.png') - assert mocked_get.call_args[1]['params']['SRS'] == 'EPSG:4326' - assert mocked_get.call_args[1]['params']['BBOX'] == '4.84497070312,45.7560261559,4.85046386719,45.7598586879' + assert fake_http.last_request.GET['SRS'] == 'EPSG:4326' + assert fake_http.last_request.GET['BBOX'] == '4.84497070312,45.7560261559,4.85046386719,45.7598586879' assert resp.content == '\x89PNG\r\n\x1a\n\x00\x00...' -@mock.patch('passerelle.utils.Request.get') -def test_get_feature_with_no_wfs_url(mocked_get, app, connector): +def test_get_feature_with_no_wfs_url(fake_http, app, connector): connector.wfs_service_url = '' connector.save() endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug) assert endpoint == '/opengis/test/features' - mocked_get.side_effect = geoserver_responses + resp = app.get(endpoint, params={'type_names': 'ref_metro_limites_communales', 'property_name': 'nom'}) assert resp.json['data'] is None assert resp.json['err'] == 1 assert resp.json['err_desc'] == 'no wfs URL declared' -@mock.patch('passerelle.utils.Request.get') -def test_get_feature(mocked_get, app, connector): +def test_get_feature(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug) assert endpoint == '/opengis/test/features' - mocked_get.side_effect = geoserver_responses + + fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES, method='GET') + fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET') resp = app.get(endpoint, params={'type_names': 'ref_metro_limites_communales', 'property_name': 'nom'}) - assert mocked_get.call_args[1]['params']['REQUEST'] == 'GetFeature' - assert mocked_get.call_args[1]['params']['PROPERTYNAME'] == 'nom' - assert mocked_get.call_args[1]['params']['TYPENAMES'] == 'ref_metro_limites_communales' - assert mocked_get.call_args[1]['params']['OUTPUTFORMAT'] == 'json' - assert mocked_get.call_args[1]['params']['SERVICE'] == 'WFS' - assert mocked_get.call_args[1]['params']['VERSION'] == connector.get_wfs_service_version() + assert fake_http.last_request.GET['REQUEST'] == 'GetFeature' + assert fake_http.last_request.GET['PROPERTYNAME'] == 'nom' + assert fake_http.last_request.GET['TYPENAMES'] == 'ref_metro_limites_communales' + assert fake_http.last_request.GET['OUTPUTFORMAT'] == 'json' + assert fake_http.last_request.GET['SERVICE'] == 'WFS' + assert fake_http.last_request.GET['VERSION'] == connector.get_wfs_service_version() assert len(resp.json['data']) == 7 for item in resp.json['data']: assert 'text' in item -@mock.patch('passerelle.utils.Request.get') -def test_get_filtered_feature(mocked_get, app, connector): +def test_get_filtered_feature(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug) - mocked_get.side_effect = geoserver_responses + fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES, method='GET') + fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET') app.get(endpoint, params={ 'type_names': 'ref_metro_limites_communales', 'property_name': 'nom', 'cql_filter': 'nom=\'Fontaine\'' }) - assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\'' + assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\'' -@mock.patch('passerelle.utils.Request.get') -def test_get_filtered_by_property_feature(mocked_get, app, connector): +def test_get_filtered_by_property_feature(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug) - mocked_get.side_effect = geoserver_responses + + fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES, method='GET') + fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET') params = {'type_names': 'ref_metro_limites_communales', 'property_name': 'nom', 'cql_filter': 'nom=\'Fontaine\'', 'filter_property_name': 'nom'} app.get(endpoint, params=params) - assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\'' + assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\'' + + fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET') params['q'] = 'bens' app.get(endpoint, params=params) - assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom LIKE \'%bens%\'' + assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom LIKE \'%bens%\'' + + fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET') params['case-insensitive'] = True app.get(endpoint, params=params) - assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom ILIKE \'%bens%\'' + assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom ILIKE \'%bens%\'' + + fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET') params.pop('cql_filter') app.get(endpoint, params=params) - assert 'CQL_FILTER' not in mocked_get.call_args[1]['params'] + assert 'CQL_FILTER' not in fake_http.last_request.GET -@mock.patch('passerelle.utils.Request.get') -def test_get_feature_error(mocked_get, app, connector): +def test_get_feature_error(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug) assert endpoint == '/opengis/test/features' - mocked_get.side_effect = geoserver_responses_errors + + fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES) + fake_http.add_response(status_code=200, content=FAKE_ERROR) resp = app.get(endpoint, params={ 'type_names': 'ref_metro_limites_communales', 'property_name': 'nom' }) - assert mocked_get.call_args[1]['params']['REQUEST'] == 'GetFeature' - assert mocked_get.call_args[1]['params']['PROPERTYNAME'] == 'nom' - assert mocked_get.call_args[1]['params']['TYPENAMES'] == 'ref_metro_limites_communales' - assert mocked_get.call_args[1]['params']['OUTPUTFORMAT'] == 'json' - assert mocked_get.call_args[1]['params']['SERVICE'] == 'WFS' - assert mocked_get.call_args[1]['params']['VERSION'] == connector.get_wfs_service_version() + assert fake_http.last_request.GET['REQUEST'] == 'GetFeature' + assert fake_http.last_request.GET['PROPERTYNAME'] == 'nom' + assert fake_http.last_request.GET['TYPENAMES'] == 'ref_metro_limites_communales' + assert fake_http.last_request.GET['OUTPUTFORMAT'] == 'json' + assert fake_http.last_request.GET['SERVICE'] == 'WFS' + assert fake_http.last_request.GET['VERSION'] == connector.get_wfs_service_version() result = resp.json assert result['err'] == 1 assert result['err_desc'] == 'OpenGIS Error: NoApplicableCode' assert 'Could not parse' in result['data']['text'] -@mock.patch('passerelle.utils.Request.get') -def test_get_feature_error2(mocked_get, app, connector): +def test_get_feature_error2(fake_http, app, connector): endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug) assert endpoint == '/opengis/test/features' - mocked_get.side_effect = geoserver_responses_errors_unparsable + + fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES) + fake_http.add_response(status_code=200, content=FAKE_ERROR[:10]) resp = app.get(endpoint, params={ 'type_names': 'ref_metro_limites_communales', 'property_name': 'nom' }) - assert mocked_get.call_args[1]['params']['REQUEST'] == 'GetFeature' - assert mocked_get.call_args[1]['params']['PROPERTYNAME'] == 'nom' - assert mocked_get.call_args[1]['params']['TYPENAMES'] == 'ref_metro_limites_communales' - assert mocked_get.call_args[1]['params']['OUTPUTFORMAT'] == 'json' - assert mocked_get.call_args[1]['params']['SERVICE'] == 'WFS' - assert mocked_get.call_args[1]['params']['VERSION'] == connector.get_wfs_service_version() + assert fake_http.last_request.GET['REQUEST'] == 'GetFeature' + assert fake_http.last_request.GET['PROPERTYNAME'] == 'nom' + assert fake_http.last_request.GET['TYPENAMES'] == 'ref_metro_limites_communales' + assert fake_http.last_request.GET['OUTPUTFORMAT'] == 'json' + assert fake_http.last_request.GET['SERVICE'] == 'WFS' + assert fake_http.last_request.GET['VERSION'] == connector.get_wfs_service_version() result = resp.json assert result['err'] == 1 assert result['err_desc'] == 'OpenGIS Error: unparsable error' assert ' 40: + if logger.level > 20: assert records_length == 0 else: assert records_length == 1 @@ -105,60 +94,67 @@ def test_log_error(caplog, log_level): assert not hasattr(record, 'response_content') assert not hasattr(record, 'response_headers') -@pytest.fixture(params=['xml', 'whatever', 'jpeg', 'pdf']) -def endpoint_response(request): - response_request = mock.Mock( - headers={'Accept': '*/*', 'Authorization': 'Basic dG9rZW46dG9rZW4='}, body=None) - xml = FakedResponse( - headers={'Content-Type': 'application/xml; charset=charset=utf-8'}, status_code=200, - content='xml test', request=response_request) - - whatever = FakedResponse( - headers={'Content-Type': 'texto/csv'}, status_code=200, - content='username;age\ntoken;10\ncartman:10', request=response_request) - - jpeg = FakedResponse( - headers={'Content-Type': 'image/jpeg'}, status_code=200, - content='binary content to be ignored', request=response_request) - - pdf = FakedResponse( - headers={'Content-Type': 'application/pdf'}, status_code=200, - content='binary content to be ignored', request=response_request) - return locals().get(request.param) - - -@mock.patch('passerelle.utils.RequestSession.send') -def test_skip_content_type(mocked_get, caplog, endpoint_response): - mocked_get.return_value = endpoint_response +@pytest.fixture(params=['xml', 'whatever', 'jpeg', 'pdf']) +def setup_endpoint_response(request, fake_http): + def do(): + if request.param == 'xml': + fake_http.set_response( + status_code=200, + headers={'Content-Type': 'application/xml; charset=charset=utf-8'}, + content='xml test') + elif request.param == 'whatever': + fake_http.set_response( + status_code=200, + headers={'Content-Type': 'texto/csv'}, + content='username;age\ntoken;10\ncartman:10') + elif request.param == 'jpeg': + fake_http.set_response( + status_code=200, + headers={'Content-Type': 'image/jpeg'}, + content='binary content to be ignored') + elif request.param == 'pdf': + fake_http.set_response( + status_code=200, + headers={'Content-Type': 'application/pdf'}, + content='binary content to be ignored') + return fake_http + do.param = request.param + return do + + +def test_skip_content_type(request, caplog, setup_endpoint_response): + # XXX: what is tested here ? I dunno :/ logger = logging.getLogger('requests') logger.setLevel(logging.DEBUG) requests = Request(logger=logger) - response = requests.get('http://example.net/whatever').body + + setup_endpoint_response() + requests.get( + 'http://example.net/whatever', + headers={'Accept': '*/*', 'Authorization': 'Basic dG9rZW46dG9rZW4='} + ) records = [record for record in caplog.records if record.name == 'requests'] - if 'xml' in endpoint_response.headers.get('Content-Type'): - assert len(records) == 1 + assert len(records) == 1 + if setup_endpoint_response.param == 'xml': assert records[0].response_content == "'xml test'" - else: - assert len(records) == 1 @mock.patch('passerelle.utils.RequestSession.request') -def test_proxies(mocked_get, caplog, endpoint_response): - mocked_get.return_value = endpoint_response +def test_proxies(mocked_get, caplog): logger = logging.getLogger('requests') + Request(logger=logger).get('http://example.net/whatever') assert mocked_get.call_args[1].get('proxies') is None - Request(logger=logger).get('http://example.net/whatever', - proxies={'http': 'http://proxy'}) + + Request(logger=logger).get('http://example.net/whatever', proxies={'http': 'http://proxy'}) assert mocked_get.call_args[1].get('proxies') == {'http': 'http://proxy'} with override_settings(REQUESTS_PROXIES={'http': 'http://globalproxy'}): Request(logger=logger).get('http://example.net/whatever') assert mocked_get.call_args[1].get('proxies') == {'http': 'http://globalproxy'} - Request(logger=logger).get('http://example.net/whatever', - proxies={'http': 'http://proxy'}) + Request(logger=logger).get('http://example.net/whatever', proxies={'http': 'http://proxy'}) assert mocked_get.call_args[1].get('proxies') == {'http': 'http://proxy'} # with a linked resource @@ -188,8 +184,7 @@ def test_proxies(mocked_get, caplog, endpoint_response): @mock.patch('passerelle.utils.RequestSession.request') -def test_resource_auth(mocked_get, caplog, endpoint_response): - mocked_get.return_value = endpoint_response +def test_resource_auth(mocked_get, caplog): logger = logging.getLogger('requests') resource = MockResource() request = Request(resource=resource, logger=logger) @@ -211,9 +206,10 @@ def test_resource_auth(mocked_get, caplog, endpoint_response): request.get('http://example.net/whatever', auth=None) assert mocked_get.call_args[1].get('auth') is None + @mock.patch('passerelle.utils.RequestSession.send') -def test_resource_hawk_auth(mocked_send, caplog, endpoint_response): - mocked_send.return_value = endpoint_response +def test_resource_hawk_auth(mocked_send): + mocked_send.return_value = FakedResponse(status_code=200, headers={}) logger = logging.getLogger('requests') resource = MockResource() request = Request(resource=resource, logger=logger) @@ -221,7 +217,7 @@ def test_resource_hawk_auth(mocked_send, caplog, endpoint_response): credentials = {'id': 'id', 'key': 'key', 'algorithm': 'sha256'} hawk_auth = HawkAuth(**credentials) - resp = request.get('http://httpbin.org/get', auth=hawk_auth) + request.get('http://httpbin.org/get', auth=hawk_auth) prepared_method = mocked_send.call_args[0][0] assert 'Authorization' in prepared_method.headers generated_header = prepared_method.headers['Authorization'] @@ -236,7 +232,7 @@ def test_resource_hawk_auth(mocked_send, caplog, endpoint_response): assert dict(generated_parts) == dict(expected_parts) hawk_auth = HawkAuth(ext='extra attribute', **credentials) - resp = request.post('http://httpbin.org/post', auth=hawk_auth, json={'key': 'value'}) + request.post('http://httpbin.org/post', auth=hawk_auth, json={'key': 'value'}) prepared_method = mocked_send.call_args[0][0] assert 'Authorization' in prepared_method.headers generated_header = prepared_method.headers['Authorization'] @@ -252,8 +248,7 @@ def test_resource_hawk_auth(mocked_send, caplog, endpoint_response): @mock.patch('passerelle.utils.RequestSession.request') -def test_resource_certificates(mocked_get, caplog, endpoint_response): - mocked_get.return_value = endpoint_response +def test_resource_certificates(mocked_get, caplog): logger = logging.getLogger('requests') resource = MockResource() request = Request(resource=resource, logger=logger) @@ -290,9 +285,9 @@ def test_requests_cache(mocked_get, caplog): response_request = mock.Mock(headers={'Accept': '*/*'}, body=None) mocked_get.return_value = FakedResponse( - headers={'Content-Type': 'text/plain; charset=charset=utf-8'}, - request=response_request, - content='hello world', status_code=200) + headers={'Content-Type': 'text/plain; charset=charset=utf-8'}, + request=response_request, + content='hello world', status_code=200) # by default there is no cache assert request.get('http://cache.example.org/').content == 'hello world' @@ -308,9 +303,9 @@ def test_requests_cache(mocked_get, caplog): # value changed mocked_get.return_value = FakedResponse( - headers={'Content-Type': 'text/plain; charset=charset=utf-8'}, - request=response_request, - content='hello second world', status_code=200) + headers={'Content-Type': 'text/plain; charset=charset=utf-8'}, + request=response_request, + content='hello second world', status_code=200) assert request.get('http://cache.example.org/', cache_duration=15).content == 'hello world' assert mocked_get.call_count == 1 @@ -320,9 +315,9 @@ def test_requests_cache(mocked_get, caplog): # do not cache errors mocked_get.return_value = FakedResponse( - headers={'Content-Type': 'text/plain; charset=charset=utf-8'}, - request=response_request, - content='no such world', status_code=404) + headers={'Content-Type': 'text/plain; charset=charset=utf-8'}, + request=response_request, + content='no such world', status_code=404) mocked_get.reset_mock() response = request.get('http://cache.example.org/404', cache_duration=15) assert response.content == 'no such world' @@ -334,32 +329,32 @@ def test_requests_cache(mocked_get, caplog): # check response headers mocked_get.reset_mock() mocked_get.return_value = FakedResponse( - headers=CaseInsensitiveDict({'Content-Type': 'image/png'}), - request=response_request, - content='hello world', status_code=200) + headers=CaseInsensitiveDict({'Content-Type': 'image/png'}), + request=response_request, + content='hello world', status_code=200) assert request.get('http://cache.example.org/img', cache_duration=15).headers.get('content-type') == 'image/png' assert mocked_get.call_count == 1 assert request.get('http://cache.example.org/img', cache_duration=15).headers.get('content-type') == 'image/png' - assert mocked_get.call_count == 1 # got a cached response + assert mocked_get.call_count == 1 # got a cached response @mock.patch('passerelle.utils.RequestSession.request') -def test_timeout(mocked_get, caplog, endpoint_response): - mocked_get.return_value = endpoint_response +def test_timeout(mocked_request, caplog): + mocked_request.return_value = FakedResponse(status_code=200, headers={}) logger = logging.getLogger('requests') Request(logger=logger).get('http://example.net/whatever') - assert mocked_get.call_args[1]['timeout'] == 25 + assert mocked_request.call_args[1]['timeout'] == 25 Request(logger=logger).get('http://example.net/whatever', timeout=42) - assert mocked_get.call_args[1]['timeout'] == 42 + assert mocked_request.call_args[1]['timeout'] == 42 Request(logger=logger).get('http://example.net/whatever', timeout=None) - assert mocked_get.call_args[1]['timeout'] is None + assert mocked_request.call_args[1]['timeout'] is None with override_settings(REQUESTS_TIMEOUT=57): Request(logger=logger).get('http://example.net/whatever') - assert mocked_get.call_args[1]['timeout'] == 57 + assert mocked_request.call_args[1]['timeout'] == 57 Request(logger=logger).get('http://example.net/whatever', timeout=42) - assert mocked_get.call_args[1]['timeout'] == 42 + assert mocked_request.call_args[1]['timeout'] == 42 Request(logger=logger).get('http://example.net/whatever', timeout=None) - assert mocked_get.call_args[1]['timeout'] is None + assert mocked_request.call_args[1]['timeout'] is None diff --git a/tests/test_solis.py b/tests/test_solis.py index b5dfed8..1cb7a80 100644 --- a/tests/test_solis.py +++ b/tests/test_solis.py @@ -127,7 +127,7 @@ def test_solis_ping(app, solis, ping_response): 'https': 'http://proxy:3128/'} -def test_solis_link_infos_unlink(app, solis): +def test_solis_link_infos_unlink(fake_http, app, solis): # full opened access api = ApiUser.objects.create(username='all', keytype='', key='') obj_type = ContentType.objects.get_for_model(solis) @@ -135,82 +135,78 @@ def test_solis_link_infos_unlink(app, solis): resource_pk=solis.pk) # link - with mock.patch('passerelle.utils.Request.post') as requests_post: # get solis token - with mock.patch('passerelle.utils.Request.get') as requests_get: # get solis informations - endpoint = utils.generic_endpoint_url('solis', 'apa-link', slug=solis.slug) - for params in (None, '', []): - resp = app.post_json(endpoint, params=params, status=200) - assert requests_post.call_count == 0 - assert resp.json['err'] == 1 - assert 'payload is not a JSON dict' in resp.json['err_desc'] + endpoint = utils.generic_endpoint_url('solis', 'apa-link', slug=solis.slug) + for params in (None, '', []): + resp = app.post_json(endpoint, params=params, status=200) + assert resp.json['err'] == 1 + assert 'payload is not a JSON dict' in resp.json['err_desc'] - for params in ({}, {'user_id': 'x'}, {'code': 'x'}, {'foo': 'bar'}): - resp = app.post_json(endpoint, params=params, status=200) - assert requests_post.call_count == 0 - assert resp.json['err'] == 1 - assert 'missing name_id' in resp.json['err_desc'] - params['name_id'] = 'xx' - resp = app.post_json(endpoint, params=params, status=200) - assert requests_post.call_count == 0 - assert resp.json['err'] == 1 - assert 'missing user_id/code credentials' in resp.json['err_desc'] - - requests_post.return_value = utils.FakedResponse(content=APATOKEN_403, status_code=403) - resp = app.post_json(endpoint, - params={'user_id': 'x', 'code': 'x', 'name_id': NAMEID}, - status=200) - assert requests_post.call_count == 1 - assert requests_get.call_count == 0 - assert resp.json['err'] == 1 - assert 'Code confidentiel non valide' in resp.json['err_desc'] - - assert SolisAPALink.objects.count() == 0 - - requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200) - requests_get.return_value = utils.FakedResponse(content=APAINFOS['exportDonneesIndividu'], - status_code=200) - resp = app.post_json(endpoint, - params={'name_id': NAMEID, 'user_id': '42', 'code': 'foo'}, - status=200) - assert requests_post.call_count == 2 - assert requests_get.call_count == 1 - assert resp.json['err'] == 0 - assert resp.json['data']['user_id'] == '42' - assert resp.json['data']['created'] - assert not resp.json['data']['updated'] - assert SolisAPALink.objects.count() == 1 - assert SolisAPALink.objects.first().name_id == NAMEID - assert SolisAPALink.objects.first().user_id == '42' - assert SolisAPALink.objects.first().code == 'foo' - assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)' - - # change code - resp = app.post_json(endpoint, - params={'name_id': NAMEID, 'user_id': '42', 'code': 'bar'}, - status=200) - assert requests_post.call_count == 3 - assert requests_get.call_count == 2 - assert resp.json['err'] == 0 - assert resp.json['data']['user_id'] == '42' - assert not resp.json['data']['created'] - assert resp.json['data']['updated'] - assert SolisAPALink.objects.count() == 1 - assert SolisAPALink.objects.first().name_id == NAMEID - assert SolisAPALink.objects.first().user_id == '42' - assert SolisAPALink.objects.first().code == 'bar' - assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)' - - # second link - resp = app.post_json(endpoint, - params={'name_id': NAMEID, 'user_id': '53', 'code': 'bar'}, - status=200) - assert requests_post.call_count == 4 - assert requests_get.call_count == 3 - assert resp.json['err'] == 0 - assert resp.json['data']['user_id'] == '53' - assert resp.json['data']['created'] - assert not resp.json['data']['updated'] - assert SolisAPALink.objects.count() == 2 + for params in ({}, {'user_id': 'x'}, {'code': 'x'}, {'foo': 'bar'}): + resp = app.post_json(endpoint, params=params, status=200) + assert resp.json['err'] == 1 + assert 'missing name_id' in resp.json['err_desc'] + params['name_id'] = 'xx' + resp = app.post_json(endpoint, params=params, status=200) + assert resp.json['err'] == 1 + assert 'missing user_id/code credentials' in resp.json['err_desc'] + + fake_http.set_response(content=APATOKEN_403, status_code=403, method='POST') + resp = app.post_json(endpoint, + params={'user_id': 'x', 'code': 'x', 'name_id': NAMEID}, + status=200) + assert resp.json['err'] == 1 + assert 'Code confidentiel non valide' in resp.json['err_desc'] + + assert SolisAPALink.objects.count() == 0 + + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=APAINFOS['exportDonneesIndividu'], + status_code=200, + method='GET') + resp = app.post_json(endpoint, + params={'name_id': NAMEID, 'user_id': '42', 'code': 'foo'}, + status=200) + assert resp.json['err'] == 0 + assert resp.json['data']['user_id'] == '42' + assert resp.json['data']['created'] + assert not resp.json['data']['updated'] + assert SolisAPALink.objects.count() == 1 + assert SolisAPALink.objects.first().name_id == NAMEID + assert SolisAPALink.objects.first().user_id == '42' + assert SolisAPALink.objects.first().code == 'foo' + assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)' + + # change code + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=APAINFOS['exportDonneesIndividu'], + status_code=200, + method='GET') + resp = app.post_json(endpoint, + params={'name_id': NAMEID, 'user_id': '42', 'code': 'bar'}, + status=200) + assert resp.json['err'] == 0 + assert resp.json['data']['user_id'] == '42' + assert not resp.json['data']['created'] + assert resp.json['data']['updated'] + assert SolisAPALink.objects.count() == 1 + assert SolisAPALink.objects.first().name_id == NAMEID + assert SolisAPALink.objects.first().user_id == '42' + assert SolisAPALink.objects.first().code == 'bar' + assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)' + + # second link + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=APAINFOS['exportDonneesIndividu'], + status_code=200, + method='GET') + resp = app.post_json(endpoint, + params={'name_id': NAMEID, 'user_id': '53', 'code': 'bar'}, + status=200) + assert resp.json['err'] == 0 + assert resp.json['data']['user_id'] == '53' + assert resp.json['data']['created'] + assert not resp.json['data']['updated'] + assert SolisAPALink.objects.count() == 2 # verify recorded names after link assert [x['text'] for x in SolisAPALink.objects.values('text')] == \ @@ -227,143 +223,119 @@ def test_solis_link_infos_unlink(app, solis): # get base informations from a linked user (exportDonneesIndividu) changed_name = APAINFOS['exportDonneesIndividu'].replace('PYPPENNE', 'PEPONE') - with mock.patch('passerelle.utils.Request.get') as requests_get: - with mock.patch('passerelle.utils.Request.post') as requests_post: - requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200) - requests_get.return_value = utils.FakedResponse(content=changed_name, status_code=200) - endpoint = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug) - endpoint += '?name_id=%s&user_id=42' % NAMEID - resp = app.get(endpoint, status=200) - assert resp.json['err'] == 0 - assert resp.json['data']['individu']['nomUsuel'] == 'PEPONE' - # user "text" updated in link: - assert SolisAPALink.objects.get(name_id=NAMEID, user_id='42').text == \ - 'Mme Pecile PEPONE (NPYNEZ)' + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=changed_name, status_code=200, method='GET') + endpoint = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug) + endpoint += '?name_id=%s&user_id=42' % NAMEID + resp = app.get(endpoint, status=200) + assert resp.json['err'] == 0 + assert resp.json['data']['individu']['nomUsuel'] == 'PEPONE' + # user "text" updated in link: + assert SolisAPALink.objects.get(name_id=NAMEID, user_id='42').text == \ + 'Mme Pecile PEPONE (NPYNEZ)' # get all kind of informations for apa_endpoint in APAINFOS: - with mock.patch('passerelle.utils.Request.get') as requests_get: - with mock.patch('passerelle.utils.Request.post') as requests_post: - requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200) + endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug) + resp = app.get(endpoint_base, status=400) # missing name_id + assert resp.json['err'] == 1 - endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug) - resp = app.get(endpoint_base, status=400) # missing name_id - assert resp.json['err'] == 1 + endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s' % (NAMEID, apa_endpoint) + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') - endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s' % (NAMEID, apa_endpoint) - requests_get.return_value = utils.FakedResponse(content=APAINFOS[apa_endpoint], - status_code=200) - resp = app.get(endpoint, status=200) - assert requests_post.call_count == 1 # get a token - assert requests_get.call_count == 1 # get informations - assert ('/asg/apa/%s' % apa_endpoint) in requests_get.call_args[0][0] - assert resp.json['err'] == 0 - assert resp.json['data'] - - # solis api crash - requests_get.return_value = utils.FakedResponse(content='boum', - status_code=500) - resp = app.get(endpoint, status=200) - assert requests_post.call_count == 2 # get a token - assert requests_get.call_count == 2 # get informations - assert ('/asg/apa/%s' % apa_endpoint) in requests_get.call_args[0][0] - assert resp.json['err'] == 1 - assert resp.json['err_desc'].startswith('error status:500') - assert resp.json['data'] == {'json_content': None, 'status_code': 500} + fake_http.add_response(content=APAINFOS[apa_endpoint], status_code=200, method='GET') + resp = app.get(endpoint, status=200) + assert ('/asg/apa/%s' % apa_endpoint) in fake_http.last_request.url + assert resp.json['err'] == 0 + assert resp.json['data'] - requests_get.return_value = utils.FakedResponse(content='{"error":"foobar"}', - status_code=500) - resp = app.get(endpoint, status=200) - assert resp.json['err'] == 1 - assert resp.json['err_desc'].startswith('error status:500') - assert resp.json['data'] == {'json_content': {'error': 'foobar'}, 'status_code': 500} + # solis api crash + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') - # unknown name_id or user_id - for qs in ('name_id=%s&user_id=XXX' % NAMEID, 'name_id=unlinked&user_id=53'): - endpoint = endpoint_base + ('?information=%s' % apa_endpoint) + '&' + qs - resp = app.get(endpoint, status=200) - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == 'unknown link' - assert resp.json['data'] is None + fake_http.add_response(content='boum', status_code=500, method='GET') + resp = app.get(endpoint, status=200) + assert ('/asg/apa/%s' % apa_endpoint) in fake_http.last_request.url + assert resp.json['err'] == 1 + assert resp.json['err_desc'].startswith('error status:500') + assert resp.json['data'] == {'json_content': None, 'status_code': 500} - # get info about a specific request - with mock.patch('passerelle.utils.Request.get') as requests_get: - with mock.patch('passerelle.utils.Request.post') as requests_post: - requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200) - endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug) + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content='{"error":"foobar"}', status_code=500, method='GET') + resp = app.get(endpoint, status=200) + assert resp.json['err'] == 1 + assert resp.json['err_desc'].startswith('error status:500') + assert resp.json['data'] == {'json_content': {'error': 'foobar'}, 'status_code': 500} - # via demandeUnitaire - endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire&index=42' % NAMEID - requests_get.return_value = utils.FakedResponse(content=APAREQUEST, status_code=200) - resp = app.get(endpoint, status=200) - assert requests_post.call_count == 1 # get a token - assert requests_get.call_count == 1 # get demandeUnitaire - url = requests_get.call_args[0][0] - assert '/asg/apa/demandeUnitaire/' in url - assert url.endswith('/42') - assert resp.json['err'] == 0 - assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42 - - requests_post.reset_mock() - requests_get.reset_mock() - requests_get.return_value = utils.FakedResponse(content='nothing here', status_code=404) + # unknown name_id or user_id + for qs in ('name_id=%s&user_id=XXX' % NAMEID, 'name_id=unlinked&user_id=53'): + endpoint = endpoint_base + ('?information=%s' % apa_endpoint) + '&' + qs resp = app.get(endpoint, status=200) - assert requests_post.call_count == 1 # get a token - assert requests_get.call_count == 1 # get demandeUnitaire - url = requests_get.call_args[0][0] - assert '/asg/apa/demandeUnitaire/' in url - assert url.endswith('/42') - assert resp.json['err'] == 1 - assert resp.json['err_desc'].startswith('error status:404') - - # missing index - requests_post.reset_mock() - requests_get.reset_mock() - endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire' % NAMEID - resp = app.get(endpoint, status=400) - requests_get.assert_not_called() - requests_post.assert_not_called() assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'unknown link' + assert resp.json['data'] is None - # get indexDemande 42 in lists - for information in ('consultationDeMesDroits', 'suiviDemandeHistorique', 'propositionPlanAide',): - requests_post.reset_mock() - requests_get.reset_mock() - endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=42' % (NAMEID, information) - requests_get.return_value = utils.FakedResponse(content=APAINFOS[information], status_code=200) - resp = app.get(endpoint, status=200) - assert ('/asg/apa/%s/' % information) in requests_get.call_args[0][0] - requests_post.assert_called_once() - requests_get.assert_called_once() - assert resp.json['err'] == 0 - assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42 - - endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=57' % (NAMEID, information) - resp = app.get(endpoint, status=200) - assert ('/asg/apa/%s/' % information) in requests_get.call_args[0][0] - assert requests_post.call_count == 2 - assert requests_get.call_count == 2 - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == 'cannot find indexDemande=57 in demandeAsg list' + # get info about a specific request + endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug) + + # via demandeUnitaire + endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire&index=42' % NAMEID + fake_http.set_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=APAREQUEST, status_code=200, method='GET') + resp = app.get(endpoint, status=200) + assert '/asg/apa/demandeUnitaire/' in fake_http.last_request.url + assert fake_http.last_request.url.endswith('/42') + assert resp.json['err'] == 0 + assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42 + + fake_http.set_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content='nothing here', status_code=404, method='GET') + resp = app.get(endpoint, status=200) + assert '/asg/apa/demandeUnitaire/' in fake_http.last_request.url + assert fake_http.last_request.url.endswith('/42') + assert resp.json['err'] == 1 + assert resp.json['err_desc'].startswith('error status:404') + + # missing index + fake_http.reset() + endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire' % NAMEID + resp = app.get(endpoint, status=400) + assert resp.json['err'] == 1 + + # get indexDemande 42 in lists + for information in ('consultationDeMesDroits', 'suiviDemandeHistorique', 'propositionPlanAide',): + endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=42' % (NAMEID, information) + fake_http.set_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=APAINFOS[information], status_code=200, method='GET') + resp = app.get(endpoint, status=200) + assert ('/asg/apa/%s/' % information) in fake_http.last_request.url + assert resp.json['err'] == 0 + assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42 + + endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=57' % (NAMEID, information) + fake_http.set_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=APAINFOS[information], status_code=200, method='GET') + resp = app.get(endpoint, status=200) + assert ('/asg/apa/%s/' % information) in fake_http.last_request.url + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'cannot find indexDemande=57 in demandeAsg list' # get informations for all users (exportDonneesIndividu) change_info = APAINFOS['exportDonneesIndividu'].replace('PYPPENNE', 'PEPPYNE') - with mock.patch('passerelle.utils.Request.get') as requests_get: - with mock.patch('passerelle.utils.Request.post') as requests_post: - requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200) - requests_get.return_value = utils.FakedResponse(content=change_info, status_code=200) - endpoint = utils.generic_endpoint_url('solis', 'apa-users', slug=solis.slug) - endpoint += '?name_id=%s' % NAMEID - resp = app.get(endpoint, status=200) - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert requests_post.call_count == 2 - assert requests_get.call_count == 2 - assert set([x['id'] for x in resp.json['data']]) == set(['42', '53']) - assert resp.json['data'][0]['text'] == 'Mme Pecile PEPPYNE (NPYNEZ)' - # user "text" updated in links: - assert [x['text'] for x in SolisAPALink.objects.values('text')] == \ - ['Mme Pecile PEPPYNE (NPYNEZ)', 'Mme Pecile PEPPYNE (NPYNEZ)'] + fake_http.set_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=change_info, status_code=200, method='GET') + fake_http.add_response(content=APATOKEN, status_code=200, method='POST') + fake_http.add_response(content=change_info, status_code=200, method='GET') + endpoint = utils.generic_endpoint_url('solis', 'apa-users', slug=solis.slug) + endpoint += '?name_id=%s' % NAMEID + resp = app.get(endpoint, status=200) + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert set([x['id'] for x in resp.json['data']]) == set(['42', '53']) + assert resp.json['data'][0]['text'] == 'Mme Pecile PEPPYNE (NPYNEZ)' + # user "text" updated in links: + assert [x['text'] for x in SolisAPALink.objects.values('text')] == \ + ['Mme Pecile PEPPYNE (NPYNEZ)', 'Mme Pecile PEPPYNE (NPYNEZ)'] + fake_http.reset() # unlink endpoint = utils.generic_endpoint_url('solis', 'apa-unlink', slug=solis.slug) @@ -399,196 +371,183 @@ def test_solis_link_infos_unlink(app, solis): assert resp.json['data'] is None -def test_solis_referentiels(app, solis): +def test_solis_referentiels(fake_http, app, solis): # full opened access api = ApiUser.objects.create(username='all', keytype='', key='') obj_type = ContentType.objects.get_for_model(solis) AccessRight.objects.create(codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=solis.pk) - with mock.patch('passerelle.utils.Request.get') as requests_get: - requests_get.return_value = utils.FakedResponse(content=DEPARTEMENTS, status_code=200) - url = utils.generic_endpoint_url('solis', 'referential', slug=solis.slug) + fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET') + url = utils.generic_endpoint_url('solis', 'referential', slug=solis.slug) - resp = app.get(url + '/trans/departement/', status=200) - assert requests_get.call_count == 1 - assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/trans/departement') - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 8 + resp = app.get(url + '/trans/departement/', status=200) + assert fake_http.last_request.url.endswith('/solisapi/referentiels/trans/departement') + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 8 - resp = app.get(url + '/trans/departement/?q=ardeche', status=200) - assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/trans/departement') - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 1 - assert resp.json['data'][0]['text'] == u'Ardèche' + fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET') + resp = app.get(url + '/trans/departement/?q=ardeche', status=200) + assert fake_http.last_request.url.endswith('/solisapi/referentiels/trans/departement') + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 1 + assert resp.json['data'][0]['text'] == u'Ardèche' - resp = app.get(url + '/trans/departement/?q=arde', status=200) - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 2 - assert (resp.json['data'][0]['text'], resp.json['data'][1]['text']) == (u'Ardèche', 'Ardennes') + fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET') + resp = app.get(url + '/trans/departement/?q=arde', status=200) + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 2 + assert (resp.json['data'][0]['text'], resp.json['data'][1]['text']) == (u'Ardèche', 'Ardennes') - resp = app.get(url + '/trans/departement/?q=arde&ignore=8', status=200) - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 1 - assert resp.json['data'][0]['text'] == u'Ardèche' + fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET') + resp = app.get(url + '/trans/departement/?q=arde&ignore=8', status=200) + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 1 + assert resp.json['data'][0]['text'] == u'Ardèche' - resp = app.get(url + '/trans/departement/?q=arde&ignore=8,, 7', status=200) - assert resp.json['err'] == 0 - assert len(resp.json['data']) == 0 + fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET') + resp = app.get(url + '/trans/departement/?q=arde&ignore=8,, 7', status=200) + assert resp.json['err'] == 0 + assert len(resp.json['data']) == 0 - resp = app.get(url + '/trans/departement/?codePays=79&foo=bar', status=200) - assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/trans/departement?codePays=79') + fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET') + resp = app.get(url + '/trans/departement/?codePays=79&foo=bar', status=200) + assert fake_http.last_request.url.endswith('/solisapi/referentiels/trans/departement?codePays=79') - requests_get.return_value = utils.FakedResponse(content='{"nada":0}', status_code=404, - reason='Not found') - resp = app.get(url + '/foo/bar/', status=200) - assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/foo/bar') - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == "error status:404 'Not found', content:'{\"nada\":0}'" - assert resp.json['data'] == {'json_content': {'nada': 0}, 'status_code': 404} + fake_http.set_response(content='{"nada":0}', status_code=404, reason='Not found', method='GET') + resp = app.get(url + '/foo/bar/', status=200) + assert fake_http.last_request.url.endswith('/solisapi/referentiels/foo/bar') + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == "error status:404 'Not found', content:'{\"nada\":0}'" + assert resp.json['data'] == {'json_content': {'nada': 0}, 'status_code': 404} - requests_get.return_value = utils.FakedResponse(content='crash', status_code=500, reason='boum') - resp = app.get(url + '/foo/bar/', status=200) - assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/foo/bar') - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == "error status:500 'boum', content:'crash'" - assert resp.json['data'] == {'json_content': None, 'status_code': 500} + fake_http.set_response(content='crash', status_code=500, reason='boum', method='GET') + resp = app.get(url + '/foo/bar/', status=200) + assert fake_http.last_request.url.endswith('/solisapi/referentiels/foo/bar') + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == "error status:500 'boum', content:'crash'" + assert resp.json['data'] == {'json_content': None, 'status_code': 500} def test_unflat_dict(): assert unflat({'foo': 'bar', 'two_foo': 'one', 'two_bar': 'two'}) == {'foo': 'bar', 'two': {'foo': 'one', 'bar': 'two'}} -def test_solis_apa_integration(app, solis): +def test_solis_apa_integration(fake_http, app, solis): api = ApiUser.objects.create(username='all', keytype='', key='') obj_type = ContentType.objects.get_for_model(solis) AccessRight.objects.create(codename='can_access', apiuser=api, resource_type=obj_type, resource_pk=solis.pk) - with mock.patch('passerelle.utils.Request.post') as requests_post: - def integration_ok(*args, **kwargs): - return utils.FakedResponse(content='', status_code=204) - requests_post.return_value = utils.FakedResponse(content='', status_code=204) - # requests_post.side_effect = [utils.FakedResponse(content='', status_code=204)] - url = utils.generic_endpoint_url('solis', 'apa-integration', slug=solis.slug) - - demande = { - "beneficiaire_demande_aide": "APAD", - "beneficiaire_demande_dateDepot": "2018-02-09", - "beneficiaire_etatCivil_civilite": "M", - "beneficiaire_etatCivil_contact_courriel": "benef@yopmail.com", - "conjoint_nom": "Conjnom", - "conjoint_prenom": "Conjprenom", - } - - resp = app.post_json(url, params=demande, status=200) - - requests_post.assert_called_once() - assert requests_post.call_args[0][0].endswith('/solisapi/asg/apa/integrationDemandeApa') - assert requests_post.call_args[1]['json']['demandeApa']['beneficiaire']['demande']['aide'] == 'APAD' - assert requests_post.call_args[1]['json']['demandeApa']['conjoint']['nom'] == 'Conjnom' - assert requests_post.call_args[1]['json']['demandeApa'] == unflat(demande) - assert resp.json['err'] == 0 - assert resp.json['data'] is None - - # don't send "conjoint" dict to Solis - requests_post.reset_mock() - demande['del:conjoint'] = True - resp = app.post_json(url, params=demande, status=200) - requests_post.assert_called_once() - assert 'conjoint' not in requests_post.call_args[1]['json']['demandeApa'] - assert resp.json['err'] == 0 + def integration_ok(*args, **kwargs): + return utils.FakedResponse(content='', status_code=204) - # send "conjoint" dict to Solis - requests_post.reset_mock() - demande['del:conjoint'] = False - resp = app.post_json(url, params=demande, status=200) - requests_post.assert_called_once() - assert requests_post.call_args[1]['json']['demandeApa']['conjoint']['nom'] == 'Conjnom' - assert resp.json['err'] == 0 + # requests_post.side_effect = [utils.FakedResponse(content='', status_code=204)] + url = utils.generic_endpoint_url('solis', 'apa-integration', slug=solis.slug) - # add files - requests_post.reset_mock() - requests_post.side_effect = [ - utils.FakedResponse(content='{"id": "foo", "nbFichiersAcceptes": 3}', status_code=200), - utils.FakedResponse(content='', status_code=204)] - demande['file:etat_civil_001.pdf'] = { - 'content': 'JVBERmZha2U=', - 'content_type': 'application/pdf', - 'filename': 'whatever.pdf', - } - demande['file:etat_civil_002.pdf'] = { - # jpeg, will be converted to PDF - 'content': '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCw' - 'kJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=', - 'content_type': 'image/jpeg', - 'filename': 'image.jpg', - } - demande['file:etat_civil_003.pdf'] = { - # transparent png (RGBA), will be converted to RGB and then PDF - 'content': 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQ' - 'ABDQottAAAAABJRU5ErkJggg==', - 'content_type': 'image/png', - 'filename': 'image.png', - } - demande['file:etat_civil_004.pdf'] = { - 'content': 'Y29pbg==', # bad content, conversion will fail - 'content_type': 'image/png', - 'filename': 'image.png', - } - demande['file:etat_civil_005.pdf'] = { - 'content': 'Y29pbg==', - 'content_type': 'video/mp4', # not a image, cannot convert - 'filename': 'video.mp4', - } - demande['file:etat_civil_006.pdf'] = { - 'content_type': 'video/mp4', # no content, cannot convert - } - demande['file:etat_civil_007.pdf'] = None - resp = app.post_json(url, params=demande, status=200) - assert requests_post.call_count == 2 # post files + demandeApa - sent_files = requests_post.call_args_list[0][1]['files'] - assert len(sent_files) == 3 - for file_ in sent_files: - assert file_[1][1].startswith('%PDF') - # file entries are removed from demandeApa JSON dict - assert 'file:etat_civil_001.pdf' not in requests_post.call_args[1]['json']['demandeApa'] - assert 'file:etat_civil_002.pdf' not in requests_post.call_args[1]['json']['demandeApa'] - assert resp.json['err'] == 0 - assert resp.json['data'] is None - assert resp.json['files_sent'] == {'id': 'foo', 'nbFichiersAcceptes': 3} - assert set(resp.json['files_failed_pdf_conversion']) == set(['etat_civil_004.pdf', - 'etat_civil_005.pdf', - 'etat_civil_006.pdf']) - - # invalid inputs - requests_post.reset_mock() - resp = app.post_json(url, params=['not', 'a', 'dict'], status=400) - requests_post.assert_not_called() - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == 'payload is not a JSON dict' - resp = app.post(url, params='coin', status=400) - requests_post.assert_not_called() - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == 'payload is not a JSON object' - - # bad file - requests_post.reset_mock() - requests_post.side_effect = [ - utils.FakedResponse(content='{"id": "foo", "nbFichiersAcceptes": 0}', status_code=200), - utils.FakedResponse(content='', status_code=204)] - resp = app.post_json(url, params=demande, status=200) - requests_post.assert_called_once() # don't try to post request - assert resp.json['err'] == 1 - assert resp.json['err_desc'] == 'fail to send all files' - assert resp.json['data'] == {'id': 'foo', 'nbFichiersAcceptes': 0} - - # error on sending file - requests_post.reset_mock() - requests_post.side_effect = [ - utils.FakedResponse(content='{"error": 1}', status_code=500), - utils.FakedResponse(content='', status_code=204)] - resp = app.post_json(url, params=demande, status=200) - requests_post.assert_called_once() # don't try to post request - assert resp.json['err'] == 1 - assert resp.json['err_desc'].startswith('error status:500') + demande = { + "beneficiaire_demande_aide": "APAD", + "beneficiaire_demande_dateDepot": "2018-02-09", + "beneficiaire_etatCivil_civilite": "M", + "beneficiaire_etatCivil_contact_courriel": "benef@yopmail.com", + "conjoint_nom": "Conjnom", + "conjoint_prenom": "Conjprenom", + } + + fake_http.set_response(content='', status_code=204, method='POST') + resp = app.post_json(url, params=demande, status=200) + + assert fake_http.last_request.url.endswith('/solisapi/asg/apa/integrationDemandeApa') + assert fake_http.last_request.json['demandeApa']['beneficiaire']['demande']['aide'] == 'APAD' + assert fake_http.last_request.json['demandeApa']['conjoint']['nom'] == 'Conjnom' + assert fake_http.last_request.json['demandeApa'] == unflat(demande) + assert resp.json['err'] == 0 + assert resp.json['data'] is None + + # don't send "conjoint" dict to Solis + demande['del:conjoint'] = True + fake_http.set_response(content='', status_code=204, method='POST') + resp = app.post_json(url, params=demande, status=200) + assert 'conjoint' not in fake_http.last_request.json['demandeApa'] + assert resp.json['err'] == 0 + + # send "conjoint" dict to Solis + demande['del:conjoint'] = False + fake_http.set_response(content='', status_code=204, method='POST') + resp = app.post_json(url, params=demande, status=200) + assert fake_http.last_request.json['demandeApa']['conjoint']['nom'] == 'Conjnom' + assert resp.json['err'] == 0 + + # add files + demande['file:etat_civil_001.pdf'] = { + 'content': 'JVBERmZha2U=', + 'content_type': 'application/pdf', + 'filename': 'whatever.pdf', + } + demande['file:etat_civil_002.pdf'] = { + # jpeg, will be converted to PDF + 'content': '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCw' + 'kJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=', + 'content_type': 'image/jpeg', + 'filename': 'image.jpg', + } + demande['file:etat_civil_003.pdf'] = { + # transparent png (RGBA), will be converted to RGB and then PDF + 'content': 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQ' + 'ABDQottAAAAABJRU5ErkJggg==', + 'content_type': 'image/png', + 'filename': 'image.png', + } + demande['file:etat_civil_004.pdf'] = { + 'content': 'Y29pbg==', # bad content, conversion will fail + 'content_type': 'image/png', + 'filename': 'image.png', + } + demande['file:etat_civil_005.pdf'] = { + 'content': 'Y29pbg==', + 'content_type': 'video/mp4', # not a image, cannot convert + 'filename': 'video.mp4', + } + demande['file:etat_civil_006.pdf'] = { + 'content_type': 'video/mp4', # no content, cannot convert + } + demande['file:etat_civil_007.pdf'] = None + + fake_http.set_response(content='{"id": "foo", "nbFichiersAcceptes": 3}', status_code=200, method='POST') + fake_http.add_response(content='', status_code=204, method='POST') + resp = app.post_json(url, params=demande, status=200) + sent_files = fake_http.requests[0].FILES.getlist('files') + assert len(sent_files) == 3 + for file_ in sent_files: + assert file_.read().startswith('%PDF') + # file entries are removed from demandeApa JSON dict + assert 'file:etat_civil_001.pdf' not in fake_http.last_request.json['demandeApa'] + assert 'file:etat_civil_002.pdf' not in fake_http.last_request.json['demandeApa'] + assert resp.json['err'] == 0 + assert resp.json['data'] is None + assert resp.json['files_sent'] == {'id': 'foo', 'nbFichiersAcceptes': 3} + assert set(resp.json['files_failed_pdf_conversion']) == set(['etat_civil_004.pdf', + 'etat_civil_005.pdf', + 'etat_civil_006.pdf']) + + # invalid inputs + fake_http.reset() + resp = app.post_json(url, params=['not', 'a', 'dict'], status=400) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'payload is not a JSON dict' + resp = app.post(url, params='coin', status=400) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'payload is not a JSON object' + + # bad file + fake_http.set_response(content='{"id": "foo", "nbFichiersAcceptes": 0}', status_code=200, method='POST') + resp = app.post_json(url, params=demande, status=200) + assert resp.json['err'] == 1 + assert resp.json['err_desc'] == 'fail to send all files' + assert resp.json['data'] == {'id': 'foo', 'nbFichiersAcceptes': 0} + + # error on sending file + fake_http.set_response(content='{"error": 1}', status_code=500, method='POST') + resp = app.post_json(url, params=demande, status=200) + assert resp.json['err'] == 1 + assert resp.json['err_desc'].startswith('error status:500') diff --git a/tests/test_vivaticket.py b/tests/test_vivaticket.py index 6ba08a5..62b0234 100644 --- a/tests/test_vivaticket.py +++ b/tests/test_vivaticket.py @@ -201,116 +201,108 @@ def connector(db): url='http://example.net/vivaticket')) -@mock.patch('passerelle.utils.Request.post') -def test_get_api_key(mocked_post, app, connector): +def test_get_api_key(fake_http, app, connector): + fake_http.set_response(content=ERROR_RESPONSE, status_code=400) with pytest.raises(APIError): - mocked_post.return_value = utils.FakedResponse(content=ERROR_RESPONSE, ok=False) connector.get_apikey() - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, ok=True) + + fake_http.set_response(content=KEY_RESPONSE, status_code=200) connector.get_apikey() - assert mocked_post.call_count == 2 - assert "Connect/PostConnect" in mocked_post.call_args[0][0] - assert mocked_post.call_args[1]['json']['Login'] == 'foo' - assert mocked_post.call_args[1]['json']['Password'] == 'bar' + assert "Connect/PostConnect" in fake_http.last_request.url + assert fake_http.last_request.json['Login'] == 'foo' + assert fake_http.last_request.json['Password'] == 'bar' # make sure the key from cache is used connector.get_apikey() - assert mocked_post.call_count == 2 + + fake_http.set_response(content=KEY_RESPONSE, status_code=200) connector.get_apikey(True) - assert mocked_post.call_count == 3 -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.get') -def test_get_events(mocked_get, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=EVENTS_RESPONSE, status_code=200) - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200) +def test_get_events(fake_http, app, connector): + fake_http.set_response(content=KEY_RESPONSE, status_code=200) + fake_http.add_response(content=EVENTS_RESPONSE, status_code=200) result = utils.endpoint_get('/vivaticket/test/events', app, connector, 'events') - assert mocked_post.call_count == 1 - assert mocked_get.call_args[1]['params']['key'] == "86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074" + assert fake_http.last_request.GET['key'] == "86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074" assert 'data' in result.json for item in result.json['data']: assert 'id' in item assert 'text' in item -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.get') -def test_get_events_with_expired_key(mocked_get, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=EVENTS_RESPONSE, status_code=401) - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200) +def test_get_events_with_expired_key(fake_http, app, connector): + fake_http.set_response(content=KEY_RESPONSE, status_code=200) + fake_http.add_response(content=EVENTS_RESPONSE, status_code=401) + fake_http.add_response(content=KEY_RESPONSE, status_code=200) + fake_http.add_response(content=EVENTS_RESPONSE, status_code=200) utils.endpoint_get('/vivaticket/test/events', app, connector, 'events') - assert mocked_post.call_count == 2 -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.get') -def test_get_rooms(mocked_get, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=ROOMS_RESPONSE, status_code=200) - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200) +def test_get_rooms(fake_http, app, connector): + fake_http.set_response(content=KEY_RESPONSE, status_code=200) + fake_http.add_response(content=ROOMS_RESPONSE, status_code=200) result = utils.endpoint_get('/vivaticket/test/rooms', app, connector, 'rooms') - assert mocked_get.call_args[1]['params']['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' + assert fake_http.last_request.GET['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' assert 'data' in result.json for item in result.json['data']: assert 'id' in item assert 'text' in item + fake_http.set_response(content=ROOMS_RESPONSE, status_code=200) result = utils.endpoint_get('/vivaticket/test/rooms', app, connector, 'rooms', params={'event': '02'}) - assert mocked_get.call_args[1]['params']['eventCategory'] == '02' + assert fake_http.last_request.GET['eventCategory'] == '02' -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.get') -def test_get_themes(mocked_get, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=ROOMS_RESPONSE, status_code=200) - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200) +def test_get_themes(fake_http, app, connector): + fake_http.set_response(content=KEY_RESPONSE, status_code=200) + fake_http.add_response(content=ROOMS_RESPONSE, status_code=200) result = utils.endpoint_get('/vivaticket/test/themes', app, connector, 'themes') - assert mocked_get.call_args[1]['params']['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' + assert fake_http.requests[-2].method == 'POST' + assert fake_http.last_request.method == 'GET' + assert fake_http.last_request.GET['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' assert 'data' in result.json for item in result.json['data']: assert 'id' in item assert 'text' in item + fake_http.add_response(content=ROOMS_RESPONSE, status_code=200) result = utils.endpoint_get('/vivaticket/test/themes', app, connector, 'themes', params={'room': '001'}) - assert mocked_get.call_args[1]['params']['room'] == '001' + assert fake_http.last_request.GET['room'] == '001' -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.get') -def test_get_or_create_contact(mocked_get, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, ok=True) - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200) +def test_get_or_create_contact(fake_http, app, connector): + fake_http.set_response(content=KEY_RESPONSE, status_code=200, method='POST') + fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET') assert connector.get_or_create_contact('foo@example.com') == {'InternalCode': '0000000273'} - mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, ok=False) - mocked_post.return_value = utils.FakedResponse( - content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}', - status_code=200) + fake_http.add_response(content=CONTACT_RESPONSE, status_code=404, method='GET') + fake_http.add_response(content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}', + status_code=200, + method='POST') connector.get_or_create_contact('foo@example.com') - assert mocked_post.call_args[1]['json']['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' - assert mocked_post.call_args[1]['json']['Contact']['Email'] == 'foo@example.com' - assert mocked_post.call_args[1]['json']['Contact']['ExternalCode'] == 'b48def645758b95537d4' + assert fake_http.last_request.json['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' + assert fake_http.last_request.json['Contact']['Email'] == 'foo@example.com' + assert fake_http.last_request.json['Contact']['ExternalCode'] == 'b48def645758b95537d4' -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.put') -@mock.patch('passerelle.utils.Request.get') -def test_get_and_update_contact(mocked_get, mocked_put, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, ok=True) - mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200) +def test_get_and_update_contact(fake_http, app, connector): + fake_http.set_response(content=KEY_RESPONSE, status_code=200, method='POST') + fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET') assert connector.get_or_create_contact('foo@example.com') == {'InternalCode': '0000000273'} - mocked_put.return_value = utils.FakedResponse( - content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}', - status_code=200) + + fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET') + fake_http.add_response(content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}', + status_code=200, + method='PUT') connector.get_or_create_contact('bar@example.com', 'bar') - assert mocked_put.call_args[1]['params']['id'] == '0000000273' - assert mocked_put.call_args[1]['json']['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' - assert mocked_put.call_args[1]['json']['Contact']['Email'] == 'bar@example.com' + assert fake_http.last_request.method == 'PUT' + assert fake_http.last_request.GET['id'] == '0000000273' + assert fake_http.last_request.json['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' + assert fake_http.last_request.json['Contact']['Email'] == 'bar@example.com' -@mock.patch('passerelle.utils.Request.post') -@mock.patch('passerelle.utils.Request.get') -def test_book(mocked_get, mocked_post, app, connector): - mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, status_code=200) +def test_book(fake_http, app, connector): url = utils.generic_endpoint_url('vivaticket', 'book') payload = {'id': 'formid', 'email': 'foo@example.com'} + response = app.post_json(url, params=payload, status=400) + payload['datetime'] = '2019-01-15' payload['event'] = '01' payload['theme'] = '001' @@ -319,16 +311,14 @@ def test_book(mocked_get, mocked_post, app, connector): response = app.post_json(url, params=payload, status=400) assert "does not match '^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}$" in response.json['err_desc'] payload['datetime'] = '2019-01-15T10:00' - # first return the API key, then the result of the booking creation - mocked_post.side_effect = [ - utils.FakedResponse(content=KEY_RESPONSE, status_code=200), - utils.FakedResponse(content=BOOKING_RESPONSE), - Exception(), - ] + + fake_http.set_response(content=KEY_RESPONSE, status_code=200, method='POST') + fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET') + fake_http.add_response(content=BOOKING_RESPONSE, status_code=200, method='POST') response = app.post_json(url, params=payload) - assert mocked_post.call_args[1]['json']['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' - assert mocked_post.call_args[1]['json']['Booking']['externalCode'] == 'formid' - assert mocked_post.call_args[1]['json']['Booking']['startDateTime'] == '2019-01-15T10:00' - assert mocked_post.call_args[1]['json']['Booking']['endDateTime'] == '2019-01-15T10:00' - assert mocked_post.call_args[1]['json']['Booking']['contact'] == {'InternalCode': '0000000273'} + assert fake_http.last_request.json['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074' + assert fake_http.last_request.json['Booking']['externalCode'] == 'formid' + assert fake_http.last_request.json['Booking']['startDateTime'] == '2019-01-15T10:00' + assert fake_http.last_request.json['Booking']['endDateTime'] == '2019-01-15T10:00' + assert fake_http.last_request.json['Booking']['contact'] == {'InternalCode': '0000000273'} assert response.json['data']['bookingCode'] == 'II0000013' -- 2.20.1