Projet

Général

Profil

0005-let-requests-handle-HTTP-errors-31114.patch

Benjamin Dauvergne, 07 mars 2019 00:30

Télécharger (158 ko)

Voir les différences:

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(-)
passerelle/apps/api_particulier/models.py
73 73
                url,
74 74
                headers=headers,
75 75
                **kwargs)
76
        except requests.HTTPError as e:
77
            msg = u'API-particulier platform "%s" request error %s' % (self.platform, e)
78
            try:
79
                data = e.response.json()
80
                if data.get('error') == 'not_found':
81
                    return {
82
                        'err': 1,
83
                        'err_desc': data.get('message', 'not_found'),
84
                    }
85
                msg += ': %s' % data
86
            except ValueError:
87
                pass
88
            raise APIError(
89
                msg,
90
                (self.platform, e),
91
                data={
92
                    'platform': self.platform,
93
                    'error': six.text_type(e),
94
                })
76 95
        except requests.RequestException as e:
77 96
            raise APIError(
78
                u'API-particulier platform "%s" connection error: %s' %
79
                (self.platform, response.status_code),
97
                u'API-particulier platform "%s" request error: %s' %
98
                (self.platform, e),
80 99
                data={
81 100
                    'platform': self.platform,
82 101
                    'error': six.text_type(e),
......
94 113
                    'platform': self.platform,
95 114
                    'content': content,
96 115
                })
97
        if response.status_code != 200:
98
            if data.get('error') == 'not_found':
99
                return {
100
                    'err': 1,
101
                    'err_desc': data.get('message', 'not-found'),
102
                }
103
            raise APIError(
104
                u'API-particulier platform "%s" returned a non 200 status %s: %s' %
105
                (self.platform, response.status_code, data),
106
                data={
107
                    'status_code': response.status_code,
108
                    'platform': self.platform,
109
                    'content': data,
110
                })
111 116
        return {
112 117
            'err': 0,
113 118
            'data': data,
passerelle/apps/arcgis/models.py
16 16

  
17 17
import urlparse
18 18

  
19
import requests
20

  
19 21
from django.db import models
20 22
from django.template import Template, Context
21 23
from django.utils.translation import ugettext_lazy as _
......
113 115
        if 'distance' in params and 'units' not in params:
114 116
            params['units'] = 'esriSRUnit_Meter'
115 117

  
116
        response = self.requests.get(url, params=params)
118
        try:
119
            response = self.requests.get(url, params=params)
120
        except requests.RequestException as e:
121
            raise ArcGISError('ArcGIS request error %s' % e)
117 122

  
118 123
        # errors
119
        if response.status_code // 100 != 2:
120
            raise ArcGISError('ArcGIS returned status code %s' % response.status_code)
121 124
        try:
122 125
            infos = response.json()
123 126
        except (ValueError,):
passerelle/apps/arpege_ecp/models.py
17 17
import json
18 18
import urlparse
19 19

  
20
import requests
21

  
20 22
from django.db import models
21 23
from django.utils.translation import ugettext_lazy as _
22 24
from django.utils.dateparse import parse_date, parse_time
......
47 49

  
48 50
    def get_access_token(self, NameID):
49 51
        url = urlparse.urljoin(self.webservice_base_url, 'LoginParSubOIDC')
50
        response = self.requests.post(url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key),
51
                                      json={'subOIDC': NameID})
52
        if response.status_code // 100 != 2:
53
            raise APIError(u'HTTP error: %s' % response.status_code)
52
        try:
53
            response = self.requests.post(url, auth=HawkAuth(self.hawk_auth_id, self.hawk_auth_key),
54
                                          json={'subOIDC': NameID})
55
        except requests.RequestException as e:
56
            raise APIError(u'Request error: %s' % e)
54 57
        try:
55 58
            result = response.json()
56 59
        except ValueError:
......
69 72
        url = urlparse.urljoin(self.webservice_base_url, 'DemandesUsager')
70 73
        params = {'scope': 'data_administratives'}
71 74
        auth = HawkAuth(self.hawk_auth_id, self.hawk_auth_key, ext=access_token)
72
        response = self.requests.get(url, params=params, auth=auth)
75
        try:
76
            response = self.requests.get(url, params=params, auth=auth)
77
        except requests.RequestException as e:
78
            raise APIError(u'Request error: %s' % e)
73 79
        data = []
74
        if response.status_code // 100 != 2:
75
            raise APIError(u'HTTP error: %s' % response.status_code)
76 80
        try:
77 81
            result = response.json()
78 82
        except ValueError:
passerelle/apps/base_adresse/models.py
5 5
import unicodedata
6 6

  
7 7
import six
8
import requests
8 9

  
9 10
from django.db import connection, models
10 11
from django.db.models import Q
......
161 162
                departments.add(zipcode[:2])
162 163

  
163 164
        for department in departments:
164
            ban_file = self.requests.get(
165
                'http://bano.openstreetmap.fr/BAN_odbl/BAN_odbl_{}-json.bz2'.format(department))
166
            if ban_file.status_code != 200:
165
            try:
166
                ban_file = self.requests.get(
167
                    'http://bano.openstreetmap.fr/BAN_odbl/BAN_odbl_{}-json.bz2'.format(department))
168
            except requests.HTTPError:
167 169
                continue
170
            except requests.RequestException:
171
                raise
168 172

  
169 173
            for line in bz2.decompress(ban_file.content).splitlines():
170 174
                street_info = json.loads(line)
passerelle/apps/bdp/models.py
32 32
        options = {}
33 33
        if self.keystore:
34 34
            options['cert'] = (self.keystore.path, self.keystore.path)
35
        if not self.verify_cert:
36
            options['verify'] = False
35
        options['verify'] = self.verify_cert
37 36
        if self.username:
38 37
            options['auth'] = HTTPBasicAuth(self.username, self.password)
39 38
        return options
40 39

  
41 40
    def get_api(self, endpoint, **params):
42 41
        options = self.requests_options()
43
        return requests.get(self.service_url + '/api/' + endpoint,
44
                params=params, **options).json()
42
        return self.requests.get(self.service_url + '/api/' + endpoint, params=params, **options).json()
45 43

  
46 44
    def post_api(self, endpoint, obj):
47 45
        data = json.dumps(obj)
48 46
        headers = {'Content-Type': 'application/json'}
49 47
        options = self.requests_options()
50
        request = requests.post(
48
        request = self.requests.post(
51 49
            self.service_url + '/api/' + endpoint,
52
            data=data, headers=headers, **options)
50
            data=data, headers=headers,
51
            raise_for_status=False,
52
            raise_for_redirect=False,
53
            **options)
53 54
        result = {
54 55
            'status_code': request.status_code,
55 56
            'x_request_id': request.headers.get('x-request-id'),
passerelle/apps/okina/models.py
16 16

  
17 17
import json
18 18

  
19
import requests
20

  
19 21
from django.db import models
20 22
from django.http import HttpResponse
21 23
from django.utils.translation import ugettext_lazy as _
......
42 44
        headers = {}
43 45
        if result_is_json:
44 46
            headers['Accept'] = 'application/json'
45
        if payload is None:
46
            result = self.requests.get(url, auth=auth, headers=headers)
47
        else:
48
            headers['Content-Type'] = 'application/json'
49
            data = json.dumps(payload)
50
            result = self.requests.post(url, data=data, auth=auth, headers=headers)
51
        if result.status_code in (401, 403):
52
            raise APIError(result.json()['message'], http_status=500)
47
        try:
48
            if payload is None:
49
                result = self.requests.get(url, auth=auth, headers=headers)
50
            else:
51
                headers['Content-Type'] = 'application/json'
52
                data = json.dumps(payload)
53
                result = self.requests.post(url, data=data, auth=auth, headers=headers)
54
        except requests.HTTPError as e:
55
            if e.response.status_code in (401, 403):
56
                raise APIError(e.response.json()['message'], http_status=500)
57
            result = e.response
53 58
        if result_is_json:
54 59
            return result.json()
55 60
        else:
passerelle/apps/opengis/models.py
19 19
from HTMLParser import HTMLParser
20 20

  
21 21
import six
22
import requests
22 23

  
23 24
import pyproj
24 25

  
......
302 303
            'OUTPUTFORMAT': 'json',
303 304
            'CQL_FILTER': cql_filter
304 305
        }
305
        response = self.requests.get(self.wfs_service_url, params=params)
306
        if not response.ok:
307
            raise APIError('Webservice returned status code %s' % response.status_code)
306
        try:
307
            response = self.requests.get(self.wfs_service_url, params=params)
308
        except requests.HTTPError as e:
309
            raise APIError('Webservice returned status code %s' % e.response.status_code)
308 310
        closest_feature = {}
309 311
        min_delta = None
310 312
        for feature in response.json().get('features'):
passerelle/apps/solis/models.py
19 19
import re
20 20
import unicodedata
21 21

  
22
import requests
23

  
22 24
from django.db import models
23 25
from django.template.loader import get_template
24 26
from django.utils.translation import ugettext_lazy as _
......
105 107
    def request(self, endpoint, data=None, files=None):
106 108
        url = self.service_url + endpoint
107 109
        headers = {'Accept': 'application/json'}
108
        if data is not None:
109
            response = self.requests.post(url, json=data, headers=headers)
110
        elif files is not None:
111
            response = self.requests.post(url, files=files, headers=headers)
112
        else:
113
            response = self.requests.get(url, headers=headers)
114

  
115
        if response.status_code // 100 != 2:
110
        try:
111
            if data is not None:
112
                response = self.requests.post(url, json=data, headers=headers)
113
            elif files is not None:
114
                response = self.requests.post(url, files=files, headers=headers)
115
            else:
116
                response = self.requests.get(url, headers=headers)
117
        except requests.HTTPError as e:
116 118
            try:
117
                json_content = response.json()
119
                json_content = e.response.json()
118 120
            except ValueError:
119 121
                json_content = None
120 122
            raise APIError('error status:%s %r, content:%r' %
121
                           (response.status_code, response.reason, response.content[:1024]),
122
                           data={'status_code': response.status_code,
123
                           (e.response.status_code, e.response.reason, e.response.content[:1024]),
124
                           data={'status_code': e.response.status_code,
123 125
                                 'json_content': json_content})
124 126

  
125 127
        if response.status_code == 204:  # 204 No Content
passerelle/apps/vivaticket/models.py
17 17
import hashlib
18 18
import urlparse
19 19

  
20
import requests
21

  
20 22
from django.core.cache import cache
21 23
from django.db import models
22 24
from django.utils.translation import ugettext_lazy as _
......
86 88
        return cls._meta.verbose_name
87 89

  
88 90
    def check_status(self):
89
        response = self.requests.get(urlparse.urljoin(self.url, 'Settings/GetVersion'))
90
        response.raise_for_status()
91
        self.requests.get(urlparse.urljoin(self.url, 'Settings/GetVersion'))
91 92

  
92 93
    def get_apikey(self, renew=False):
93 94
        cache_key_name = 'vivaticket-%s-key' % self.id
......
95 96
            return cache.get(cache_key_name)
96 97
        url = urlparse.urljoin(self.url, 'Connect/PostConnect')
97 98
        payload = {'Login': self.login, 'Password': self.password}
98
        response = self.requests.post(url, json=payload)
99
        if not response.ok:
100
            raise APIError(response.content)
99
        try:
100
            response = self.requests.post(url, json=payload)
101
        except requests.HTTPError as e:
102
            raise APIError(e.response.content)
101 103
        api_key = response.json()['Key']
102 104
        # api key is available for 30 minutes
103 105
        cache.set(cache_key_name, api_key, 60 * 30)
......
107 109
        url = urlparse.urljoin(self.url, endpoint)
108 110
        params = {'key': self.get_apikey()}
109 111
        params.update(kwargs)
110
        response = self.requests.get(url, params=params)
111
        # api key is expired
112
        if response.status_code == 401:
113
            params['key'] = self.get_apikey(True)
114
        else:
115
            return response
116
        return self.requests.get(url, params=params)
112
        try:
113
            return self.requests.get(url, params=params)
114
        except requests.HTTPError as e:
115
            # api key is expired
116
            if e.response.status_code == 401:
117
                params['key'] = self.get_apikey(True)
118
                return self.requests.get(url, params=params)
119
            return e.response
117 120

  
118 121
    def post(self, endpoint, payload):
119 122
        url = urlparse.urljoin(self.url, endpoint)
120 123
        payload.update({'Key': self.get_apikey()})
121
        response = self.requests.post(url, json=payload)
122
        # api key is expired
123
        if response.status_code == 401:
124
            payload['key'] = self.get_apikey(True)
124
        try:
125 125
            return self.requests.post(url, json=payload)
126
        return response
126
        except requests.HTTPError as e:
127
            # api key is expired
128
            if e.response.status_code == 401:
129
                payload['key'] = self.get_apikey(True)
130
                return self.requests.post(url, json=payload)
131
            raise
127 132

  
128 133
    def get_setting(self, endpoint, **kwargs):
129 134
        response = self.get(endpoint, **kwargs)
passerelle/contrib/gdema/models.py
18 18
import json
19 19
import re
20 20

  
21
import requests
22

  
21 23
from django.db import models
22 24
from django.utils.timezone import get_fixed_timezone, utc, is_naive, make_aware
23 25
from django.utils.dateparse import parse_date, parse_datetime
......
162 164
            auth = None
163 165
        headers = {}
164 166
        headers['Accept'] = 'application/json'
165
        if payload is None:
166
            result = self.requests.get(url, auth=auth, headers=headers)
167
        else:
168
            headers['Content-Type'] = 'application/json'
169
            data = json.dumps(payload)
170
            result = self.requests.post(url, data=data, auth=auth, headers=headers)
171
        if result.status_code < 200 or result.status_code >= 300:
172
            raise APIError('GDEMA returns HTTP status %s' % result.status_code)
167
        try:
168
            if payload is None:
169
                result = self.requests.get(url, auth=auth, headers=headers)
170
            else:
171
                headers['Content-Type'] = 'application/json'
172
                data = json.dumps(payload)
173
                result = self.requests.post(url, data=data, auth=auth, headers=headers)
174
        except requests.RequestException as e:
175
            raise APIError('GDEMA request failed %s' % e)
173 176
        return result.json()
174 177

  
175 178
    def get_services(self):
passerelle/contrib/greco/models.py
23 23
from email.mime.multipart import MIMEMultipart
24 24
from email.mime.text import MIMEText
25 25

  
26
import requests
27

  
26 28
from suds.client import Client
27 29
from suds.transport import Reply
28 30
from suds.transport.http import HttpAuthenticated
......
155 157
                request.headers['Authorization'] = self.instance.get_token()
156 158
                resp = self.instance.requests.post(request.url, data=request.message,
157 159
                                                   headers=request.headers,
158
                                                   verify=self.instance.verify_cert)
160
                                                   verify=self.instance.verify_cert,
161
                                                   raise_for_status=False,
162
                                                   raise_for_redirect=False)
159 163
                if resp.status_code == 401:
160 164
                    # ask for a new token, and retry
161 165
                    request.headers['Authorization'] = self.instance.get_token(renew=True)
passerelle/contrib/mdph13/models.py
46 46

  
47 47
    def url_get(self, *args, **kwargs):
48 48
        try:
49
            response = None
50 49
            response = self.requests.get(*args, **kwargs)
51
            response.raise_for_status()
52 50
        except requests.RequestException as e:
53 51
            data = {'exception': six.text_type(e)}
52
            response = getattr(e, 'response', None)
54 53
            if response is not None:
55 54
                try:
56 55
                    if response.json():
passerelle/contrib/planitech/models.py
21 21
import urlparse
22 22
import uuid
23 23

  
24
import requests
25

  
24 26
from django.core.cache import cache
25 27
from django.db import models, transaction
26 28
from django.utils import dateformat
27 29
from django.utils import dateparse
28 30
from django.utils.translation import ugettext_lazy as _
29 31
from jsonfield import JSONField
30
from requests.exceptions import RequestException
31 32

  
32 33
from passerelle.base.models import BaseResource
33 34
from passerelle.contrib.planitech import mste
......
208 209
        kwargs = {}
209 210
        if params is not None:
210 211
            kwargs['data'] = json.dumps(mste.encode(params))
211
        response = session_meth(urlparse.urljoin(self.url, endpoint), **kwargs)
212
        if response.status_code != 200:
213
            error_msg = "Planitech error %s" % response.status_code
212
        try:
213
            response = session_meth(urlparse.urljoin(self.url, endpoint), **kwargs)
214
        except requests.HTTPError as e:
215
            error_msg = "Planitech error %s" % e.response.status_code
214 216
            try:
215
                data = mste.decode(response.json())
217
                data = mste.decode(e.response.json())
218
            except TypeError:
219
                pass
220
            else:
216 221
                if hasattr(data, 'get'):
217 222
                    error = data.get('errors')
218 223
                    if error:
219 224
                        error_msg += " - %s" % error
220
            except TypeError:
221
                pass
222 225
            raise APIError(error_msg)
223 226
        return mste.decode(response.json())
224 227

  
......
317 320
            tmp_hash = compute_hash(self.password, hardness1, salt1)
318 321
            hash_pass = compute_hash(tmp_hash, hardness2, salt2)
319 322
            response = self.requests.get(auth_url, headers={'MH-PASSWORD': hash_pass})
320
            response.raise_for_status()
321 323
            # the last response should have set a cookie which will be used for authentication
322
        except RequestException as e:
323
            raise APIError("Authentication to Planitech failed: %s" % str(e))
324
        except requests.RequestException as e:
325
            raise APIError("Authentication to Planitech failed: %s" % e)
324 326

  
325 327
    @endpoint(
326 328
        perm='can_access',
passerelle/contrib/solis_apa/models.py
18 18
import json
19 19
import urlparse
20 20

  
21
import requests
22

  
21 23
from django.db import models
22 24
from django.core.cache import cache
23 25
from django.core.urlresolvers import reverse
......
100 102
                    }
101 103
        data = json.dumps(data)
102 104

  
103
        response = self.requests.post(url, data=data, headers=HEADERS)
104
        if response.status_code != 200:
105
            raise ValueError('referential ws: error code %d' % response.status_code)
105
        try:
106
            response = self.requests.post(url, data=data, headers=HEADERS)
107
        except requests.RequestException as e:
108
            raise ValueError('referential request failed %s' % e)
106 109

  
107 110
        ret = self._check_requests_response(response)
108 111

  
......
123 126
        url = self.get_resource_url(uri)
124 127
        name = config['block']['name'].lower()
125 128
        data = json.dumps(conciliation.conciliation_payload(config, **data))
126
        response = self.requests.post(url, data=data, headers=HEADERS)
127
        if response.status_code != 200:
128
            raise ValueError('conciliation ws: error code %d' % response.status_code)
129
        try:
130
            response = self.requests.post(url, data=data, headers=HEADERS)
131
        except requests.RequestException as e:
132
            raise ValueError('conciliation ws failed: %s' % e)
129 133

  
130 134
        ret = self._check_requests_response(response)
131 135

  
......
299 303

  
300 304
        payload = suivi.render_payload(suivi_type, datedebut, datefin)
301 305
        payload = json.dumps(payload)
302
        response = self.requests.post(url, data=payload, headers=HEADERS, timeout=300)
303
        if response.status_code != 200:
304
            raise ValueError('suivi %s ws: error code %d' %(suivi_type, response.status_code))
306
        try:
307
            response = self.requests.post(url, data=payload, headers=HEADERS, timeout=300)
308
        except requests.RequestException as e:
309
            raise ValueError('suivi %s ws: error code %e' % (suivi_type, e))
305 310

  
306 311
        response = self._check_requests_response(response)
307 312

  
......
315 320
        data = {'ImportInputWSDemandeApa': integration.build_message(json.loads(data))}
316 321
        data = json.dumps(data)
317 322
        self.logger.debug('Demande APA: %s' % data, extra={'solis_apa_demande': data})
318
        response = self.requests.post(url, data=data, headers=HEADERS)
319
        if response.status_code != 200:
320
            raise ValueError('integration ws: error code %d' %(response.status_code))
323
        try:
324
            response = self.requests.post(url, data=data, headers=HEADERS)
325
        except requests.RequestException as e:
326
            raise ValueError('integration ws: error code %s' % e)
321 327

  
322 328
        response = self._check_requests_response(response)
323 329

  
passerelle/contrib/teamnet_axel/soap.py
53 53
        self.addcredentials(request)
54 54
        resp = self.model.requests.post(
55 55
            request.url, data=request.message,
56
            headers=request.headers, **self.get_requests_kwargs())
56
            headers=request.headers,
57
            raise_for_status=False,
58
            raise_for_redirect=False,
59
            **self.get_requests_kwargs())
57 60
        result = Reply(resp.status_code, resp.headers, resp.content)
58 61
        return result
59 62

  
passerelle/soap.py
44 44

  
45 45
    def send(self, request):
46 46
        resp = requests.post(request.url, data=request.message, headers=request.headers,
47
                             raise_for_status=False, raise_for_redirect=False,
47 48
                             **self.get_requests_kwargs(request))
48 49
        return Reply(resp.status_code, resp.headers, resp.content)
49 50

  
tests/conftest.py
1
from io import BytesIO
2
import json as json_module
3
import base64
4
from django.utils.six.moves.urllib import parse as urlparse
5

  
1 6
import pytest
2 7
from httmock import urlmatch, HTTMock, response
3 8

  
4 9
import django_webtest
5 10

  
11

  
6 12
from django.core.files import File
7 13
from django.core.cache import cache
8 14
from io import BytesIO
......
170 176
            del os.environ['OPENSSL_CONF']
171 177
        else:
172 178
            os.environ['OPENSSL_CONF'] = old_value
179

  
180

  
181
@pytest.fixture
182
def fake_http():
183
    class MockHttp(object):
184
        def __init__(self):
185
            self.requests = []
186
            self.responses = []
187

  
188
        def reset(self):
189
            assert len(self.responses) == len(self.requests), 'all responses have not been consumed'
190
            self.requests = []
191
            self.responses = []
192

  
193
        def set_response(self, *args, **kwargs):
194
            self.reset()
195
            self.add_response(*args, **kwargs)
196

  
197
        def add_response(self, status_code=200, reason=None, content=None,
198
                         json=None, headers=None, method=None, url=None):
199
            response = {'status_code': status_code}
200
            if not content and json:
201
                content = json_module.dumps(json)
202
                headers = headers or {}
203
                for key in headers:
204
                    if key.lower() == 'content-type':
205
                        break
206
                else:
207
                    headers['content-type'] = 'application/json'
208
            if reason:
209
                response['reason'] = reason
210
            if content:
211
                response['content'] = content
212
            if headers:
213
                response['headers'] = headers
214
            if method:
215
                response['request_method'] = method
216
            if url:
217
                response['request_url'] = url
218
            self.responses.append(response)
219

  
220
        @property
221
        def last_request(self):
222
            return self.requests[-1]
223

  
224
        def request_handler(self, url, request):
225
            from django.http.request import QueryDict
226
            from django.http.multipartparser import MultiPartParser
227
            from django.core.files.uploadhandler import TemporaryFileUploadHandler
228

  
229
            idx = len(self.requests)
230

  
231
            url_parsed = urlparse.urlparse(request.url)
232
            request.path = url_parsed.path
233
            request.GET = QueryDict(query_string=url_parsed.query)
234

  
235
            if ('content-type' in request.headers
236
                    and request.headers['content-type'].split(';')[0] == 'application/json'):
237
                request.json = json_module.loads(request.body)
238
            else:
239
                request.json = None
240

  
241
            if ('content-type' in request.headers
242
                    and request.headers['content-type'].split(';')[0] == 'multipart/form-data'):
243
                data = BytesIO(request.body)
244
                META = {'CONTENT_TYPE': request.headers['content-type'], 'CONTENT_LENGTH': request.headers['content-length']}
245
                request.POST, request.FILES = MultiPartParser(META, data, [TemporaryFileUploadHandler()]).parse()
246
            else:
247
                request.POST = QueryDict()
248
                request.FILES = QueryDict()
249

  
250
            if ('authorization' in request.headers
251
                    and request.headers['authorization'].split()[0] == 'Basic'):
252
                header = request.headers['authorization']
253
                request.basic_auth = base64.b64decode(header.split()[1]).split(':')
254
            self.requests.append(request)
255
            assert idx < len(self.responses), ('unexpected request', request)
256
            response = self.responses[idx]
257

  
258
            if 'request_method' in response:
259
                assert request.method == response['request_method']
260

  
261
            if 'request_url' in response:
262
                if hasattr(response['request_url'], 'match'):
263
                    assert response['request_url'].match(request.url)
264
                else:
265
                    assert response['request_url'] == request.url
266

  
267
            return response
268

  
269
    mock_http = MockHttp()
270
    with HTTMock(urlmatch()(mock_http.request_handler)):
271
        yield mock_http
272
        assert len(mock_http.responses) == len(mock_http.requests), 'all responses have not been consumed'
tests/test_api_particulier.py
195 195
                params=params)
196 196
            assert resp.status_code == 200
197 197
            assert resp.json['err'] == 1
198
            assert resp.json['data']['status_code'] == 500
198
            assert '500 Server Error' in resp.json['err_desc']
199 199
        vector = [
200 200
            (['impots_svair', 'impots_adresse'], {
201 201
                'numero_fiscal': 12,
tests/test_arpege_ecp.py
60 60
  }
61 61
}"""
62 62

  
63

  
63 64
@pytest.fixture
64 65
def connector(db):
65
    resource = ArpegeECP.objects.create(slug='test',
66
        webservice_base_url = 'http://arpege.net',
67
        hawk_auth_id = 'id', hawk_auth_key = 'secret')
66
    resource = ArpegeECP.objects.create(
67
        slug='test',
68
        webservice_base_url='http://arpege.net',
69
        hawk_auth_id='id',
70
        hawk_auth_key='secret')
68 71
    return utils.setup_access_rights(resource)
69 72

  
70
@mock.patch('passerelle.utils.Request.get')
71
def test_check_status(mocked_get, connector):
72
    mocked_get.return_value = utils.FakedResponse(content=FAKE_HELLO_RESPONSE, status_code=200)
73

  
74
def test_check_status_ok(fake_http, connector):
75
    fake_http.add_response(200, content=FAKE_HELLO_RESPONSE)
73 76
    resp = connector.check_status()
74 77
    assert resp['data'] == u'InteropAPI v1 (c) Arpège 2017'
75 78

  
76
@mock.patch('passerelle.utils.Request.get')
77
def test_check_status(mocked_get, connector):
79

  
80
def test_check_status_nok(fake_http, connector):
78 81
    hello_response = json.loads(FAKE_HELLO_RESPONSE)
79 82
    del hello_response['Data']
80
    mocked_get.return_value = utils.FakedResponse(content=json.dumps(hello_response), status_code=200)
83
    fake_http.add_response(200, content=json.dumps(hello_response))
81 84
    with pytest.raises(Exception) as error:
82
        resp = connector.check_status()
85
        connector.check_status()
83 86
    assert str(error.value) == 'Invalid credentials'
84 87

  
85
@mock.patch('passerelle.utils.Request.post')
86
def test_get_access_token(mocked_post, connector):
87
    mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
88

  
89
def test_get_access_token(fake_http, connector):
90
    fake_http.add_response(200, content=FAKE_LOGIN_OIDC_RESPONSE)
88 91
    token = connector.get_access_token('nameid')
89 92
    assert token == '0f86353f2d87b8b78aaaacc2ecc763e287ded44f773289a5e336546a251718b3'
90 93

  
91
    mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=404)
94
    fake_http.add_response(404, content=FAKE_LOGIN_OIDC_RESPONSE)
92 95
    with pytest.raises(APIError) as error:
93 96
        token = connector.get_access_token('nameid')
94 97

  
95
    assert str(error.value) == 'HTTP error: 404'
98
    assert '404' in str(error.value)
96 99

  
97
    mocked_post.return_value = utils.FakedResponse(content="content", status_code=200)
100
    fake_http.add_response(200, content="content")
98 101
    with pytest.raises(APIError) as error:
99 102
        token = connector.get_access_token('nameid')
100 103
    assert str(error.value) == 'No JSON content returned: \'content\''
101 104

  
102
    mocked_post.return_value = utils.FakedResponse(content="content", status_code=200)
105
    fake_http.add_response(200, content="content")
103 106
    with pytest.raises(APIError) as error:
104 107
        token = connector.get_access_token('nameid')
105 108
    assert str(error.value) == 'No JSON content returned: \'content\''
106 109

  
107
    mocked_post.return_value = utils.FakedResponse(content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Auth FAIL"}',
108
                                                   status_code=200)
110
    fake_http.add_response(200, content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Auth FAIL"}')
109 111
    with pytest.raises(APIError) as error:
110 112
        token = connector.get_access_token('nameid')
111 113
    assert str(error.value) == 'Auth FAIL (Fail)'
112 114

  
113 115

  
114
@mock.patch('passerelle.utils.Request.get')
115
@mock.patch('passerelle.utils.Request.post')
116
def test_get_user_forms(mocked_post, mocked_get, app, connector):
116
def test_get_user_forms(fake_http, app, connector):
117 117
    endpoint = reverse('generic-endpoint', kwargs={
118 118
        'connector': 'arpege-ecp', 'slug': connector.slug, 'endpoint': 'api', 'rest': 'users/nameid/forms'})
119 119
    assert endpoint == '/arpege-ecp/test/api/users/nameid/forms'
120 120

  
121
    mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
122
    mocked_get.return_value = utils.FakedResponse(content=FAKE_USER_DEMANDS_RESPONSE, status_code=200)
121
    fake_http.add_response(200, content=FAKE_LOGIN_OIDC_RESPONSE)
122
    fake_http.add_response(200, content=FAKE_USER_DEMANDS_RESPONSE)
123 123
    resp = app.get(endpoint)
124 124
    result = resp.json
125 125
    assert resp.json['data']
......
134 134
        assert item['form_status_is_endpoint'] == False
135 135

  
136 136

  
137
@mock.patch('passerelle.utils.Request.get')
138
@mock.patch('passerelle.utils.Request.post')
139
def test_get_user_forms_failure(mocked_post, mocked_get, app, connector):
137
def test_get_user_forms_failure(fake_http, app, connector):
140 138
    endpoint = reverse('generic-endpoint', kwargs={
141 139
        'connector': 'arpege-ecp', 'slug': connector.slug, 'endpoint': 'api', 'rest': 'users/nameid/forms'})
142 140

  
143
    mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
144
    mocked_get.return_value = utils.FakedResponse(content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Failed to get demands"}',
145
                                                  status_code=200)
141
    fake_http.add_response(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
142
    fake_http.add_response(content='{"IsSuccess": false, "CodErreur": "Fail", "LibErreur": "Failed to get demands"}',
143
                           status_code=200)
146 144
    resp = app.get(endpoint)
147 145
    result = resp.json
148 146
    assert result['err'] == 1
149 147
    assert result['err_desc'] == 'Failed to get demands (Fail)'
150 148

  
151 149

  
152
@mock.patch('passerelle.utils.Request.get')
153
@mock.patch('passerelle.utils.Request.post')
154
def test_get_user_forms_failure_404(mocked_post, mocked_get, app, connector):
150
def test_get_user_forms_failure_404(fake_http, app, connector):
155 151
    endpoint = reverse('generic-endpoint', kwargs={
156 152
        'connector': 'arpege-ecp', 'slug': connector.slug, 'endpoint': 'api', 'rest': 'users/nameid/forms'})
157 153

  
158
    mocked_post.return_value = utils.FakedResponse(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
159
    mocked_get.return_value = utils.FakedResponse(content=FAKE_USER_DEMANDS_RESPONSE, status_code=404)
154
    fake_http.add_response(content=FAKE_LOGIN_OIDC_RESPONSE, status_code=200)
155
    fake_http.add_response(content=FAKE_USER_DEMANDS_RESPONSE, status_code=404)
160 156
    resp = app.get(endpoint)
161 157
    result = resp.json
162 158
    assert result['err'] == 1
163
    assert result['err_desc'] == 'HTTP error: 404'
159
    assert '404 Client Error' in result['err_desc']
164 160

  
165 161

  
166 162
@mock.patch('passerelle.utils.Request.get')
tests/test_gdema.py
75 75
    return gdema
76 76

  
77 77

  
78
def test_gdema_services_and_typologies(app, gdema):
78
def test_gdema_services_and_typologies(fake_http, app, gdema):
79 79
    endpoint = utils.generic_endpoint_url('gdema', 'referentiel', slug=gdema.slug)
80 80
    assert endpoint == '/gdema/test/referentiel'
81
    with mock.patch('passerelle.utils.Request.get') as requests_get:
82
        requests_get.return_value = utils.FakedResponse(content=SERVICES,
83
                                                        status_code=200)
84
        resp = app.get(endpoint + '/service/', status=200)
85
        assert requests_get.call_count == 1
86
        assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/referentiel/service'
87
        assert 'data' in resp.json
88
        assert resp.json['err'] == 0
89
        assert len(resp.json['data']) == 3
90
        assert resp.json['data'][0]['id'] == '16151'
91
        assert resp.json['data'][0]['text'] == u'DMT - Mobilité et transports'
92

  
93
        resp = app.get(endpoint + '/typology/', status=200)
94
        assert requests_get.call_count == 2
95
        assert 'data' in resp.json
96
        assert resp.json['err'] == 0
97
        assert len(resp.json['data']) == 12
98
        assert resp.json['data'][0]['id'] == '13067'
99
        assert resp.json['data'][0]['text'] == u'Maintenance Cie'
100
        assert resp.json['data'][0]['service_id'] == '10173'
101
        assert resp.json['data'][0]['service_text'] == u'DESPU - Administration Direction environnement et services publics urbains'
102

  
103
        resp = app.get(endpoint + '/typology/?service_id=10426', status=200)
104
        assert requests_get.call_count == 3
105
        assert 'data' in resp.json
106
        assert resp.json['err'] == 0
107
        assert len(resp.json['data']) == 7
108
        assert resp.json['data'][0]['id'] == '10804'
109
        assert resp.json['data'][0]['text'] == u'Activités périscolaires'
110
        assert resp.json['data'][0]['service_id'] == '10426'
111
        assert resp.json['data'][0]['service_text'] == u'DEE - Périscolaire et éducatif'
112

  
113

  
114
def test_gdema_referentiel(app, gdema):
81
    fake_http.add_response(content=SERVICES, status_code=200)
82
    resp = app.get(endpoint + '/service/', status=200)
83
    assert fake_http.last_request.url == 'https://gdema.example.net/api/referentiel/service'
84
    assert 'data' in resp.json
85
    assert resp.json['err'] == 0
86
    assert len(resp.json['data']) == 3
87
    assert resp.json['data'][0]['id'] == '16151'
88
    assert resp.json['data'][0]['text'] == u'DMT - Mobilité et transports'
89

  
90
    fake_http.add_response(content=SERVICES, status_code=200)
91
    resp = app.get(endpoint + '/typology/', status=200)
92
    assert 'data' in resp.json
93
    assert resp.json['err'] == 0
94
    assert len(resp.json['data']) == 12
95
    assert resp.json['data'][0]['id'] == '13067'
96
    assert resp.json['data'][0]['text'] == u'Maintenance Cie'
97
    assert resp.json['data'][0]['service_id'] == '10173'
98
    assert resp.json['data'][0]['service_text'] == u'DESPU - Administration Direction environnement et services publics urbains'
99

  
100
    fake_http.add_response(content=SERVICES, status_code=200)
101
    resp = app.get(endpoint + '/typology/?service_id=10426', status=200)
102
    assert 'data' in resp.json
103
    assert resp.json['err'] == 0
104
    assert len(resp.json['data']) == 7
105
    assert resp.json['data'][0]['id'] == '10804'
106
    assert resp.json['data'][0]['text'] == u'Activités périscolaires'
107
    assert resp.json['data'][0]['service_id'] == '10426'
108
    assert resp.json['data'][0]['service_text'] == u'DEE - Périscolaire et éducatif'
109

  
110

  
111
def test_gdema_referentiel(fake_http, app, gdema):
115 112
    endpoint = utils.generic_endpoint_url('gdema', 'referentiel', slug=gdema.slug)
116 113
    assert endpoint == '/gdema/test/referentiel'
117
    with mock.patch('passerelle.utils.Request.get') as requests_get:
118
        requests_get.return_value = utils.FakedResponse(content=CIVILITY,
119
                                                        status_code=200)
120
        resp = app.get(endpoint + '/civility/', status=200)
121
        assert requests_get.call_count == 1
122
        assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/referentiel/civility'
123
        assert 'data' in resp.json
124
        assert resp.json['err'] == 0
125
        assert len(resp.json['data']) == 3
126
        assert resp.json['data'][0]['id'] == '1'
127
        assert resp.json['data'][0]['text'] == 'Monsieur'
128

  
129
    with mock.patch('passerelle.utils.Request.get') as requests_get:
130
        requests_get.return_value = utils.FakedResponse(content='404', status_code=404)
131
        resp = app.get(endpoint + '/nothing/', status=200)
132
        assert requests_get.call_count == 1
133
        assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/referentiel/nothing'
134
        assert 'data' in resp.json
135
        assert resp.json['err'] == 1
136
        assert resp.json['data'] is None
137
        assert resp.json['err_class'].endswith('.APIError')
138
        assert '404' in resp.json['err_desc']
139

  
140

  
141
def test_gdema_get_request(app, gdema):
114
    fake_http.add_response(content=CIVILITY, status_code=200)
115
    resp = app.get(endpoint + '/civility/', status=200)
116
    assert fake_http.last_request.url == 'https://gdema.example.net/api/referentiel/civility'
117
    assert 'data' in resp.json
118
    assert resp.json['err'] == 0
119
    assert len(resp.json['data']) == 3
120
    assert resp.json['data'][0]['id'] == '1'
121
    assert resp.json['data'][0]['text'] == 'Monsieur'
122

  
123
    fake_http.add_response(content='404', status_code=404)
124
    resp = app.get(endpoint + '/nothing/', status=200)
125
    assert fake_http.last_request.url == 'https://gdema.example.net/api/referentiel/nothing'
126
    assert 'data' in resp.json
127
    assert resp.json['err'] == 1
128
    assert resp.json['data'] is None
129
    assert resp.json['err_class'].endswith('.APIError')
130
    assert '404' in resp.json['err_desc']
131

  
132

  
133
def test_gdema_get_request(fake_http, app, gdema):
142 134
    endpoint = utils.generic_endpoint_url('gdema', 'get-request', slug=gdema.slug)
143 135
    assert endpoint == '/gdema/test/get-request'
144
    with mock.patch('passerelle.utils.Request.get') as requests_get:
145
        requests_get.return_value = utils.FakedResponse(content=REQUEST,
146
                                                        status_code=200)
147
        resp = app.get(endpoint + '/1/', status=200)
148
        assert requests_get.call_count == 1
149
        assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/request/1'
150
        assert 'data' in resp.json
151
        assert resp.json['err'] == 0
152
        assert resp.json['data']['Id'] == '1'
153
        assert resp.json['data']['AnswerToProvide'] is True
154
        assert resp.json['data']['Description'].startswith(u'contrôle')
155
        assert resp.json['data']['ExpectedDate'] is None
156
        assert resp.json['data']['Files'] == []
157
        assert resp.json['data']['Handler']['CivilityId'] == '0'
158
        assert resp.json['data']['ReceptDate'] == '2006-12-13T00:00:00+01:00'
136
    fake_http.add_response(content=REQUEST, status_code=200)
137
    resp = app.get(endpoint + '/1/', status=200)
138
    assert fake_http.last_request.url == 'https://gdema.example.net/api/request/1'
139
    assert 'data' in resp.json
140
    assert resp.json['err'] == 0
141
    assert resp.json['data']['Id'] == '1'
142
    assert resp.json['data']['AnswerToProvide'] is True
143
    assert resp.json['data']['Description'].startswith(u'contrôle')
144
    assert resp.json['data']['ExpectedDate'] is None
145
    assert resp.json['data']['Files'] == []
146
    assert resp.json['data']['Handler']['CivilityId'] == '0'
147
    assert resp.json['data']['ReceptDate'] == '2006-12-13T00:00:00+01:00'
159 148

  
160 149
    endpoint = utils.generic_endpoint_url('gdema', 'get-request-state', slug=gdema.slug)
161 150
    assert endpoint == '/gdema/test/get-request-state'
162
    with mock.patch('passerelle.utils.Request.get') as requests_get:
163
        requests_get.return_value = utils.FakedResponse(content=REQUEST_STATE,
164
                                                        status_code=200)
165
        resp = app.get(endpoint + '/1/', status=200)
166
        assert requests_get.call_count == 1
167
        assert requests_get.call_args[0][0] == 'https://gdema.example.net/api/request/1/state'
168
        assert 'data' in resp.json
169
        assert resp.json['err'] == 0
170
        assert resp.json['data'] == {'Id': '1', 'State': '64', 'StateLabel': u'Cloturée'}
171

  
172

  
173
def test_gdema_create_request(app, gdema):
151
    fake_http.add_response(content=REQUEST_STATE, status_code=200)
152
    resp = app.get(endpoint + '/1/', status=200)
153
    assert fake_http.last_request.url == 'https://gdema.example.net/api/request/1/state'
154
    assert 'data' in resp.json
155
    assert resp.json['err'] == 0
156
    assert resp.json['data'] == {'Id': '1', 'State': '64', 'StateLabel': u'Cloturée'}
157

  
158

  
159
def test_gdema_create_request(fake_http, app, gdema):
174 160
    endpoint = utils.generic_endpoint_url('gdema', 'create-request', slug=gdema.slug)
175 161
    assert endpoint == '/gdema/test/create-request'
176
    with mock.patch('passerelle.utils.Request.post') as requests_post:
177
        requests_post.return_value = utils.FakedResponse(content=REQUEST,
178
                                                         status_code=200)
179
        resp = app.post_json(endpoint + '?raise=1', params=CREATE_INPUT, status=200)
180
        assert requests_post.call_count == 1
181
        assert requests_post.call_args[0][0] == 'https://gdema.example.net/api/request/create'
182
        assert json.loads(requests_post.call_args[1]['data']) == CONVERTED_INPUT
183
        assert 'data' in resp.json
184
        assert resp.json['err'] == 0
185
        assert resp.json['data']['Id'] == '1'
162
    fake_http.add_response(content=REQUEST, status_code=200)
163
    resp = app.post_json(endpoint + '?raise=1', params=CREATE_INPUT, status=200)
164
    assert fake_http.last_request.url == 'https://gdema.example.net/api/request/create'
165
    assert fake_http.last_request.json == CONVERTED_INPUT
166
    assert 'data' in resp.json
167
    assert resp.json['err'] == 0
168
    assert resp.json['data']['Id'] == '1'
tests/test_generic_endpoint.py
309 309

  
310 310
    @endpoint(methods=['get'])
311 311
    def httpcall(obj, request):
312
        response = obj.requests.get(httpbin.url + '/cookies/set?foo=bar', allow_redirects=False)
312
        response = obj.requests.get(httpbin.url + '/cookies/set?foo=bar',
313
                                    raise_for_redirect=False,
314
                                    allow_redirects=False)
313 315
        cookie1 = response.request.headers.get('Cookie')
314 316
        response = obj.requests.get(httpbin.url + '/get')
315 317
        cookie2 = response.request.headers.get('Cookie')
......
339 341

  
340 342
    resource = utils.make_resource(Maarch, wsdl_url='https://example.com/', slug='slug', verify_cert=True)
341 343
    with pytest.raises(SSLError):
342
        resource.requests.get(httpbin_secure.join('/get/'))
344
        resource.requests.get(httpbin_secure.join('/get'))
343 345
    resource.verify_cert = False
344 346
    with warnings.catch_warnings():
345 347
        warnings.simplefilter('error')
346
        resource.requests.get(httpbin_secure.join('/get/'))
348
        resource.requests.get(httpbin_secure.join('/get'))
tests/test_okina.py
1339 1339
                                password='userpass')
1340 1340

  
1341 1341

  
1342
def test_okina_cities(app, okina):
1342
def test_okina_cities(fake_http, app, okina):
1343 1343
    endpoint = utils.generic_endpoint_url('okina', 'cities', slug=okina.slug)
1344 1344
    assert endpoint == '/okina/test/cities'
1345
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1346
        requests_get.return_value = utils.FakedResponse(content=CITIES,
1347
                                                        status_code=200)
1348
        resp = app.get(endpoint, status=200)
1349
        assert requests_get.call_count == 1
1350
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/cities'
1351
        assert requests_get.call_args[1]['auth'] == ('usertest', 'userpass')
1352
        assert 'data' in resp.json
1353
        assert resp.json['err'] == 0
1354
        assert len(resp.json['data']) == 2
1355
        assert resp.json['data'][0]['id'] == '83355'
1356
        assert resp.json['data'][0]['insee'] == '36005'
1357
        assert resp.json['data'][0]['text'] == 'ARDENTES (36120)'
1345
    fake_http.set_response(content=CITIES, status_code=200)
1346
    resp = app.get(endpoint, status=200)
1347
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/cities'
1348
    assert fake_http.last_request.basic_auth == ['usertest', 'userpass']
1349
    assert 'data' in resp.json
1350
    assert resp.json['err'] == 0
1351
    assert len(resp.json['data']) == 2
1352
    assert resp.json['data'][0]['id'] == '83355'
1353
    assert resp.json['data'][0]['insee'] == '36005'
1354
    assert resp.json['data'][0]['text'] == 'ARDENTES (36120)'
1355

  
1358 1356

  
1359
def test_okina_classes(app, okina):
1357
def test_okina_classes(fake_http, app, okina):
1360 1358
    endpoint = utils.generic_endpoint_url('okina', 'classes', slug=okina.slug)
1361 1359
    assert endpoint == '/okina/test/classes'
1362
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1363
        requests_get.return_value = utils.FakedResponse(content=CLASSES,
1364
                                                        status_code=200)
1365
        resp = app.get(endpoint, status=200)
1366
        assert requests_get.call_count == 1
1367
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/classes'
1368
        assert resp.json['err'] == 0
1369
        assert len(resp.json['data']) == 4
1370
        assert resp.json['data'][0]['id'] == '1'
1371
        assert resp.json['data'][0]['text'] == u'École maternelle - Petite section'
1360
    fake_http.set_response(content=CLASSES, status_code=200)
1361
    resp = app.get(endpoint, status=200)
1362
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/classes'
1363
    assert resp.json['err'] == 0
1364
    assert len(resp.json['data']) == 4
1365
    assert resp.json['data'][0]['id'] == '1'
1366
    assert resp.json['data'][0]['text'] == u'École maternelle - Petite section'
1372 1367

  
1373
def test_okina_institutions(app, okina):
1368

  
1369
def test_okina_institutions(fake_http, app, okina):
1374 1370
    endpoint = utils.generic_endpoint_url('okina', 'institutions', slug=okina.slug)
1375 1371
    assert endpoint == '/okina/test/institutions'
1376
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1377
        requests_get.return_value = utils.FakedResponse(content=INSTITUTIONS,
1378
                                                        status_code=200)
1379
        resp = app.get(endpoint, status=200)
1380
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/institutions'
1381
        assert resp.json['err'] == 0
1382
        assert len(resp.json['data']) == 2
1383
        assert resp.json['data'][0]['id'] == '277'
1384
        assert resp.json['data'][0]['text'] == u'Collège Touvent'
1372
    fake_http.set_response(content=INSTITUTIONS, status_code=200)
1373
    resp = app.get(endpoint, status=200)
1374
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/institutions'
1375
    assert resp.json['err'] == 0
1376
    assert len(resp.json['data']) == 2
1377
    assert resp.json['data'][0]['id'] == '277'
1378
    assert resp.json['data'][0]['text'] == u'Collège Touvent'
1385 1379

  
1386
        resp = app.get(endpoint + '/from-city/36005/', status=200)
1387
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/institutions/subscriberCity/36005'
1388
        assert resp.json['err'] == 0
1389
        assert len(resp.json['data']) == 2
1390
        assert resp.json['data'][0]['id'] == '277'
1391
        assert resp.json['data'][0]['text'] == u'Collège Touvent'
1380
    fake_http.set_response(content=INSTITUTIONS, status_code=200)
1381
    resp = app.get(endpoint + '/from-city/36005/', status=200)
1382
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/institutions/subscriberCity/36005'
1383
    assert resp.json['err'] == 0
1384
    assert len(resp.json['data']) == 2
1385
    assert resp.json['data'][0]['id'] == '277'
1386
    assert resp.json['data'][0]['text'] == u'Collège Touvent'
1392 1387

  
1393
def test_okina_stops_area(app, okina):
1388

  
1389
def test_okina_stops_area(fake_http, app, okina):
1394 1390
    endpoint = utils.generic_endpoint_url('okina', 'stop-areas', slug=okina.slug)
1395 1391
    assert endpoint == '/okina/test/stop-areas'
1396
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1397
        requests_get.return_value = utils.FakedResponse(content=STOPS,
1398
                                                        status_code=200)
1399
        resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200)
1400
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/stop-areas/subscriberCity/36005/institution/276'
1401
        assert resp.json['err'] == 0
1402
        assert len(resp.json['data']) == 3
1403
        assert resp.json['data'][0]['id'] == '3281'
1404
        assert resp.json['data'][0]['text'] == u'Les Loges de Dressais'
1392
    fake_http.set_response(content=STOPS, status_code=200)
1393
    resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200)
1394
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/stop-areas/subscriberCity/36005/institution/276'
1395
    assert resp.json['err'] == 0
1396
    assert len(resp.json['data']) == 3
1397
    assert resp.json['data'][0]['id'] == '3281'
1398
    assert resp.json['data'][0]['text'] == u'Les Loges de Dressais'
1399

  
1405 1400

  
1406
def test_okina_ods(app, okina):
1401
def test_okina_ods(fake_http, app, okina):
1407 1402
    endpoint = utils.generic_endpoint_url('okina', 'origin-destinations', slug=okina.slug)
1408 1403
    assert endpoint == '/okina/test/origin-destinations'
1409
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1410
        requests_get.return_value = utils.FakedResponse(content=ODS, status_code=200)
1411
        resp = app.get(endpoint, status=200)
1412
        assert requests_get.call_count == 1
1413
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods'
1414
        assert resp.json['err'] == 0
1415
        assert len(resp.json['data']) == 2
1416
        assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1417
        assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1418
        assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1419
        assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1404
    fake_http.set_response(content=ODS, status_code=200)
1405
    resp = app.get(endpoint, status=200)
1406
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods'
1407
    assert resp.json['err'] == 0
1408
    assert len(resp.json['data']) == 2
1409
    assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1410
    assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1411
    assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1412
    assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1420 1413

  
1421
        requests_get.return_value = utils.FakedResponse(content=ODS, status_code=200)
1422
        resp = app.get(endpoint + '/to-institution/276/', status=200)
1423
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/institution/276'
1424
        assert resp.json['err'] == 0
1425
        assert len(resp.json['data']) == 2
1426
        assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1427
        assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1428
        assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1429
        assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1414
    fake_http.set_response(content=ODS, status_code=200)
1415
    resp = app.get(endpoint + '/to-institution/276/', status=200)
1416
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/institution/276'
1417
    assert resp.json['err'] == 0
1418
    assert len(resp.json['data']) == 2
1419
    assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1420
    assert resp.json['data'][0]['text'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1421
    assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1422
    assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1430 1423

  
1431
        requests_get.return_value = utils.FakedResponse(content=ODS_LINES, status_code=200)
1432
        resp = app.get(endpoint + '/from-stop-area/3282/to-institution/276/', status=200)
1433
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/institution/276/stop-area/3282'
1434
        assert resp.json['err'] == 0
1435
        assert len(resp.json['data']) == 3
1436
        assert resp.json['data'][0]['id'] == '1'
1437
        assert resp.json['data'][0]['text'] == 'LIGNE 24'
1438
        assert len(resp.json['data'][0]['lines']) == 1
1439
        assert resp.json['data'][0]['lines'][0]['id'] == '24'
1440
        assert resp.json['data'][0]['lines'][0]['text'] == 'LIGNE 24'
1441
        assert resp.json['data'][1]['id'] == '2'
1442
        assert resp.json['data'][1]['text'] == 'LIGNE 22'
1443
        assert len(resp.json['data'][1]['lines']) == 1
1444
        assert resp.json['data'][1]['lines'][0]['id'] == '22'
1445
        assert resp.json['data'][1]['lines'][0]['text'] == 'LIGNE 22'
1446
        assert resp.json['data'][2]['id'] == '3'
1447
        assert resp.json['data'][2]['text'] == 'LIGNE 24 + LIGNE 23'
1448
        assert len(resp.json['data'][2]['lines']) == 2
1449
        assert resp.json['data'][2]['lines'][0]['id'] == '24'
1450
        assert resp.json['data'][2]['lines'][0]['text'] == 'LIGNE 24'
1451
        assert resp.json['data'][2]['lines'][1]['id'] == '23'
1452
        assert resp.json['data'][2]['lines'][1]['text'] == 'LIGNE 23'
1424
    fake_http.set_response(content=ODS_LINES, status_code=200)
1425
    resp = app.get(endpoint + '/from-stop-area/3282/to-institution/276/', status=200)
1426
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/institution/276/stop-area/3282'
1427
    assert resp.json['err'] == 0
1428
    assert len(resp.json['data']) == 3
1429
    assert resp.json['data'][0]['id'] == '1'
1430
    assert resp.json['data'][0]['text'] == 'LIGNE 24'
1431
    assert len(resp.json['data'][0]['lines']) == 1
1432
    assert resp.json['data'][0]['lines'][0]['id'] == '24'
1433
    assert resp.json['data'][0]['lines'][0]['text'] == 'LIGNE 24'
1434
    assert resp.json['data'][1]['id'] == '2'
1435
    assert resp.json['data'][1]['text'] == 'LIGNE 22'
1436
    assert len(resp.json['data'][1]['lines']) == 1
1437
    assert resp.json['data'][1]['lines'][0]['id'] == '22'
1438
    assert resp.json['data'][1]['lines'][0]['text'] == 'LIGNE 22'
1439
    assert resp.json['data'][2]['id'] == '3'
1440
    assert resp.json['data'][2]['text'] == 'LIGNE 24 + LIGNE 23'
1441
    assert len(resp.json['data'][2]['lines']) == 2
1442
    assert resp.json['data'][2]['lines'][0]['id'] == '24'
1443
    assert resp.json['data'][2]['lines'][0]['text'] == 'LIGNE 24'
1444
    assert resp.json['data'][2]['lines'][1]['id'] == '23'
1445
    assert resp.json['data'][2]['lines'][1]['text'] == 'LIGNE 23'
1453 1446

  
1454
        requests_get.return_value = utils.FakedResponse(content=ODS_FULL, status_code=200)
1455
        resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200)
1456
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/institution/276/subscriberCity/36005'
1457
        assert resp.json['err'] == 0
1458
        assert len(resp.json['data']) == 1
1459
        assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1460
        assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent'
1461
        assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1462
        assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1447
    fake_http.set_response(content=ODS_FULL, status_code=200)
1448
    resp = app.get(endpoint + '/from-city/36005/to-institution/276/', status=200)
1449
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/institution/276/subscriberCity/36005'
1450
    assert resp.json['err'] == 0
1451
    assert len(resp.json['data']) == 1
1452
    assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1453
    assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent'
1454
    assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1455
    assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1456

  
1457
    fake_http.set_response(content=ODS_FULL, status_code=200)
1458
    resp = app.get(endpoint + '/from-city/36005/', status=200)
1459
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/ods/subscriberCity/36005'
1460
    assert resp.json['err'] == 0
1461
    assert len(resp.json['data']) == 1
1462
    assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1463
    assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent'
1464
    assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1465
    assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1463 1466

  
1464
        requests_get.return_value = utils.FakedResponse(content=ODS_FULL, status_code=200)
1465
        resp = app.get(endpoint + '/from-city/36005/', status=200)
1466
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/ods/subscriberCity/36005'
1467
        assert resp.json['err'] == 0
1468
        assert len(resp.json['data']) == 1
1469
        assert resp.json['data'][0]['id'] == 'inst:276-seq:1-6-84'
1470
        assert resp.json['data'][0]['text'] == u'Brenne 1 vers écoles Antoine Fée, Saint Martin et Saint Vincent'
1471
        assert resp.json['data'][0]['identifier'] == 'SYNDICAT ARDENTES 4 (semaine Aller)'
1472
        assert resp.json['data'][0]['vehicle_journey_id'] == '84'
1473 1467

  
1474
def test_okina_topology(app, okina):
1468
def test_okina_topology(fake_http, app, okina):
1475 1469
    endpoint = utils.generic_endpoint_url('okina', 'topology', slug=okina.slug)
1476 1470
    assert endpoint == '/okina/test/topology'
1477
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1478
        requests_get.return_value = utils.FakedResponse(content=LINES, status_code=200)
1479
        resp = app.get(endpoint + '/lines/', status=200)
1480
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/topology/lines'
1481
        assert resp.json['err'] == 0
1482
        assert len(resp.json['data']) == 3
1483
        assert resp.json['data'][0]['id'] == '45'
1484
        assert resp.json['data'][0]['text'] == '019 - 02 - VELLES LYCEES DE CHATEAUROUX'
1471
    fake_http.set_response(content=LINES, status_code=200)
1472
    resp = app.get(endpoint + '/lines/', status=200)
1473
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/topology/lines'
1474
    assert resp.json['err'] == 0
1475
    assert len(resp.json['data']) == 3
1476
    assert resp.json['data'][0]['id'] == '45'
1477
    assert resp.json['data'][0]['text'] == '019 - 02 - VELLES LYCEES DE CHATEAUROUX'
1485 1478

  
1486
        requests_get.return_value = utils.FakedResponse(content=NETWORKS, status_code=200)
1487
        resp = app.get(endpoint + '/networks/', status=200)
1488
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/topology/networks'
1489
        assert resp.json['err'] == 0
1490
        assert len(resp.json['data']) == 1
1491
        assert resp.json['data'][0]['id'] == '2'
1492
        assert resp.json['data'][0]['text'] == u'réseau scolaire'
1479
    fake_http.set_response(content=NETWORKS, status_code=200)
1480
    resp = app.get(endpoint + '/networks/', status=200)
1481
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/topology/networks'
1482
    assert resp.json['err'] == 0
1483
    assert len(resp.json['data']) == 1
1484
    assert resp.json['data'][0]['id'] == '2'
1485
    assert resp.json['data'][0]['text'] == u'réseau scolaire'
1493 1486

  
1494
        requests_get.return_value = utils.FakedResponse(content=VEHICLE_JOURNEYS, status_code=200)
1495
        resp = app.get(endpoint + '/vehicle-journeys/', status=200)
1496
        assert requests_get.call_args[0][0] == 'https://okina.example.net/b2b/topology/vehicle-journeys'
1497
        assert resp.json['err'] == 0
1498
        assert len(resp.json['data']) == 3
1499
        assert resp.json['data'][0]['id'] == '306'
1500
        assert resp.json['data'][0]['text'] == u'019 02 - VELLES LYCEES DE CHATEAUROUX'
1487
    fake_http.set_response(content=VEHICLE_JOURNEYS, status_code=200)
1488
    resp = app.get(endpoint + '/vehicle-journeys/', status=200)
1489
    assert fake_http.last_request.url == 'https://okina.example.net/b2b/topology/vehicle-journeys'
1490
    assert resp.json['err'] == 0
1491
    assert len(resp.json['data']) == 3
1492
    assert resp.json['data'][0]['id'] == '306'
1493
    assert resp.json['data'][0]['text'] == u'019 02 - VELLES LYCEES DE CHATEAUROUX'
1501 1494

  
1502
def test_okina_errors(app, okina):
1503
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1504
        for response in ((200, '{"foo": "bar"}'),   # not a list
1505
                         (200, '{["foo": "bar"]}'), # list of malformatted dict
1506
                         (200, '<h1>Welcome</h1>'), # bad json
1507
                         (403, '<h1>Bad creds</h1>'),
1508
                         (404, '<h1>Not Found</h1>'),
1509
                         (500, '<h1>Crash</h1>'),
1510
                        ):
1511
            requests_get.return_value = utils.FakedResponse(content=response[1],
1512
                                                            status_code=response[0])
1513
            resp = app.get('/okina/test/cities', status=500)
1514
            assert resp.json['err'] == 1
1515
            assert resp.json['data'] == None
1516 1495

  
1517
        # "normal" 401/403 response, ie problem with login/password
1518
        for status_code in (401, 403):
1519
            requests_get.return_value = utils.FakedResponse(content='''{"message": "Invalid credentials",
1520
                    "code": 4, "status" : %d}''' % status_code, status_code=status_code)
1521
            resp = app.get('/okina/test/cities', status=500)
1522
            assert resp.json['err'] == 1
1523
            assert resp.json['err_desc'] == "Invalid credentials"
1524
            assert resp.json['data'] is None
1496
def test_okina_errors(fake_http, app, okina):
1497
    for status_code, content in (
1498
            (200, '{"foo": "bar"}'),   # not a list
1499
            (200, '{["foo": "bar"]}'), # list of malformatted dict
1500
            (200, '<h1>Welcome</h1>'), # bad json
1501
            (403, '<h1>Bad creds</h1>'),
1502
            (404, '<h1>Not Found</h1>'),
1503
            (500, '<h1>Crash</h1>')):
1504
        fake_http.set_response(status_code=status_code, content=content)
1505
        resp = app.get('/okina/test/cities', status=500)
1506
        assert resp.json['err'] == 1
1507
        assert resp.json['data'] is None
1525 1508

  
1526
def test_okina_suscribe(app, okina):
1509
    # "normal" 401/403 response, ie problem with login/password
1510
    for status_code in (401, 403):
1511
        fake_http.set_response(content='''{"message": "Invalid credentials", "code": 4, "status" : %d}''' % status_code,
1512
                               status_code=status_code)
1513
        resp = app.get('/okina/test/cities', status=500)
1514
        assert resp.json['err'] == 1
1515
        assert resp.json['err_desc'] == "Invalid credentials"
1516
        assert resp.json['data'] is None
1517

  
1518

  
1519
def test_okina_suscribe(fake_http, app, okina):
1527 1520

  
1528 1521
    for service in ('subscriber', 'subscription'):
1529 1522
        endpoint = utils.generic_endpoint_url('okina', service, slug=okina.slug)
1530 1523
        assert endpoint == '/okina/test/%s' % service
1531
        with mock.patch('passerelle.utils.Request.get') as requests_get:
1532
            resp = app.post(endpoint, status=403)
1533
            assert requests_get.call_count == 0
1534
            assert resp.json['err'] == 1
1535
            assert resp.json['err_class'] == 'django.core.exceptions.PermissionDenied'
1524
        resp = app.post(endpoint, status=403)
1525
        assert resp.json['err'] == 1
1526
        assert resp.json['err_class'] == 'django.core.exceptions.PermissionDenied'
1527

  
1536 1528
    # open access
1537 1529
    api = ApiUser.objects.create(username='all', keytype='', key='')
1538 1530
    obj_type = ContentType.objects.get_for_model(okina)
......
1541 1533
    for service in ('subscriber', 'subscription'):
1542 1534
        endpoint = utils.generic_endpoint_url('okina', service, slug=okina.slug)
1543 1535
        assert endpoint == '/okina/test/%s' % service
1544
        with mock.patch('passerelle.utils.Request.post') as requests_get:
1545
            resp = app.post(endpoint, status=400)  # no payload
1546
            assert requests_get.call_count == 0
1547
            assert resp.json['err'] == 1
1548
            assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
1549
            assert resp.json['err_desc'] == 'payload must be a JSON object'
1536
        resp = app.post(endpoint, status=400)  # no payload
1537
        assert resp.json['err'] == 1
1538
        assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
1539
        assert resp.json['err_desc'] == 'payload must be a JSON object'
1550 1540

  
1551
            resp = app.post_json(endpoint, params=[], status=400)  # bad payload
1552
            assert requests_get.call_count == 0
1553
            assert resp.json['err'] == 1
1554
            assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
1555
            assert resp.json['err_desc'] == 'payload must be a dict'
1541
        resp = app.post_json(endpoint, params=[], status=400)  # bad payload
1542
        assert resp.json['err'] == 1
1543
        assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
1544
        assert resp.json['err_desc'] == 'payload must be a dict'
1556 1545

  
1557
            requests_get.return_value = utils.FakedResponse(content='{"foo":"bar"}', status_code=200)
1558
            resp = app.post_json(endpoint, params={'x':'y'})
1559
            assert requests_get.call_count == 1
1560
            assert resp.json['err'] == 0
1561
            assert resp.json['data'] == {'foo': 'bar'}
1546
        fake_http.set_response(content='{"foo":"bar"}', status_code=200)
1547
        resp = app.post_json(endpoint, params={'x': 'y'})
1548
        assert resp.json['err'] == 0
1549
        assert resp.json['data'] == {'foo': 'bar'}
1562 1550

  
1563 1551
    # qrcode
1564 1552
    endpoint = '/okina/test/subscriber/123/qrcode'
1565
    with mock.patch('passerelle.utils.Request.get') as requests_get:
1566
        requests_get.return_value = utils.FakedResponse(content='PNGfoo',
1567
                                                        headers={'Content-Type': 'image/png'},
1568
                                                        status_code=200)
1569
        resp = app.get(endpoint)
1570
        assert requests_get.call_count == 1
1571
        assert resp.headers['content-type'] == 'image/png'
1572
        assert resp.content == 'PNGfoo'
1553
    fake_http.set_response(content='PNGfoo', headers={'Content-Type': 'image/png'}, status_code=200)
1554
    resp = app.get(endpoint)
1555
    assert resp.headers['content-type'] == 'image/png'
1556
    assert resp.content == 'PNGfoo'
1573 1557

  
1574
        requests_get.return_value = utils.FakedResponse(content=QRCODE_400,
1575
                                                        headers={'Content-Type': 'application/json' },
1576
                                                        status_code=400)
1577
        resp = app.get(endpoint, status=400)
1578
        assert requests_get.call_count == 2
1579
        assert resp.json == {
1580
            u'err': 1,
1581
            u'err_class': u'passerelle.utils.jsonresponse.APIError',
1582
            u'err_desc': u'Subscriber with ID 123 has no passcard number to generate qr code from.',
1583
            u'data': None,
1584
        }
1558
    fake_http.set_response(content=QRCODE_400,
1559
                           headers={'Content-Type': 'application/json' },
1560
                           status_code=400)
1561
    resp = app.get(endpoint, status=400)
1562
    assert resp.json == {
1563
        u'err': 1,
1564
        u'err_class': u'passerelle.utils.jsonresponse.APIError',
1565
        u'err_desc': u'Subscriber with ID 123 has no passcard number to generate qr code from.',
1566
        u'data': None,
1567
    }
1585 1568

  
1586
        requests_get.return_value = utils.FakedResponse(content=QRCODE_404,
1587
                                                        headers={'Content-Type': 'application/json' },
1588
                                                        status_code=404)
1589
        resp = app.get(endpoint, status=404)
1590
        assert requests_get.call_count == 3
1591
        assert resp.json == {
1592
            u'err': 1,
1593
            u'err_class': u'passerelle.utils.jsonresponse.APIError',
1594
            u'err_desc': u'Subscriber with ID 123 not found.',
1595
            u'data': None,
1596
        }
1569
    fake_http.set_response(content=QRCODE_404,
1570
                           headers={'Content-Type': 'application/json' },
1571
                           status_code=404)
1572
    resp = app.get(endpoint, status=404)
1573
    assert resp.json == {
1574
        u'err': 1,
1575
        u'err_class': u'passerelle.utils.jsonresponse.APIError',
1576
        u'err_desc': u'Subscriber with ID 123 not found.',
1577
        u'data': None,
1578
    }
tests/test_opengis.py
222 222
        wfs_service_url='http://example.net/wfs'))
223 223

  
224 224

  
225
def geoserver_responses(url, **kwargs):
226
    if kwargs['params'].get('request') == 'GetCapabilities':
227
        return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
228
    return utils.FakedResponse(status_code=200, content=FAKE_FEATURES_JSON)
229

  
230

  
231
def geoserver_responses_errors(url, **kwargs):
232
    if kwargs['params'].get('request') == 'GetCapabilities':
233
        return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
234
    return utils.FakedResponse(status_code=200, content=FAKE_ERROR)
235

  
236

  
237
def geoserver_responses_errors_unparsable(url, **kwargs):
238
    if kwargs['params'].get('request') == 'GetCapabilities':
239
        return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
240
    return utils.FakedResponse(status_code=200, content=FAKE_ERROR[:10])
241

  
242

  
243
@mock.patch('passerelle.utils.Request.get')
244
def test_feature_info(mocked_get, app, connector):
225
def test_feature_info(fake_http, app, connector):
245 226
    endpoint = utils.generic_endpoint_url('opengis', 'feature_info', slug=connector.slug)
246 227
    assert endpoint == '/opengis/test/feature_info'
247
    mocked_get.return_value = utils.FakedResponse(content=FAKE_FEATURE_INFO, status_code=200)
228

  
229
    fake_http.set_response(content=FAKE_FEATURE_INFO, status_code=200)
248 230
    resp = app.get(endpoint, params={'lat': '45.796890', 'lon': '4.784140'})
249
    assert mocked_get.call_args[1]['params']['BBOX'] == '5747860.22776,532568.028684,5748179.56467,532790.667665'
250
    assert mocked_get.call_args[1]['params']['CRS'] == 'EPSG:3857'
231
    assert fake_http.last_request.GET['BBOX'] == '5747860.22776,532568.028684,5748179.56467,532790.667665'
232
    assert fake_http.last_request.GET['CRS'] == 'EPSG:3857'
251 233
    assert (resp.json['data']
252 234
                     ['cad_cadastrecadparcelle_layer']
253 235
                     ['cad_cadastrecadparcelle_feature']
......
255 237
            == 'Particulier')
256 238
    connector.projection = 'EPSG:4326'
257 239
    connector.save()
240

  
241
    fake_http.set_response(content=FAKE_FEATURE_INFO, status_code=200)
258 242
    resp = app.get(endpoint, params={'lat': '45.796890', 'lon': '4.784140'})
259
    assert mocked_get.call_args[1]['params']['BBOX'] == '45.796890,4.784140,45.79889,4.78614'
260
    assert mocked_get.call_args[1]['params']['CRS'] == 'EPSG:4326'
243
    assert fake_http.last_request.GET['BBOX'] == '45.796890,4.784140,45.79889,4.78614'
244
    assert fake_http.last_request.GET['CRS'] == 'EPSG:4326'
261 245

  
262 246

  
263
@mock.patch('passerelle.utils.Request.get')
264
def test_tile(mocked_get, app, connector):
247
def test_tile(fake_http, app, connector):
265 248
    endpoint = utils.generic_endpoint_url('opengis', 'tile', slug=connector.slug)
266 249
    assert endpoint == '/opengis/test/tile'
267
    mocked_get.return_value = utils.FakedResponse(content='\x89PNG\r\n\x1a\n\x00\x00...', status_code=200)
250

  
251
    fake_http.set_response(content='\x89PNG\r\n\x1a\n\x00\x00...', status_code=200)
268 252
    resp = app.get(endpoint + '/16/33650/23378.png')
269
    assert mocked_get.call_args[1]['params']['SRS'] == 'EPSG:3857'
270
    assert mocked_get.call_args[1]['params']['BBOX'] == '539339.67158,5741338.06856,539951.167806,5741949.56478'
253
    assert fake_http.last_request.GET['SRS'] == 'EPSG:3857'
254
    assert fake_http.last_request.GET['BBOX'] == '539339.67158,5741338.06856,539951.167806,5741949.56478'
271 255
    connector.projection = 'EPSG:4326'
272 256
    connector.save()
257

  
258
    fake_http.set_response(content='\x89PNG\r\n\x1a\n\x00\x00...', status_code=200)
273 259
    resp = app.get(endpoint + '/16/33650/23378.png')
274
    assert mocked_get.call_args[1]['params']['SRS'] == 'EPSG:4326'
275
    assert mocked_get.call_args[1]['params']['BBOX'] == '4.84497070312,45.7560261559,4.85046386719,45.7598586879'
260
    assert fake_http.last_request.GET['SRS'] == 'EPSG:4326'
261
    assert fake_http.last_request.GET['BBOX'] == '4.84497070312,45.7560261559,4.85046386719,45.7598586879'
276 262
    assert resp.content == '\x89PNG\r\n\x1a\n\x00\x00...'
277 263

  
278 264

  
279
@mock.patch('passerelle.utils.Request.get')
280
def test_get_feature_with_no_wfs_url(mocked_get, app, connector):
265
def test_get_feature_with_no_wfs_url(fake_http, app, connector):
281 266
    connector.wfs_service_url = ''
282 267
    connector.save()
283 268
    endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug)
284 269
    assert endpoint == '/opengis/test/features'
285
    mocked_get.side_effect = geoserver_responses
270

  
286 271
    resp = app.get(endpoint, params={'type_names': 'ref_metro_limites_communales', 'property_name': 'nom'})
287 272
    assert resp.json['data'] is None
288 273
    assert resp.json['err'] == 1
289 274
    assert resp.json['err_desc'] == 'no wfs URL declared'
290 275

  
291 276

  
292
@mock.patch('passerelle.utils.Request.get')
293
def test_get_feature(mocked_get, app, connector):
277
def test_get_feature(fake_http, app, connector):
294 278
    endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug)
295 279
    assert endpoint == '/opengis/test/features'
296
    mocked_get.side_effect = geoserver_responses
280

  
281
    fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES, method='GET')
282
    fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET')
297 283
    resp = app.get(endpoint, params={'type_names': 'ref_metro_limites_communales', 'property_name': 'nom'})
298
    assert mocked_get.call_args[1]['params']['REQUEST'] == 'GetFeature'
299
    assert mocked_get.call_args[1]['params']['PROPERTYNAME'] == 'nom'
300
    assert mocked_get.call_args[1]['params']['TYPENAMES'] == 'ref_metro_limites_communales'
301
    assert mocked_get.call_args[1]['params']['OUTPUTFORMAT'] == 'json'
302
    assert mocked_get.call_args[1]['params']['SERVICE'] == 'WFS'
303
    assert mocked_get.call_args[1]['params']['VERSION'] == connector.get_wfs_service_version()
284
    assert fake_http.last_request.GET['REQUEST'] == 'GetFeature'
285
    assert fake_http.last_request.GET['PROPERTYNAME'] == 'nom'
286
    assert fake_http.last_request.GET['TYPENAMES'] == 'ref_metro_limites_communales'
287
    assert fake_http.last_request.GET['OUTPUTFORMAT'] == 'json'
288
    assert fake_http.last_request.GET['SERVICE'] == 'WFS'
289
    assert fake_http.last_request.GET['VERSION'] == connector.get_wfs_service_version()
304 290
    assert len(resp.json['data']) == 7
305 291
    for item in resp.json['data']:
306 292
        assert 'text' in item
307 293

  
308 294

  
309
@mock.patch('passerelle.utils.Request.get')
310
def test_get_filtered_feature(mocked_get, app, connector):
295
def test_get_filtered_feature(fake_http, app, connector):
311 296
    endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug)
312
    mocked_get.side_effect = geoserver_responses
297
    fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES, method='GET')
298
    fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET')
313 299
    app.get(endpoint,
314 300
            params={
315 301
                'type_names': 'ref_metro_limites_communales',
316 302
                'property_name': 'nom',
317 303
                'cql_filter': 'nom=\'Fontaine\''
318 304
            })
319
    assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\''
305
    assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\''
320 306

  
321 307

  
322
@mock.patch('passerelle.utils.Request.get')
323
def test_get_filtered_by_property_feature(mocked_get, app, connector):
308
def test_get_filtered_by_property_feature(fake_http, app, connector):
324 309
    endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug)
325
    mocked_get.side_effect = geoserver_responses
310

  
311
    fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES, method='GET')
312
    fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET')
326 313
    params = {'type_names': 'ref_metro_limites_communales',
327 314
              'property_name': 'nom', 'cql_filter': 'nom=\'Fontaine\'',
328 315
              'filter_property_name': 'nom'}
329 316
    app.get(endpoint, params=params)
330
    assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\''
317
    assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\''
318

  
319
    fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET')
331 320
    params['q'] = 'bens'
332 321
    app.get(endpoint, params=params)
333
    assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom LIKE \'%bens%\''
322
    assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom LIKE \'%bens%\''
323

  
324
    fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET')
334 325
    params['case-insensitive'] = True
335 326
    app.get(endpoint, params=params)
336
    assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom ILIKE \'%bens%\''
327
    assert fake_http.last_request.GET['CQL_FILTER'] == 'nom=\'Fontaine\' AND nom ILIKE \'%bens%\''
328

  
329
    fake_http.add_response(status_code=200, content=FAKE_FEATURES_JSON, method='GET')
337 330
    params.pop('cql_filter')
338 331
    app.get(endpoint, params=params)
339
    assert 'CQL_FILTER' not in mocked_get.call_args[1]['params']
332
    assert 'CQL_FILTER' not in fake_http.last_request.GET
340 333

  
341 334

  
342
@mock.patch('passerelle.utils.Request.get')
343
def test_get_feature_error(mocked_get, app, connector):
335
def test_get_feature_error(fake_http, app, connector):
344 336
    endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug)
345 337
    assert endpoint == '/opengis/test/features'
346
    mocked_get.side_effect = geoserver_responses_errors
338

  
339
    fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
340
    fake_http.add_response(status_code=200, content=FAKE_ERROR)
347 341
    resp = app.get(endpoint, params={
348 342
        'type_names': 'ref_metro_limites_communales',
349 343
        'property_name': 'nom'
350 344
    })
351
    assert mocked_get.call_args[1]['params']['REQUEST'] == 'GetFeature'
352
    assert mocked_get.call_args[1]['params']['PROPERTYNAME'] == 'nom'
353
    assert mocked_get.call_args[1]['params']['TYPENAMES'] == 'ref_metro_limites_communales'
354
    assert mocked_get.call_args[1]['params']['OUTPUTFORMAT'] == 'json'
355
    assert mocked_get.call_args[1]['params']['SERVICE'] == 'WFS'
356
    assert mocked_get.call_args[1]['params']['VERSION'] == connector.get_wfs_service_version()
345
    assert fake_http.last_request.GET['REQUEST'] == 'GetFeature'
346
    assert fake_http.last_request.GET['PROPERTYNAME'] == 'nom'
347
    assert fake_http.last_request.GET['TYPENAMES'] == 'ref_metro_limites_communales'
348
    assert fake_http.last_request.GET['OUTPUTFORMAT'] == 'json'
349
    assert fake_http.last_request.GET['SERVICE'] == 'WFS'
350
    assert fake_http.last_request.GET['VERSION'] == connector.get_wfs_service_version()
357 351
    result = resp.json
358 352
    assert result['err'] == 1
359 353
    assert result['err_desc'] == 'OpenGIS Error: NoApplicableCode'
360 354
    assert 'Could not parse' in result['data']['text']
361 355

  
362 356

  
363
@mock.patch('passerelle.utils.Request.get')
364
def test_get_feature_error2(mocked_get, app, connector):
357
def test_get_feature_error2(fake_http, app, connector):
365 358
    endpoint = utils.generic_endpoint_url('opengis', 'features', slug=connector.slug)
366 359
    assert endpoint == '/opengis/test/features'
367
    mocked_get.side_effect = geoserver_responses_errors_unparsable
360

  
361
    fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
362
    fake_http.add_response(status_code=200, content=FAKE_ERROR[:10])
368 363
    resp = app.get(endpoint, params={
369 364
        'type_names': 'ref_metro_limites_communales',
370 365
        'property_name': 'nom'
371 366
    })
372
    assert mocked_get.call_args[1]['params']['REQUEST'] == 'GetFeature'
373
    assert mocked_get.call_args[1]['params']['PROPERTYNAME'] == 'nom'
374
    assert mocked_get.call_args[1]['params']['TYPENAMES'] == 'ref_metro_limites_communales'
375
    assert mocked_get.call_args[1]['params']['OUTPUTFORMAT'] == 'json'
376
    assert mocked_get.call_args[1]['params']['SERVICE'] == 'WFS'
377
    assert mocked_get.call_args[1]['params']['VERSION'] == connector.get_wfs_service_version()
367
    assert fake_http.last_request.GET['REQUEST'] == 'GetFeature'
368
    assert fake_http.last_request.GET['PROPERTYNAME'] == 'nom'
369
    assert fake_http.last_request.GET['TYPENAMES'] == 'ref_metro_limites_communales'
370
    assert fake_http.last_request.GET['OUTPUTFORMAT'] == 'json'
371
    assert fake_http.last_request.GET['SERVICE'] == 'WFS'
372
    assert fake_http.last_request.GET['VERSION'] == connector.get_wfs_service_version()
378 373
    result = resp.json
379 374
    assert result['err'] == 1
380 375
    assert result['err_desc'] == 'OpenGIS Error: unparsable error'
381 376
    assert '<ows:' in result['data']['content']
382 377

  
383 378

  
384
@mock.patch('passerelle.utils.Request.get')
385
def test_reverse_geocoding(mocked_get, app, connector):
379
def test_reverse_geocoding(fake_http, app, connector):
386 380
    connector.search_radius = 45
387 381
    connector.projection = 'EPSG:3945'
388 382
    connector.save()
389 383
    endpoint = utils.generic_endpoint_url('opengis', 'reverse', slug=connector.slug)
390 384
    assert endpoint == '/opengis/test/reverse'
391 385

  
392
    def side_effect(url, **kwargs):
393
        if kwargs['params'].get('request') == 'GetCapabilities':
394
            return utils.FakedResponse(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
395
        return mock.DEFAULT
396
    mocked_get.side_effect = side_effect
397
    mocked_get.return_value = utils.FakedResponse(content=FAKE_GEOLOCATED_FEATURE, status_code=200)
386
    fake_http.set_response(status_code=200, content=FAKE_SERVICE_CAPABILITIES)
387
    fake_http.add_response(content=FAKE_GEOLOCATED_FEATURE, status_code=200)
388

  
398 389
    resp = app.get(endpoint,
399 390
                   params={
400 391
                       'lat': '45.1893469606986',
401 392
                       'lon': '5.72462060798'
402 393
                   })
403
    assert (mocked_get.call_args[1]['params']['CQL_FILTER']
394
    assert (fake_http.last_request.GET['CQL_FILTER']
404 395
            == 'DWITHIN(the_geom,Point(1914061.48604 4224640.45779),45,meters)')
405 396
    assert resp.json['lon'] == '5.72407744145'
406 397
    assert resp.json['lat'] == '45.1893972656'
......
412 403
    connector.projection = 'EPSG:4326'
413 404
    connector.search_radius = 10
414 405
    connector.save()
415
    mocked_get.return_value = utils.FakedResponse(content='{"features": []}', status_code=200)
406

  
407
    fake_http.set_response(status_code=200, content='{"features": []}')
416 408
    resp = app.get(
417 409
        endpoint,
418 410
        params={
419 411
            'lat': '45.183784',
420 412
            'lon': '5.714885'
421 413
        })
422
    assert mocked_get.call_args[1]['params']['CQL_FILTER'] == 'DWITHIN(the_geom,Point(5.714885 45.183784),10,meters)'
414
    assert fake_http.last_request.GET['CQL_FILTER'] == 'DWITHIN(the_geom,Point(5.714885 45.183784),10,meters)'
423 415
    assert resp.json['err'] == 1
424 416
    assert resp.json['err_desc'] == 'Unable to geocode'
425 417

  
426
    mocked_get.return_value = utils.FakedResponse(status_code=404, content='{}', ok=False)
418
    fake_http.set_response(status_code=404, content='{}')
427 419
    resp = app.get(endpoint,
428 420
                   params={
429 421
                       'lat': '45.183784',
tests/test_planitech.py
1
import json
1 2
from datetime import datetime
2 3

  
3 4
from django.contrib.contenttypes.models import ContentType
......
100 101
    return mock_call_planitech
101 102

  
102 103

  
103
def test_call_planitech(connector, monkeypatch):
104

  
105
    class MockResponse(object):
106

  
107
        status_code = 200
108
        content = None
109

  
110
        def __init__(self, content=None, status_code=None):
111
            if content is not None:
112
                self.content = content
113
            if status_code is not None:
114
                self.status_code = status_code
115

  
116
        def session_meth(self, *args, **kwargs):
117
            return self
118

  
119
        def json(self):
120
            return mste.encode(self.content)
121

  
104
def test_call_planitech(fake_http, connector, monkeypatch):
122 105
    connector._planitech_session = True
123 106

  
124
    response = MockResponse(content='somestring')
125
    assert connector._call_planitech(response.session_meth, 'endpoint') == "somestring"
107
    def set_response(status_code, content):
108
        content = json.dumps(mste.encode(content))
109
        fake_http.set_response(status_code=status_code, content=content)
110

  
111
    set_response(status_code=200, content='somestring')
112
    assert connector._call_planitech(connector.requests.get, 'endpoint') == "somestring"
126 113

  
127
    response = MockResponse(content=set(), status_code=400)
114
    set_response(status_code=400, content=[])
128 115
    with pytest.raises(APIError) as excinfo:
129
        connector._call_planitech(response.session_meth, 'endpoint')
116
        connector._call_planitech(connector.requests.get, 'endpoint')
130 117
    assert str(excinfo.value) == 'Planitech error 400'
131 118

  
132
    response = MockResponse(content='unexpected error format', status_code=400)
119
    set_response(status_code=400, content='unexpected error format')
133 120
    with pytest.raises(APIError) as excinfo:
134
        connector._call_planitech(response.session_meth, 'endpoint')
121
        connector._call_planitech(connector.requests.get, 'endpoint')
135 122
    assert str(excinfo.value) == 'Planitech error 400'
136 123

  
137
    response = MockResponse(content={'errors': 'planitech error message'}, status_code=400)
124
    set_response(status_code=400, content={'errors': 'planitech error message'})
138 125
    with pytest.raises(APIError) as excinfo:
139
        connector._call_planitech(response.session_meth, 'endpoint')
126
        connector._call_planitech(connector.requests.get, 'endpoint')
140 127
    assert str(excinfo.value) == 'Planitech error 400 - planitech error message'
141 128

  
142 129

  
tests/test_requests.py
3 3
import pytest
4 4
import mohawk
5 5
import mock
6
from httmock import urlmatch, HTTMock, response
7 6

  
8 7
from django.test import override_settings
9 8

  
10 9
from passerelle.utils import Request, CaseInsensitiveDict
11 10
from passerelle.utils.http_authenticators import HawkAuth
12
import utils
13 11
from utils import FakedResponse
14 12

  
15 13

  
......
32 30
def log_level(request):
33 31
    return request.param
34 32

  
35
@urlmatch(netloc=r'(.*\.)?httpbin\.org$')
36
def httpbin_mock(url, request):
37
    return response(200, {"message": "Are you really josh ?"},
38
                    headers={"Content-Type": "application/json"}, request=request)
39 33

  
40
@urlmatch(netloc=r'(.*\.)?httperror\.org$')
41
def http400_mock(url, request):
42
    return response(400, {"foo": "bar"},
43
                    headers={"Content-Type": "application/json"}, request=request)
44

  
45

  
46
def test_log_level(caplog, log_level):
34
def test_log_level(fake_http, caplog, log_level):
47 35
    url = 'https://httpbin.org/post'
48 36

  
49 37
    logger = logging.getLogger('requests')
50 38
    logger.setLevel(log_level)
51 39

  
52
    with HTTMock(httpbin_mock):
53
        requests = Request(logger=logger)
54
        response = requests.post(url, json={'name':'josh'})
40
    requests = Request(logger=logger)
41
    fake_http.set_response(status_code=200, json={'message': 'Are you really josh ?'})
42
    response = requests.post(url, json={'name': 'josh'})
55 43

  
56 44
    records = [record for record in caplog.records if record.name == 'requests']
57 45

  
......
74 62
            assert not hasattr(record, 'response_content')
75 63
            assert not hasattr(record, 'response_headers')
76 64

  
77
def test_log_error(caplog, log_level):
65

  
66
def test_log_error(fake_http, caplog, log_level):
78 67
    url = 'https://httperror.org/plop'
79 68

  
80 69
    logger = logging.getLogger('requests')
81 70
    logger.setLevel(log_level)
82 71

  
83
    with HTTMock(http400_mock):
84
        requests = Request(logger=logger)
85
        response = requests.post(url, json={'name':'josh'})
72
    requests = Request(logger=logger)
73
    fake_http.set_response(status_code=400, json={'foo': 'bar'})
74
    response = requests.post(url, json={'name': 'josh'}, raise_for_status=False)
86 75

  
87 76
    records = [record for record in caplog.records if record.name == 'requests']
88 77

  
89 78
    records_length = len(records)
90 79

  
91
    if logger.level > 40:
80
    if logger.level > 20:
92 81
        assert records_length == 0
93 82
    else:
94 83
        assert records_length == 1
......
105 94
            assert not hasattr(record, 'response_content')
106 95
            assert not hasattr(record, 'response_headers')
107 96

  
108
@pytest.fixture(params=['xml', 'whatever', 'jpeg', 'pdf'])
109
def endpoint_response(request):
110
    response_request = mock.Mock(
111
        headers={'Accept': '*/*', 'Authorization': 'Basic dG9rZW46dG9rZW4='}, body=None)
112
    xml = FakedResponse(
113
        headers={'Content-Type': 'application/xml; charset=charset=utf-8'}, status_code=200,
114
        content='<tests><test>xml test</test></tests>', request=response_request)
115

  
116
    whatever = FakedResponse(
117
        headers={'Content-Type': 'texto/csv'}, status_code=200,
118
        content='username;age\ntoken;10\ncartman:10', request=response_request)
119

  
120
    jpeg = FakedResponse(
121
        headers={'Content-Type': 'image/jpeg'}, status_code=200,
122
        content='binary content to be ignored', request=response_request)
123

  
124
    pdf = FakedResponse(
125
        headers={'Content-Type': 'application/pdf'}, status_code=200,
126
        content='binary content to be ignored', request=response_request)
127 97

  
128
    return locals().get(request.param)
129

  
130

  
131
@mock.patch('passerelle.utils.RequestSession.send')
132
def test_skip_content_type(mocked_get, caplog, endpoint_response):
133
    mocked_get.return_value = endpoint_response
98
@pytest.fixture(params=['xml', 'whatever', 'jpeg', 'pdf'])
99
def setup_endpoint_response(request, fake_http):
100
    def do():
101
        if request.param == 'xml':
102
            fake_http.set_response(
103
                status_code=200,
104
                headers={'Content-Type': 'application/xml; charset=charset=utf-8'},
105
                content='<tests><test>xml test</test></tests>')
106
        elif request.param == 'whatever':
107
            fake_http.set_response(
108
                status_code=200,
109
                headers={'Content-Type': 'texto/csv'},
110
                content='username;age\ntoken;10\ncartman:10')
111
        elif request.param == 'jpeg':
112
            fake_http.set_response(
113
                status_code=200,
114
                headers={'Content-Type': 'image/jpeg'},
115
                content='binary content to be ignored')
116
        elif request.param == 'pdf':
117
            fake_http.set_response(
118
                status_code=200,
119
                headers={'Content-Type': 'application/pdf'},
120
                content='binary content to be ignored')
121
        return fake_http
122
    do.param = request.param
123
    return do
124

  
125

  
126
def test_skip_content_type(request, caplog, setup_endpoint_response):
127
    # XXX: what is tested here ? I dunno :/
134 128
    logger = logging.getLogger('requests')
135 129
    logger.setLevel(logging.DEBUG)
136 130
    requests = Request(logger=logger)
137
    response = requests.get('http://example.net/whatever').body
131

  
132
    setup_endpoint_response()
133
    requests.get(
134
        'http://example.net/whatever',
135
        headers={'Accept': '*/*', 'Authorization': 'Basic dG9rZW46dG9rZW4='}
136
    )
138 137
    records = [record for record in caplog.records if record.name == 'requests']
139 138

  
140
    if 'xml' in endpoint_response.headers.get('Content-Type'):
141
        assert len(records) == 1
139
    assert len(records) == 1
140
    if setup_endpoint_response.param == 'xml':
142 141
        assert records[0].response_content == "'<tests><test>xml test</test></tests>'"
143
    else:
144
        assert len(records) == 1
145 142

  
146 143

  
147 144
@mock.patch('passerelle.utils.RequestSession.request')
148
def test_proxies(mocked_get, caplog, endpoint_response):
149
    mocked_get.return_value = endpoint_response
145
def test_proxies(mocked_get, caplog):
150 146
    logger = logging.getLogger('requests')
147

  
151 148
    Request(logger=logger).get('http://example.net/whatever')
152 149
    assert mocked_get.call_args[1].get('proxies') is None
153
    Request(logger=logger).get('http://example.net/whatever',
154
                                     proxies={'http': 'http://proxy'})
150

  
151
    Request(logger=logger).get('http://example.net/whatever', proxies={'http': 'http://proxy'})
155 152
    assert mocked_get.call_args[1].get('proxies') == {'http': 'http://proxy'}
156 153

  
157 154
    with override_settings(REQUESTS_PROXIES={'http': 'http://globalproxy'}):
158 155
        Request(logger=logger).get('http://example.net/whatever')
159 156
        assert mocked_get.call_args[1].get('proxies') == {'http': 'http://globalproxy'}
160
        Request(logger=logger).get('http://example.net/whatever',
161
                                         proxies={'http': 'http://proxy'})
157
        Request(logger=logger).get('http://example.net/whatever', proxies={'http': 'http://proxy'})
162 158
        assert mocked_get.call_args[1].get('proxies') == {'http': 'http://proxy'}
163 159

  
164 160
    # with a linked resource
......
188 184

  
189 185

  
190 186
@mock.patch('passerelle.utils.RequestSession.request')
191
def test_resource_auth(mocked_get, caplog, endpoint_response):
192
    mocked_get.return_value = endpoint_response
187
def test_resource_auth(mocked_get, caplog):
193 188
    logger = logging.getLogger('requests')
194 189
    resource = MockResource()
195 190
    request = Request(resource=resource, logger=logger)
......
211 206
    request.get('http://example.net/whatever', auth=None)
212 207
    assert mocked_get.call_args[1].get('auth') is None
213 208

  
209

  
214 210
@mock.patch('passerelle.utils.RequestSession.send')
215
def test_resource_hawk_auth(mocked_send, caplog, endpoint_response):
216
    mocked_send.return_value = endpoint_response
211
def test_resource_hawk_auth(mocked_send):
212
    mocked_send.return_value = FakedResponse(status_code=200, headers={})
217 213
    logger = logging.getLogger('requests')
218 214
    resource = MockResource()
219 215
    request = Request(resource=resource, logger=logger)
......
221 217
    credentials = {'id': 'id', 'key': 'key', 'algorithm': 'sha256'}
222 218
    hawk_auth = HawkAuth(**credentials)
223 219

  
224
    resp = request.get('http://httpbin.org/get', auth=hawk_auth)
220
    request.get('http://httpbin.org/get', auth=hawk_auth)
225 221
    prepared_method = mocked_send.call_args[0][0]
226 222
    assert 'Authorization' in prepared_method.headers
227 223
    generated_header = prepared_method.headers['Authorization']
......
236 232
    assert dict(generated_parts) == dict(expected_parts)
237 233

  
238 234
    hawk_auth = HawkAuth(ext='extra attribute', **credentials)
239
    resp = request.post('http://httpbin.org/post', auth=hawk_auth, json={'key': 'value'})
235
    request.post('http://httpbin.org/post', auth=hawk_auth, json={'key': 'value'})
240 236
    prepared_method = mocked_send.call_args[0][0]
241 237
    assert 'Authorization' in prepared_method.headers
242 238
    generated_header = prepared_method.headers['Authorization']
......
252 248

  
253 249

  
254 250
@mock.patch('passerelle.utils.RequestSession.request')
255
def test_resource_certificates(mocked_get, caplog, endpoint_response):
256
    mocked_get.return_value = endpoint_response
251
def test_resource_certificates(mocked_get, caplog):
257 252
    logger = logging.getLogger('requests')
258 253
    resource = MockResource()
259 254
    request = Request(resource=resource, logger=logger)
......
290 285

  
291 286
    response_request = mock.Mock(headers={'Accept': '*/*'}, body=None)
292 287
    mocked_get.return_value = FakedResponse(
293
            headers={'Content-Type': 'text/plain; charset=charset=utf-8'},
294
            request=response_request,
295
            content='hello world', status_code=200)
288
        headers={'Content-Type': 'text/plain; charset=charset=utf-8'},
289
        request=response_request,
290
        content='hello world', status_code=200)
296 291

  
297 292
    # by default there is no cache
298 293
    assert request.get('http://cache.example.org/').content == 'hello world'
......
308 303

  
309 304
    # value changed
310 305
    mocked_get.return_value = FakedResponse(
311
            headers={'Content-Type': 'text/plain; charset=charset=utf-8'},
312
            request=response_request,
313
            content='hello second world', status_code=200)
306
        headers={'Content-Type': 'text/plain; charset=charset=utf-8'},
307
        request=response_request,
308
        content='hello second world', status_code=200)
314 309
    assert request.get('http://cache.example.org/', cache_duration=15).content == 'hello world'
315 310
    assert mocked_get.call_count == 1
316 311

  
......
320 315

  
321 316
    # do not cache errors
322 317
    mocked_get.return_value = FakedResponse(
323
            headers={'Content-Type': 'text/plain; charset=charset=utf-8'},
324
            request=response_request,
325
            content='no such world', status_code=404)
318
        headers={'Content-Type': 'text/plain; charset=charset=utf-8'},
319
        request=response_request,
320
        content='no such world', status_code=404)
326 321
    mocked_get.reset_mock()
327 322
    response = request.get('http://cache.example.org/404', cache_duration=15)
328 323
    assert response.content == 'no such world'
......
334 329
    # check response headers
335 330
    mocked_get.reset_mock()
336 331
    mocked_get.return_value = FakedResponse(
337
            headers=CaseInsensitiveDict({'Content-Type': 'image/png'}),
338
            request=response_request,
339
            content='hello world', status_code=200)
332
        headers=CaseInsensitiveDict({'Content-Type': 'image/png'}),
333
        request=response_request,
334
        content='hello world', status_code=200)
340 335
    assert request.get('http://cache.example.org/img', cache_duration=15).headers.get('content-type') == 'image/png'
341 336
    assert mocked_get.call_count == 1
342 337
    assert request.get('http://cache.example.org/img', cache_duration=15).headers.get('content-type') == 'image/png'
343
    assert mocked_get.call_count == 1 # got a cached response
338
    assert mocked_get.call_count == 1  # got a cached response
344 339

  
345 340

  
346 341
@mock.patch('passerelle.utils.RequestSession.request')
347
def test_timeout(mocked_get, caplog, endpoint_response):
348
    mocked_get.return_value = endpoint_response
342
def test_timeout(mocked_request, caplog):
343
    mocked_request.return_value = FakedResponse(status_code=200, headers={})
349 344
    logger = logging.getLogger('requests')
350 345

  
351 346
    Request(logger=logger).get('http://example.net/whatever')
352
    assert mocked_get.call_args[1]['timeout'] == 25
347
    assert mocked_request.call_args[1]['timeout'] == 25
353 348

  
354 349
    Request(logger=logger).get('http://example.net/whatever', timeout=42)
355
    assert mocked_get.call_args[1]['timeout'] == 42
350
    assert mocked_request.call_args[1]['timeout'] == 42
356 351
    Request(logger=logger).get('http://example.net/whatever', timeout=None)
357
    assert mocked_get.call_args[1]['timeout'] is None
352
    assert mocked_request.call_args[1]['timeout'] is None
358 353

  
359 354
    with override_settings(REQUESTS_TIMEOUT=57):
360 355
        Request(logger=logger).get('http://example.net/whatever')
361
        assert mocked_get.call_args[1]['timeout'] == 57
356
        assert mocked_request.call_args[1]['timeout'] == 57
362 357
        Request(logger=logger).get('http://example.net/whatever', timeout=42)
363
        assert mocked_get.call_args[1]['timeout'] == 42
358
        assert mocked_request.call_args[1]['timeout'] == 42
364 359
        Request(logger=logger).get('http://example.net/whatever', timeout=None)
365
        assert mocked_get.call_args[1]['timeout'] is None
360
        assert mocked_request.call_args[1]['timeout'] is None
tests/test_solis.py
127 127
                                                        'https': 'http://proxy:3128/'}
128 128

  
129 129

  
130
def test_solis_link_infos_unlink(app, solis):
130
def test_solis_link_infos_unlink(fake_http, app, solis):
131 131
    # full opened access
132 132
    api = ApiUser.objects.create(username='all', keytype='', key='')
133 133
    obj_type = ContentType.objects.get_for_model(solis)
......
135 135
                               resource_pk=solis.pk)
136 136

  
137 137
    # link
138
    with mock.patch('passerelle.utils.Request.post') as requests_post:  # get solis token
139
        with mock.patch('passerelle.utils.Request.get') as requests_get:  # get solis informations
140
            endpoint = utils.generic_endpoint_url('solis', 'apa-link', slug=solis.slug)
141
            for params in (None, '', []):
142
                resp = app.post_json(endpoint, params=params, status=200)
143
                assert requests_post.call_count == 0
144
                assert resp.json['err'] == 1
145
                assert 'payload is not a JSON dict' in resp.json['err_desc']
138
    endpoint = utils.generic_endpoint_url('solis', 'apa-link', slug=solis.slug)
139
    for params in (None, '', []):
140
        resp = app.post_json(endpoint, params=params, status=200)
141
        assert resp.json['err'] == 1
142
        assert 'payload is not a JSON dict' in resp.json['err_desc']
146 143

  
147
            for params in ({}, {'user_id': 'x'}, {'code': 'x'}, {'foo': 'bar'}):
148
                resp = app.post_json(endpoint, params=params, status=200)
149
                assert requests_post.call_count == 0
150
                assert resp.json['err'] == 1
151
                assert 'missing name_id' in resp.json['err_desc']
152
                params['name_id'] = 'xx'
153
                resp = app.post_json(endpoint, params=params, status=200)
154
                assert requests_post.call_count == 0
155
                assert resp.json['err'] == 1
156
                assert 'missing user_id/code credentials' in resp.json['err_desc']
157

  
158
            requests_post.return_value = utils.FakedResponse(content=APATOKEN_403, status_code=403)
159
            resp = app.post_json(endpoint,
160
                                 params={'user_id': 'x', 'code': 'x', 'name_id': NAMEID},
161
                                 status=200)
162
            assert requests_post.call_count == 1
163
            assert requests_get.call_count == 0
164
            assert resp.json['err'] == 1
165
            assert 'Code confidentiel non valide' in resp.json['err_desc']
166

  
167
            assert SolisAPALink.objects.count() == 0
168

  
169
            requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200)
170
            requests_get.return_value = utils.FakedResponse(content=APAINFOS['exportDonneesIndividu'],
171
                                                            status_code=200)
172
            resp = app.post_json(endpoint,
173
                                 params={'name_id': NAMEID, 'user_id': '42', 'code': 'foo'},
174
                                 status=200)
175
            assert requests_post.call_count == 2
176
            assert requests_get.call_count == 1
177
            assert resp.json['err'] == 0
178
            assert resp.json['data']['user_id'] == '42'
179
            assert resp.json['data']['created']
180
            assert not resp.json['data']['updated']
181
            assert SolisAPALink.objects.count() == 1
182
            assert SolisAPALink.objects.first().name_id == NAMEID
183
            assert SolisAPALink.objects.first().user_id == '42'
184
            assert SolisAPALink.objects.first().code == 'foo'
185
            assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)'
186

  
187
            # change code
188
            resp = app.post_json(endpoint,
189
                                 params={'name_id': NAMEID, 'user_id': '42', 'code': 'bar'},
190
                                 status=200)
191
            assert requests_post.call_count == 3
192
            assert requests_get.call_count == 2
193
            assert resp.json['err'] == 0
194
            assert resp.json['data']['user_id'] == '42'
195
            assert not resp.json['data']['created']
196
            assert resp.json['data']['updated']
197
            assert SolisAPALink.objects.count() == 1
198
            assert SolisAPALink.objects.first().name_id == NAMEID
199
            assert SolisAPALink.objects.first().user_id == '42'
200
            assert SolisAPALink.objects.first().code == 'bar'
201
            assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)'
202

  
203
            # second link
204
            resp = app.post_json(endpoint,
205
                                 params={'name_id': NAMEID, 'user_id': '53', 'code': 'bar'},
206
                                 status=200)
207
            assert requests_post.call_count == 4
208
            assert requests_get.call_count == 3
209
            assert resp.json['err'] == 0
210
            assert resp.json['data']['user_id'] == '53'
211
            assert resp.json['data']['created']
212
            assert not resp.json['data']['updated']
213
            assert SolisAPALink.objects.count() == 2
144
    for params in ({}, {'user_id': 'x'}, {'code': 'x'}, {'foo': 'bar'}):
145
        resp = app.post_json(endpoint, params=params, status=200)
146
        assert resp.json['err'] == 1
147
        assert 'missing name_id' in resp.json['err_desc']
148
        params['name_id'] = 'xx'
149
        resp = app.post_json(endpoint, params=params, status=200)
150
        assert resp.json['err'] == 1
151
        assert 'missing user_id/code credentials' in resp.json['err_desc']
152

  
153
    fake_http.set_response(content=APATOKEN_403, status_code=403, method='POST')
154
    resp = app.post_json(endpoint,
155
                         params={'user_id': 'x', 'code': 'x', 'name_id': NAMEID},
156
                         status=200)
157
    assert resp.json['err'] == 1
158
    assert 'Code confidentiel non valide' in resp.json['err_desc']
159

  
160
    assert SolisAPALink.objects.count() == 0
161

  
162
    fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
163
    fake_http.add_response(content=APAINFOS['exportDonneesIndividu'],
164
                           status_code=200,
165
                           method='GET')
166
    resp = app.post_json(endpoint,
167
                         params={'name_id': NAMEID, 'user_id': '42', 'code': 'foo'},
168
                         status=200)
169
    assert resp.json['err'] == 0
170
    assert resp.json['data']['user_id'] == '42'
171
    assert resp.json['data']['created']
172
    assert not resp.json['data']['updated']
173
    assert SolisAPALink.objects.count() == 1
174
    assert SolisAPALink.objects.first().name_id == NAMEID
175
    assert SolisAPALink.objects.first().user_id == '42'
176
    assert SolisAPALink.objects.first().code == 'foo'
177
    assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)'
178

  
179
    # change code
180
    fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
181
    fake_http.add_response(content=APAINFOS['exportDonneesIndividu'],
182
                           status_code=200,
183
                           method='GET')
184
    resp = app.post_json(endpoint,
185
                         params={'name_id': NAMEID, 'user_id': '42', 'code': 'bar'},
186
                         status=200)
187
    assert resp.json['err'] == 0
188
    assert resp.json['data']['user_id'] == '42'
189
    assert not resp.json['data']['created']
190
    assert resp.json['data']['updated']
191
    assert SolisAPALink.objects.count() == 1
192
    assert SolisAPALink.objects.first().name_id == NAMEID
193
    assert SolisAPALink.objects.first().user_id == '42'
194
    assert SolisAPALink.objects.first().code == 'bar'
195
    assert SolisAPALink.objects.first().text == 'Mme Pecile PYPPENNE (NPYNEZ)'
196

  
197
    # second link
198
    fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
199
    fake_http.add_response(content=APAINFOS['exportDonneesIndividu'],
200
                           status_code=200,
201
                           method='GET')
202
    resp = app.post_json(endpoint,
203
                         params={'name_id': NAMEID, 'user_id': '53', 'code': 'bar'},
204
                         status=200)
205
    assert resp.json['err'] == 0
206
    assert resp.json['data']['user_id'] == '53'
207
    assert resp.json['data']['created']
208
    assert not resp.json['data']['updated']
209
    assert SolisAPALink.objects.count() == 2
214 210

  
215 211
    # verify recorded names after link
216 212
    assert [x['text'] for x in SolisAPALink.objects.values('text')] == \
......
227 223

  
228 224
    # get base informations from a linked user (exportDonneesIndividu)
229 225
    changed_name = APAINFOS['exportDonneesIndividu'].replace('PYPPENNE', 'PEPONE')
230
    with mock.patch('passerelle.utils.Request.get') as requests_get:
231
        with mock.patch('passerelle.utils.Request.post') as requests_post:
232
            requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200)
233
            requests_get.return_value = utils.FakedResponse(content=changed_name, status_code=200)
234
            endpoint = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug)
235
            endpoint += '?name_id=%s&user_id=42' % NAMEID
236
            resp = app.get(endpoint, status=200)
237
            assert resp.json['err'] == 0
238
            assert resp.json['data']['individu']['nomUsuel'] == 'PEPONE'
239
            # user "text" updated in link:
240
            assert SolisAPALink.objects.get(name_id=NAMEID, user_id='42').text == \
241
                'Mme Pecile PEPONE (NPYNEZ)'
226
    fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
227
    fake_http.add_response(content=changed_name, status_code=200, method='GET')
228
    endpoint = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug)
229
    endpoint += '?name_id=%s&user_id=42' % NAMEID
230
    resp = app.get(endpoint, status=200)
231
    assert resp.json['err'] == 0
232
    assert resp.json['data']['individu']['nomUsuel'] == 'PEPONE'
233
    # user "text" updated in link:
234
    assert SolisAPALink.objects.get(name_id=NAMEID, user_id='42').text == \
235
        'Mme Pecile PEPONE (NPYNEZ)'
242 236

  
243 237
    # get all kind of informations
244 238
    for apa_endpoint in APAINFOS:
245
        with mock.patch('passerelle.utils.Request.get') as requests_get:
246
            with mock.patch('passerelle.utils.Request.post') as requests_post:
247
                requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200)
239
        endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug)
240
        resp = app.get(endpoint_base, status=400)  # missing name_id
241
        assert resp.json['err'] == 1
248 242

  
249
                endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug)
250
                resp = app.get(endpoint_base, status=400)  # missing name_id
251
                assert resp.json['err'] == 1
243
        endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s' % (NAMEID, apa_endpoint)
244
        fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
252 245

  
253
                endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s' % (NAMEID, apa_endpoint)
254
                requests_get.return_value = utils.FakedResponse(content=APAINFOS[apa_endpoint],
255
                                                                status_code=200)
256
                resp = app.get(endpoint, status=200)
257
                assert requests_post.call_count == 1  # get a token
258
                assert requests_get.call_count == 1   # get informations
259
                assert ('/asg/apa/%s' % apa_endpoint) in requests_get.call_args[0][0]
260
                assert resp.json['err'] == 0
261
                assert resp.json['data']
262

  
263
                # solis api crash
264
                requests_get.return_value = utils.FakedResponse(content='boum',
265
                                                                status_code=500)
266
                resp = app.get(endpoint, status=200)
267
                assert requests_post.call_count == 2  # get a token
268
                assert requests_get.call_count == 2   # get informations
269
                assert ('/asg/apa/%s' % apa_endpoint) in requests_get.call_args[0][0]
270
                assert resp.json['err'] == 1
271
                assert resp.json['err_desc'].startswith('error status:500')
272
                assert resp.json['data'] == {'json_content': None, 'status_code': 500}
246
        fake_http.add_response(content=APAINFOS[apa_endpoint], status_code=200, method='GET')
247
        resp = app.get(endpoint, status=200)
248
        assert ('/asg/apa/%s' % apa_endpoint) in fake_http.last_request.url
249
        assert resp.json['err'] == 0
250
        assert resp.json['data']
273 251

  
274
                requests_get.return_value = utils.FakedResponse(content='{"error":"foobar"}',
275
                                                                status_code=500)
276
                resp = app.get(endpoint, status=200)
277
                assert resp.json['err'] == 1
278
                assert resp.json['err_desc'].startswith('error status:500')
279
                assert resp.json['data'] == {'json_content': {'error': 'foobar'}, 'status_code': 500}
252
        # solis api crash
253
        fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
280 254

  
281
                # unknown name_id or user_id
282
                for qs in ('name_id=%s&user_id=XXX' % NAMEID, 'name_id=unlinked&user_id=53'):
283
                    endpoint = endpoint_base + ('?information=%s' % apa_endpoint) + '&' + qs
284
                    resp = app.get(endpoint, status=200)
285
                    assert resp.json['err'] == 1
286
                    assert resp.json['err_desc'] == 'unknown link'
287
                    assert resp.json['data'] is None
255
        fake_http.add_response(content='boum', status_code=500, method='GET')
256
        resp = app.get(endpoint, status=200)
257
        assert ('/asg/apa/%s' % apa_endpoint) in fake_http.last_request.url
258
        assert resp.json['err'] == 1
259
        assert resp.json['err_desc'].startswith('error status:500')
260
        assert resp.json['data'] == {'json_content': None, 'status_code': 500}
288 261

  
289
    # get info about a specific request
290
    with mock.patch('passerelle.utils.Request.get') as requests_get:
291
        with mock.patch('passerelle.utils.Request.post') as requests_post:
292
            requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200)
293
            endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug)
262
        fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
263
        fake_http.add_response(content='{"error":"foobar"}', status_code=500, method='GET')
264
        resp = app.get(endpoint, status=200)
265
        assert resp.json['err'] == 1
266
        assert resp.json['err_desc'].startswith('error status:500')
267
        assert resp.json['data'] == {'json_content': {'error': 'foobar'}, 'status_code': 500}
294 268

  
295
            # via demandeUnitaire
296
            endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire&index=42' % NAMEID
297
            requests_get.return_value = utils.FakedResponse(content=APAREQUEST, status_code=200)
298
            resp = app.get(endpoint, status=200)
299
            assert requests_post.call_count == 1  # get a token
300
            assert requests_get.call_count == 1  # get demandeUnitaire
301
            url = requests_get.call_args[0][0]
302
            assert '/asg/apa/demandeUnitaire/' in url
303
            assert url.endswith('/42')
304
            assert resp.json['err'] == 0
305
            assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42
306

  
307
            requests_post.reset_mock()
308
            requests_get.reset_mock()
309
            requests_get.return_value = utils.FakedResponse(content='nothing here', status_code=404)
269
        # unknown name_id or user_id
270
        for qs in ('name_id=%s&user_id=XXX' % NAMEID, 'name_id=unlinked&user_id=53'):
271
            endpoint = endpoint_base + ('?information=%s' % apa_endpoint) + '&' + qs
310 272
            resp = app.get(endpoint, status=200)
311
            assert requests_post.call_count == 1  # get a token
312
            assert requests_get.call_count == 1  # get demandeUnitaire
313
            url = requests_get.call_args[0][0]
314
            assert '/asg/apa/demandeUnitaire/' in url
315
            assert url.endswith('/42')
316
            assert resp.json['err'] == 1
317
            assert resp.json['err_desc'].startswith('error status:404')
318

  
319
            # missing index
320
            requests_post.reset_mock()
321
            requests_get.reset_mock()
322
            endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire' % NAMEID
323
            resp = app.get(endpoint, status=400)
324
            requests_get.assert_not_called()
325
            requests_post.assert_not_called()
326 273
            assert resp.json['err'] == 1
274
            assert resp.json['err_desc'] == 'unknown link'
275
            assert resp.json['data'] is None
327 276

  
328
            # get indexDemande 42 in lists
329
            for information in ('consultationDeMesDroits', 'suiviDemandeHistorique', 'propositionPlanAide',):
330
                requests_post.reset_mock()
331
                requests_get.reset_mock()
332
                endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=42' % (NAMEID, information)
333
                requests_get.return_value = utils.FakedResponse(content=APAINFOS[information], status_code=200)
334
                resp = app.get(endpoint, status=200)
335
                assert ('/asg/apa/%s/' % information) in requests_get.call_args[0][0]
336
                requests_post.assert_called_once()
337
                requests_get.assert_called_once()
338
                assert resp.json['err'] == 0
339
                assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42
340

  
341
                endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=57' % (NAMEID, information)
342
                resp = app.get(endpoint, status=200)
343
                assert ('/asg/apa/%s/' % information) in requests_get.call_args[0][0]
344
                assert requests_post.call_count == 2
345
                assert requests_get.call_count == 2
346
                assert resp.json['err'] == 1
347
                assert resp.json['err_desc'] == 'cannot find indexDemande=57 in demandeAsg list'
277
    # get info about a specific request
278
    endpoint_base = utils.generic_endpoint_url('solis', 'apa-user-info', slug=solis.slug)
279

  
280
    # via demandeUnitaire
281
    endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire&index=42' % NAMEID
282
    fake_http.set_response(content=APATOKEN, status_code=200, method='POST')
283
    fake_http.add_response(content=APAREQUEST, status_code=200, method='GET')
284
    resp = app.get(endpoint, status=200)
285
    assert '/asg/apa/demandeUnitaire/' in fake_http.last_request.url
286
    assert fake_http.last_request.url.endswith('/42')
287
    assert resp.json['err'] == 0
288
    assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42
289

  
290
    fake_http.set_response(content=APATOKEN, status_code=200, method='POST')
291
    fake_http.add_response(content='nothing here', status_code=404, method='GET')
292
    resp = app.get(endpoint, status=200)
293
    assert '/asg/apa/demandeUnitaire/' in fake_http.last_request.url
294
    assert fake_http.last_request.url.endswith('/42')
295
    assert resp.json['err'] == 1
296
    assert resp.json['err_desc'].startswith('error status:404')
297

  
298
    # missing index
299
    fake_http.reset()
300
    endpoint = endpoint_base + '?name_id=%s&user_id=53&information=demandeUnitaire' % NAMEID
301
    resp = app.get(endpoint, status=400)
302
    assert resp.json['err'] == 1
303

  
304
    # get indexDemande 42 in lists
305
    for information in ('consultationDeMesDroits', 'suiviDemandeHistorique', 'propositionPlanAide',):
306
        endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=42' % (NAMEID, information)
307
        fake_http.set_response(content=APATOKEN, status_code=200, method='POST')
308
        fake_http.add_response(content=APAINFOS[information], status_code=200, method='GET')
309
        resp = app.get(endpoint, status=200)
310
        assert ('/asg/apa/%s/' % information) in fake_http.last_request.url
311
        assert resp.json['err'] == 0
312
        assert resp.json['data']['demandeAsg']['demande']['indexDemande'] == 42
313

  
314
        endpoint = endpoint_base + '?name_id=%s&user_id=53&information=%s&index=57' % (NAMEID, information)
315
        fake_http.set_response(content=APATOKEN, status_code=200, method='POST')
316
        fake_http.add_response(content=APAINFOS[information], status_code=200, method='GET')
317
        resp = app.get(endpoint, status=200)
318
        assert ('/asg/apa/%s/' % information) in fake_http.last_request.url
319
        assert resp.json['err'] == 1
320
        assert resp.json['err_desc'] == 'cannot find indexDemande=57 in demandeAsg list'
348 321

  
349 322
    # get informations for all users (exportDonneesIndividu)
350 323
    change_info = APAINFOS['exportDonneesIndividu'].replace('PYPPENNE', 'PEPPYNE')
351
    with mock.patch('passerelle.utils.Request.get') as requests_get:
352
        with mock.patch('passerelle.utils.Request.post') as requests_post:
353
            requests_post.return_value = utils.FakedResponse(content=APATOKEN, status_code=200)
354
            requests_get.return_value = utils.FakedResponse(content=change_info, status_code=200)
355
            endpoint = utils.generic_endpoint_url('solis', 'apa-users', slug=solis.slug)
356
            endpoint += '?name_id=%s' % NAMEID
357
            resp = app.get(endpoint, status=200)
358
            assert resp.json['err'] == 0
359
            assert len(resp.json['data']) == 2
360
            assert requests_post.call_count == 2
361
            assert requests_get.call_count == 2
362
            assert set([x['id'] for x in resp.json['data']]) == set(['42', '53'])
363
            assert resp.json['data'][0]['text'] == 'Mme Pecile PEPPYNE (NPYNEZ)'
364
            # user "text" updated in links:
365
            assert [x['text'] for x in SolisAPALink.objects.values('text')] == \
366
                ['Mme Pecile PEPPYNE (NPYNEZ)', 'Mme Pecile PEPPYNE (NPYNEZ)']
324
    fake_http.set_response(content=APATOKEN, status_code=200, method='POST')
325
    fake_http.add_response(content=change_info, status_code=200, method='GET')
326
    fake_http.add_response(content=APATOKEN, status_code=200, method='POST')
327
    fake_http.add_response(content=change_info, status_code=200, method='GET')
328
    endpoint = utils.generic_endpoint_url('solis', 'apa-users', slug=solis.slug)
329
    endpoint += '?name_id=%s' % NAMEID
330
    resp = app.get(endpoint, status=200)
331
    assert resp.json['err'] == 0
332
    assert len(resp.json['data']) == 2
333
    assert set([x['id'] for x in resp.json['data']]) == set(['42', '53'])
334
    assert resp.json['data'][0]['text'] == 'Mme Pecile PEPPYNE (NPYNEZ)'
335
    # user "text" updated in links:
336
    assert [x['text'] for x in SolisAPALink.objects.values('text')] == \
337
        ['Mme Pecile PEPPYNE (NPYNEZ)', 'Mme Pecile PEPPYNE (NPYNEZ)']
338
    fake_http.reset()
367 339

  
368 340
    # unlink
369 341
    endpoint = utils.generic_endpoint_url('solis', 'apa-unlink', slug=solis.slug)
......
399 371
    assert resp.json['data'] is None
400 372

  
401 373

  
402
def test_solis_referentiels(app, solis):
374
def test_solis_referentiels(fake_http, app, solis):
403 375
    # full opened access
404 376
    api = ApiUser.objects.create(username='all', keytype='', key='')
405 377
    obj_type = ContentType.objects.get_for_model(solis)
406 378
    AccessRight.objects.create(codename='can_access', apiuser=api, resource_type=obj_type,
407 379
                               resource_pk=solis.pk)
408 380

  
409
    with mock.patch('passerelle.utils.Request.get') as requests_get:
410
        requests_get.return_value = utils.FakedResponse(content=DEPARTEMENTS, status_code=200)
411
        url = utils.generic_endpoint_url('solis', 'referential', slug=solis.slug)
381
    fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET')
382
    url = utils.generic_endpoint_url('solis', 'referential', slug=solis.slug)
412 383

  
413
        resp = app.get(url + '/trans/departement/', status=200)
414
        assert requests_get.call_count == 1
415
        assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/trans/departement')
416
        assert resp.json['err'] == 0
417
        assert len(resp.json['data']) == 8
384
    resp = app.get(url + '/trans/departement/', status=200)
385
    assert fake_http.last_request.url.endswith('/solisapi/referentiels/trans/departement')
386
    assert resp.json['err'] == 0
387
    assert len(resp.json['data']) == 8
418 388

  
419
        resp = app.get(url + '/trans/departement/?q=ardeche', status=200)
420
        assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/trans/departement')
421
        assert resp.json['err'] == 0
422
        assert len(resp.json['data']) == 1
423
        assert resp.json['data'][0]['text'] == u'Ardèche'
389
    fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET')
390
    resp = app.get(url + '/trans/departement/?q=ardeche', status=200)
391
    assert fake_http.last_request.url.endswith('/solisapi/referentiels/trans/departement')
392
    assert resp.json['err'] == 0
393
    assert len(resp.json['data']) == 1
394
    assert resp.json['data'][0]['text'] == u'Ardèche'
424 395

  
425
        resp = app.get(url + '/trans/departement/?q=arde', status=200)
426
        assert resp.json['err'] == 0
427
        assert len(resp.json['data']) == 2
428
        assert (resp.json['data'][0]['text'], resp.json['data'][1]['text']) == (u'Ardèche', 'Ardennes')
396
    fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET')
397
    resp = app.get(url + '/trans/departement/?q=arde', status=200)
398
    assert resp.json['err'] == 0
399
    assert len(resp.json['data']) == 2
400
    assert (resp.json['data'][0]['text'], resp.json['data'][1]['text']) == (u'Ardèche', 'Ardennes')
429 401

  
430
        resp = app.get(url + '/trans/departement/?q=arde&ignore=8', status=200)
431
        assert resp.json['err'] == 0
432
        assert len(resp.json['data']) == 1
433
        assert resp.json['data'][0]['text'] == u'Ardèche'
402
    fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET')
403
    resp = app.get(url + '/trans/departement/?q=arde&ignore=8', status=200)
404
    assert resp.json['err'] == 0
405
    assert len(resp.json['data']) == 1
406
    assert resp.json['data'][0]['text'] == u'Ardèche'
434 407

  
435
        resp = app.get(url + '/trans/departement/?q=arde&ignore=8,, 7', status=200)
436
        assert resp.json['err'] == 0
437
        assert len(resp.json['data']) == 0
408
    fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET')
409
    resp = app.get(url + '/trans/departement/?q=arde&ignore=8,, 7', status=200)
410
    assert resp.json['err'] == 0
411
    assert len(resp.json['data']) == 0
438 412

  
439
        resp = app.get(url + '/trans/departement/?codePays=79&foo=bar', status=200)
440
        assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/trans/departement?codePays=79')
413
    fake_http.set_response(content=DEPARTEMENTS, status_code=200, method='GET')
414
    resp = app.get(url + '/trans/departement/?codePays=79&foo=bar', status=200)
415
    assert fake_http.last_request.url.endswith('/solisapi/referentiels/trans/departement?codePays=79')
441 416

  
442
        requests_get.return_value = utils.FakedResponse(content='{"nada":0}', status_code=404,
443
                                                        reason='Not found')
444
        resp = app.get(url + '/foo/bar/', status=200)
445
        assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/foo/bar')
446
        assert resp.json['err'] == 1
447
        assert resp.json['err_desc'] == "error status:404 'Not found', content:'{\"nada\":0}'"
448
        assert resp.json['data'] == {'json_content': {'nada': 0}, 'status_code': 404}
417
    fake_http.set_response(content='{"nada":0}', status_code=404, reason='Not found', method='GET')
418
    resp = app.get(url + '/foo/bar/', status=200)
419
    assert fake_http.last_request.url.endswith('/solisapi/referentiels/foo/bar')
420
    assert resp.json['err'] == 1
421
    assert resp.json['err_desc'] == "error status:404 'Not found', content:'{\"nada\":0}'"
422
    assert resp.json['data'] == {'json_content': {'nada': 0}, 'status_code': 404}
449 423

  
450
        requests_get.return_value = utils.FakedResponse(content='crash', status_code=500, reason='boum')
451
        resp = app.get(url + '/foo/bar/', status=200)
452
        assert requests_get.call_args[0][0].endswith('/solisapi/referentiels/foo/bar')
453
        assert resp.json['err'] == 1
454
        assert resp.json['err_desc'] == "error status:500 'boum', content:'crash'"
455
        assert resp.json['data'] == {'json_content': None, 'status_code': 500}
424
    fake_http.set_response(content='crash', status_code=500, reason='boum', method='GET')
425
    resp = app.get(url + '/foo/bar/', status=200)
426
    assert fake_http.last_request.url.endswith('/solisapi/referentiels/foo/bar')
427
    assert resp.json['err'] == 1
428
    assert resp.json['err_desc'] == "error status:500 'boum', content:'crash'"
429
    assert resp.json['data'] == {'json_content': None, 'status_code': 500}
456 430

  
457 431

  
458 432
def test_unflat_dict():
459 433
    assert unflat({'foo': 'bar', 'two_foo': 'one', 'two_bar': 'two'}) == {'foo': 'bar', 'two': {'foo': 'one', 'bar': 'two'}}
460 434

  
461 435

  
462
def test_solis_apa_integration(app, solis):
436
def test_solis_apa_integration(fake_http, app, solis):
463 437
    api = ApiUser.objects.create(username='all', keytype='', key='')
464 438
    obj_type = ContentType.objects.get_for_model(solis)
465 439
    AccessRight.objects.create(codename='can_access', apiuser=api, resource_type=obj_type,
466 440
                               resource_pk=solis.pk)
467 441

  
468
    with mock.patch('passerelle.utils.Request.post') as requests_post:
469
        def integration_ok(*args, **kwargs):
470
            return utils.FakedResponse(content='', status_code=204)
471
        requests_post.return_value = utils.FakedResponse(content='', status_code=204)
472
        # requests_post.side_effect = [utils.FakedResponse(content='', status_code=204)]
473
        url = utils.generic_endpoint_url('solis', 'apa-integration', slug=solis.slug)
474

  
475
        demande = {
476
            "beneficiaire_demande_aide": "APAD",
477
            "beneficiaire_demande_dateDepot": "2018-02-09",
478
            "beneficiaire_etatCivil_civilite": "M",
479
            "beneficiaire_etatCivil_contact_courriel": "benef@yopmail.com",
480
            "conjoint_nom": "Conjnom",
481
            "conjoint_prenom": "Conjprenom",
482
        }
483

  
484
        resp = app.post_json(url, params=demande, status=200)
485

  
486
        requests_post.assert_called_once()
487
        assert requests_post.call_args[0][0].endswith('/solisapi/asg/apa/integrationDemandeApa')
488
        assert requests_post.call_args[1]['json']['demandeApa']['beneficiaire']['demande']['aide'] == 'APAD'
489
        assert requests_post.call_args[1]['json']['demandeApa']['conjoint']['nom'] == 'Conjnom'
490
        assert requests_post.call_args[1]['json']['demandeApa'] == unflat(demande)
491
        assert resp.json['err'] == 0
492
        assert resp.json['data'] is None
493

  
494
        # don't send "conjoint" dict to Solis
495
        requests_post.reset_mock()
496
        demande['del:conjoint'] = True
497
        resp = app.post_json(url, params=demande, status=200)
498
        requests_post.assert_called_once()
499
        assert 'conjoint' not in requests_post.call_args[1]['json']['demandeApa']
500
        assert resp.json['err'] == 0
442
    def integration_ok(*args, **kwargs):
443
        return utils.FakedResponse(content='', status_code=204)
501 444

  
502
        # send "conjoint" dict to Solis
503
        requests_post.reset_mock()
504
        demande['del:conjoint'] = False
505
        resp = app.post_json(url, params=demande, status=200)
506
        requests_post.assert_called_once()
507
        assert requests_post.call_args[1]['json']['demandeApa']['conjoint']['nom'] == 'Conjnom'
508
        assert resp.json['err'] == 0
445
    # requests_post.side_effect = [utils.FakedResponse(content='', status_code=204)]
446
    url = utils.generic_endpoint_url('solis', 'apa-integration', slug=solis.slug)
509 447

  
510
        # add files
511
        requests_post.reset_mock()
512
        requests_post.side_effect = [
513
            utils.FakedResponse(content='{"id": "foo", "nbFichiersAcceptes": 3}', status_code=200),
514
            utils.FakedResponse(content='', status_code=204)]
515
        demande['file:etat_civil_001.pdf'] = {
516
            'content': 'JVBERmZha2U=',
517
            'content_type': 'application/pdf',
518
            'filename': 'whatever.pdf',
519
        }
520
        demande['file:etat_civil_002.pdf'] = {
521
            # jpeg, will be converted to PDF
522
            'content': '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCw'
523
                'kJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=',
524
            'content_type': 'image/jpeg',
525
            'filename': 'image.jpg',
526
        }
527
        demande['file:etat_civil_003.pdf'] = {
528
            # transparent png (RGBA), will be converted to RGB and then PDF
529
            'content': 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQ'
530
                'ABDQottAAAAABJRU5ErkJggg==',
531
            'content_type': 'image/png',
532
            'filename': 'image.png',
533
        }
534
        demande['file:etat_civil_004.pdf'] = {
535
            'content': 'Y29pbg==',  # bad content, conversion will fail
536
            'content_type': 'image/png',
537
            'filename': 'image.png',
538
        }
539
        demande['file:etat_civil_005.pdf'] = {
540
            'content': 'Y29pbg==',
541
            'content_type': 'video/mp4',  # not a image, cannot convert
542
            'filename': 'video.mp4',
543
        }
544
        demande['file:etat_civil_006.pdf'] = {
545
            'content_type': 'video/mp4',  # no content, cannot convert
546
        }
547
        demande['file:etat_civil_007.pdf'] = None
548
        resp = app.post_json(url, params=demande, status=200)
549
        assert requests_post.call_count == 2  # post files + demandeApa
550
        sent_files = requests_post.call_args_list[0][1]['files']
551
        assert len(sent_files) == 3
552
        for file_ in sent_files:
553
            assert file_[1][1].startswith('%PDF')
554
        # file entries are removed from demandeApa JSON dict
555
        assert 'file:etat_civil_001.pdf' not in requests_post.call_args[1]['json']['demandeApa']
556
        assert 'file:etat_civil_002.pdf' not in requests_post.call_args[1]['json']['demandeApa']
557
        assert resp.json['err'] == 0
558
        assert resp.json['data'] is None
559
        assert resp.json['files_sent'] == {'id': 'foo', 'nbFichiersAcceptes': 3}
560
        assert set(resp.json['files_failed_pdf_conversion']) == set(['etat_civil_004.pdf',
561
                                                                     'etat_civil_005.pdf',
562
                                                                     'etat_civil_006.pdf'])
563

  
564
        # invalid inputs
565
        requests_post.reset_mock()
566
        resp = app.post_json(url, params=['not', 'a', 'dict'], status=400)
567
        requests_post.assert_not_called()
568
        assert resp.json['err'] == 1
569
        assert resp.json['err_desc'] == 'payload is not a JSON dict'
570
        resp = app.post(url, params='coin', status=400)
571
        requests_post.assert_not_called()
572
        assert resp.json['err'] == 1
573
        assert resp.json['err_desc'] == 'payload is not a JSON object'
574

  
575
        # bad file
576
        requests_post.reset_mock()
577
        requests_post.side_effect = [
578
            utils.FakedResponse(content='{"id": "foo", "nbFichiersAcceptes": 0}', status_code=200),
579
            utils.FakedResponse(content='', status_code=204)]
580
        resp = app.post_json(url, params=demande, status=200)
581
        requests_post.assert_called_once()  # don't try to post request
582
        assert resp.json['err'] == 1
583
        assert resp.json['err_desc'] == 'fail to send all files'
584
        assert resp.json['data'] == {'id': 'foo', 'nbFichiersAcceptes': 0}
585

  
586
        # error on sending file
587
        requests_post.reset_mock()
588
        requests_post.side_effect = [
589
            utils.FakedResponse(content='{"error": 1}', status_code=500),
590
            utils.FakedResponse(content='', status_code=204)]
591
        resp = app.post_json(url, params=demande, status=200)
592
        requests_post.assert_called_once()  # don't try to post request
593
        assert resp.json['err'] == 1
594
        assert resp.json['err_desc'].startswith('error status:500')
448
    demande = {
449
        "beneficiaire_demande_aide": "APAD",
450
        "beneficiaire_demande_dateDepot": "2018-02-09",
451
        "beneficiaire_etatCivil_civilite": "M",
452
        "beneficiaire_etatCivil_contact_courriel": "benef@yopmail.com",
453
        "conjoint_nom": "Conjnom",
454
        "conjoint_prenom": "Conjprenom",
455
    }
456

  
457
    fake_http.set_response(content='', status_code=204, method='POST')
458
    resp = app.post_json(url, params=demande, status=200)
459

  
460
    assert fake_http.last_request.url.endswith('/solisapi/asg/apa/integrationDemandeApa')
461
    assert fake_http.last_request.json['demandeApa']['beneficiaire']['demande']['aide'] == 'APAD'
462
    assert fake_http.last_request.json['demandeApa']['conjoint']['nom'] == 'Conjnom'
463
    assert fake_http.last_request.json['demandeApa'] == unflat(demande)
464
    assert resp.json['err'] == 0
465
    assert resp.json['data'] is None
466

  
467
    # don't send "conjoint" dict to Solis
468
    demande['del:conjoint'] = True
469
    fake_http.set_response(content='', status_code=204, method='POST')
470
    resp = app.post_json(url, params=demande, status=200)
471
    assert 'conjoint' not in fake_http.last_request.json['demandeApa']
472
    assert resp.json['err'] == 0
473

  
474
    # send "conjoint" dict to Solis
475
    demande['del:conjoint'] = False
476
    fake_http.set_response(content='', status_code=204, method='POST')
477
    resp = app.post_json(url, params=demande, status=200)
478
    assert fake_http.last_request.json['demandeApa']['conjoint']['nom'] == 'Conjnom'
479
    assert resp.json['err'] == 0
480

  
481
    # add files
482
    demande['file:etat_civil_001.pdf'] = {
483
        'content': 'JVBERmZha2U=',
484
        'content_type': 'application/pdf',
485
        'filename': 'whatever.pdf',
486
    }
487
    demande['file:etat_civil_002.pdf'] = {
488
        # jpeg, will be converted to PDF
489
        'content': '/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCw'
490
            'kJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=',
491
        'content_type': 'image/jpeg',
492
        'filename': 'image.jpg',
493
    }
494
    demande['file:etat_civil_003.pdf'] = {
495
        # transparent png (RGBA), will be converted to RGB and then PDF
496
        'content': 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQ'
497
            'ABDQottAAAAABJRU5ErkJggg==',
498
        'content_type': 'image/png',
499
        'filename': 'image.png',
500
    }
501
    demande['file:etat_civil_004.pdf'] = {
502
        'content': 'Y29pbg==',  # bad content, conversion will fail
503
        'content_type': 'image/png',
504
        'filename': 'image.png',
505
    }
506
    demande['file:etat_civil_005.pdf'] = {
507
        'content': 'Y29pbg==',
508
        'content_type': 'video/mp4',  # not a image, cannot convert
509
        'filename': 'video.mp4',
510
    }
511
    demande['file:etat_civil_006.pdf'] = {
512
        'content_type': 'video/mp4',  # no content, cannot convert
513
    }
514
    demande['file:etat_civil_007.pdf'] = None
515

  
516
    fake_http.set_response(content='{"id": "foo", "nbFichiersAcceptes": 3}', status_code=200, method='POST')
517
    fake_http.add_response(content='', status_code=204, method='POST')
518
    resp = app.post_json(url, params=demande, status=200)
519
    sent_files = fake_http.requests[0].FILES.getlist('files')
520
    assert len(sent_files) == 3
521
    for file_ in sent_files:
522
        assert file_.read().startswith('%PDF')
523
    # file entries are removed from demandeApa JSON dict
524
    assert 'file:etat_civil_001.pdf' not in fake_http.last_request.json['demandeApa']
525
    assert 'file:etat_civil_002.pdf' not in fake_http.last_request.json['demandeApa']
526
    assert resp.json['err'] == 0
527
    assert resp.json['data'] is None
528
    assert resp.json['files_sent'] == {'id': 'foo', 'nbFichiersAcceptes': 3}
529
    assert set(resp.json['files_failed_pdf_conversion']) == set(['etat_civil_004.pdf',
530
                                                                 'etat_civil_005.pdf',
531
                                                                 'etat_civil_006.pdf'])
532

  
533
    # invalid inputs
534
    fake_http.reset()
535
    resp = app.post_json(url, params=['not', 'a', 'dict'], status=400)
536
    assert resp.json['err'] == 1
537
    assert resp.json['err_desc'] == 'payload is not a JSON dict'
538
    resp = app.post(url, params='coin', status=400)
539
    assert resp.json['err'] == 1
540
    assert resp.json['err_desc'] == 'payload is not a JSON object'
541

  
542
    # bad file
543
    fake_http.set_response(content='{"id": "foo", "nbFichiersAcceptes": 0}', status_code=200, method='POST')
544
    resp = app.post_json(url, params=demande, status=200)
545
    assert resp.json['err'] == 1
546
    assert resp.json['err_desc'] == 'fail to send all files'
547
    assert resp.json['data'] == {'id': 'foo', 'nbFichiersAcceptes': 0}
548

  
549
    # error on sending file
550
    fake_http.set_response(content='{"error": 1}', status_code=500, method='POST')
551
    resp = app.post_json(url, params=demande, status=200)
552
    assert resp.json['err'] == 1
553
    assert resp.json['err_desc'].startswith('error status:500')
tests/test_vivaticket.py
201 201
        url='http://example.net/vivaticket'))
202 202

  
203 203

  
204
@mock.patch('passerelle.utils.Request.post')
205
def test_get_api_key(mocked_post, app, connector):
204
def test_get_api_key(fake_http, app, connector):
205
    fake_http.set_response(content=ERROR_RESPONSE, status_code=400)
206 206
    with pytest.raises(APIError):
207
        mocked_post.return_value = utils.FakedResponse(content=ERROR_RESPONSE, ok=False)
208 207
        connector.get_apikey()
209
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, ok=True)
208

  
209
    fake_http.set_response(content=KEY_RESPONSE, status_code=200)
210 210
    connector.get_apikey()
211
    assert mocked_post.call_count == 2
212
    assert "Connect/PostConnect" in mocked_post.call_args[0][0]
213
    assert mocked_post.call_args[1]['json']['Login'] == 'foo'
214
    assert mocked_post.call_args[1]['json']['Password'] == 'bar'
211
    assert "Connect/PostConnect" in fake_http.last_request.url
212
    assert fake_http.last_request.json['Login'] == 'foo'
213
    assert fake_http.last_request.json['Password'] == 'bar'
215 214
    # make sure the key from cache is used
216 215
    connector.get_apikey()
217
    assert mocked_post.call_count == 2
216

  
217
    fake_http.set_response(content=KEY_RESPONSE, status_code=200)
218 218
    connector.get_apikey(True)
219
    assert mocked_post.call_count == 3
220 219

  
221 220

  
222
@mock.patch('passerelle.utils.Request.post')
223
@mock.patch('passerelle.utils.Request.get')
224
def test_get_events(mocked_get, mocked_post, app, connector):
225
    mocked_get.return_value = utils.FakedResponse(content=EVENTS_RESPONSE, status_code=200)
226
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200)
221
def test_get_events(fake_http, app, connector):
222
    fake_http.set_response(content=KEY_RESPONSE, status_code=200)
223
    fake_http.add_response(content=EVENTS_RESPONSE, status_code=200)
227 224
    result = utils.endpoint_get('/vivaticket/test/events', app, connector, 'events')
228
    assert mocked_post.call_count == 1
229
    assert mocked_get.call_args[1]['params']['key'] == "86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074"
225
    assert fake_http.last_request.GET['key'] == "86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074"
230 226
    assert 'data' in result.json
231 227
    for item in result.json['data']:
232 228
        assert 'id' in item
233 229
        assert 'text' in item
234 230

  
235 231

  
236
@mock.patch('passerelle.utils.Request.post')
237
@mock.patch('passerelle.utils.Request.get')
238
def test_get_events_with_expired_key(mocked_get, mocked_post, app, connector):
239
    mocked_get.return_value = utils.FakedResponse(content=EVENTS_RESPONSE, status_code=401)
240
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200)
232
def test_get_events_with_expired_key(fake_http, app, connector):
233
    fake_http.set_response(content=KEY_RESPONSE, status_code=200)
234
    fake_http.add_response(content=EVENTS_RESPONSE, status_code=401)
235
    fake_http.add_response(content=KEY_RESPONSE, status_code=200)
236
    fake_http.add_response(content=EVENTS_RESPONSE, status_code=200)
241 237
    utils.endpoint_get('/vivaticket/test/events', app, connector, 'events')
242
    assert mocked_post.call_count == 2
243 238

  
244 239

  
245
@mock.patch('passerelle.utils.Request.post')
246
@mock.patch('passerelle.utils.Request.get')
247
def test_get_rooms(mocked_get, mocked_post, app, connector):
248
    mocked_get.return_value = utils.FakedResponse(content=ROOMS_RESPONSE, status_code=200)
249
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200)
240
def test_get_rooms(fake_http, app, connector):
241
    fake_http.set_response(content=KEY_RESPONSE, status_code=200)
242
    fake_http.add_response(content=ROOMS_RESPONSE, status_code=200)
250 243
    result = utils.endpoint_get('/vivaticket/test/rooms', app, connector, 'rooms')
251
    assert mocked_get.call_args[1]['params']['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
244
    assert fake_http.last_request.GET['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
252 245
    assert 'data' in result.json
253 246
    for item in result.json['data']:
254 247
        assert 'id' in item
255 248
        assert 'text' in item
249
    fake_http.set_response(content=ROOMS_RESPONSE, status_code=200)
256 250
    result = utils.endpoint_get('/vivaticket/test/rooms', app, connector, 'rooms', params={'event': '02'})
257
    assert mocked_get.call_args[1]['params']['eventCategory'] == '02'
251
    assert fake_http.last_request.GET['eventCategory'] == '02'
258 252

  
259 253

  
260
@mock.patch('passerelle.utils.Request.post')
261
@mock.patch('passerelle.utils.Request.get')
262
def test_get_themes(mocked_get, mocked_post, app, connector):
263
    mocked_get.return_value = utils.FakedResponse(content=ROOMS_RESPONSE, status_code=200)
264
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200)
254
def test_get_themes(fake_http, app, connector):
255
    fake_http.set_response(content=KEY_RESPONSE, status_code=200)
256
    fake_http.add_response(content=ROOMS_RESPONSE, status_code=200)
265 257
    result = utils.endpoint_get('/vivaticket/test/themes', app, connector, 'themes')
266
    assert mocked_get.call_args[1]['params']['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
258
    assert fake_http.requests[-2].method == 'POST'
259
    assert fake_http.last_request.method == 'GET'
260
    assert fake_http.last_request.GET['key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
267 261
    assert 'data' in result.json
268 262
    for item in result.json['data']:
269 263
        assert 'id' in item
270 264
        assert 'text' in item
265
    fake_http.add_response(content=ROOMS_RESPONSE, status_code=200)
271 266
    result = utils.endpoint_get('/vivaticket/test/themes', app, connector, 'themes', params={'room': '001'})
272
    assert mocked_get.call_args[1]['params']['room'] == '001'
267
    assert fake_http.last_request.GET['room'] == '001'
273 268

  
274 269

  
275
@mock.patch('passerelle.utils.Request.post')
276
@mock.patch('passerelle.utils.Request.get')
277
def test_get_or_create_contact(mocked_get, mocked_post, app, connector):
278
    mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, ok=True)
279
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200)
270
def test_get_or_create_contact(fake_http, app, connector):
271
    fake_http.set_response(content=KEY_RESPONSE, status_code=200, method='POST')
272
    fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET')
280 273
    assert connector.get_or_create_contact('foo@example.com') == {'InternalCode': '0000000273'}
281
    mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, ok=False)
282
    mocked_post.return_value = utils.FakedResponse(
283
        content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}',
284
        status_code=200)
274
    fake_http.add_response(content=CONTACT_RESPONSE, status_code=404, method='GET')
275
    fake_http.add_response(content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}',
276
                           status_code=200,
277
                           method='POST')
285 278
    connector.get_or_create_contact('foo@example.com')
286
    assert mocked_post.call_args[1]['json']['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
287
    assert mocked_post.call_args[1]['json']['Contact']['Email'] == 'foo@example.com'
288
    assert mocked_post.call_args[1]['json']['Contact']['ExternalCode'] == 'b48def645758b95537d4'
279
    assert fake_http.last_request.json['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
280
    assert fake_http.last_request.json['Contact']['Email'] == 'foo@example.com'
281
    assert fake_http.last_request.json['Contact']['ExternalCode'] == 'b48def645758b95537d4'
289 282

  
290 283

  
291
@mock.patch('passerelle.utils.Request.post')
292
@mock.patch('passerelle.utils.Request.put')
293
@mock.patch('passerelle.utils.Request.get')
294
def test_get_and_update_contact(mocked_get, mocked_put, mocked_post, app, connector):
295
    mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, ok=True)
296
    mocked_post.return_value = utils.FakedResponse(content=KEY_RESPONSE, status_code=200)
284
def test_get_and_update_contact(fake_http, app, connector):
285
    fake_http.set_response(content=KEY_RESPONSE, status_code=200, method='POST')
286
    fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET')
297 287
    assert connector.get_or_create_contact('foo@example.com') == {'InternalCode': '0000000273'}
298
    mocked_put.return_value = utils.FakedResponse(
299
        content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}',
300
        status_code=200)
288

  
289
    fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET')
290
    fake_http.add_response(content='{"InternalCode": "0000000277", "ReturnCode": 0, "Error": null}',
291
                           status_code=200,
292
                           method='PUT')
301 293
    connector.get_or_create_contact('bar@example.com', 'bar')
302
    assert mocked_put.call_args[1]['params']['id'] == '0000000273'
303
    assert mocked_put.call_args[1]['json']['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
304
    assert mocked_put.call_args[1]['json']['Contact']['Email'] == 'bar@example.com'
294
    assert fake_http.last_request.method == 'PUT'
295
    assert fake_http.last_request.GET['id'] == '0000000273'
296
    assert fake_http.last_request.json['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
297
    assert fake_http.last_request.json['Contact']['Email'] == 'bar@example.com'
305 298

  
306 299

  
307
@mock.patch('passerelle.utils.Request.post')
308
@mock.patch('passerelle.utils.Request.get')
309
def test_book(mocked_get, mocked_post, app, connector):
310
    mocked_get.return_value = utils.FakedResponse(content=CONTACT_RESPONSE, status_code=200)
300
def test_book(fake_http, app, connector):
311 301
    url = utils.generic_endpoint_url('vivaticket', 'book')
312 302
    payload = {'id': 'formid', 'email': 'foo@example.com'}
303

  
313 304
    response = app.post_json(url, params=payload, status=400)
305

  
314 306
    payload['datetime'] = '2019-01-15'
315 307
    payload['event'] = '01'
316 308
    payload['theme'] = '001'
......
319 311
    response = app.post_json(url, params=payload, status=400)
320 312
    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']
321 313
    payload['datetime'] = '2019-01-15T10:00'
322
    # first return the API key, then the result of the booking creation
323
    mocked_post.side_effect = [
324
        utils.FakedResponse(content=KEY_RESPONSE, status_code=200),
325
        utils.FakedResponse(content=BOOKING_RESPONSE),
326
        Exception(),
327
    ]
314

  
315
    fake_http.set_response(content=KEY_RESPONSE, status_code=200, method='POST')
316
    fake_http.add_response(content=CONTACT_RESPONSE, status_code=200, method='GET')
317
    fake_http.add_response(content=BOOKING_RESPONSE, status_code=200, method='POST')
328 318
    response = app.post_json(url, params=payload)
329
    assert mocked_post.call_args[1]['json']['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
330
    assert mocked_post.call_args[1]['json']['Booking']['externalCode'] == 'formid'
331
    assert mocked_post.call_args[1]['json']['Booking']['startDateTime'] == '2019-01-15T10:00'
332
    assert mocked_post.call_args[1]['json']['Booking']['endDateTime'] == '2019-01-15T10:00'
333
    assert mocked_post.call_args[1]['json']['Booking']['contact'] == {'InternalCode': '0000000273'}
319
    assert fake_http.last_request.json['Key'] == '86569D0CA1B1CBEF8D77DD5BDC9F5CBAE5C99074'
320
    assert fake_http.last_request.json['Booking']['externalCode'] == 'formid'
321
    assert fake_http.last_request.json['Booking']['startDateTime'] == '2019-01-15T10:00'
322
    assert fake_http.last_request.json['Booking']['endDateTime'] == '2019-01-15T10:00'
323
    assert fake_http.last_request.json['Booking']['contact'] == {'InternalCode': '0000000273'}
334 324
    assert response.json['data']['bookingCode'] == 'II0000013'
335
-