0001-api_particulier-cache-svai-responses-44684.patch
passerelle/apps/api_particulier/models.py | ||
---|---|---|
29 | 29 | |
30 | 30 | |
31 | 31 |
from django.contrib.postgres.fields import ArrayField |
32 |
from django.core.cache import cache |
|
32 | 33 |
from django.db import models |
33 | 34 |
from django.utils import six |
34 | 35 |
from django.utils.six.moves.urllib import parse |
... | ... | |
115 | 116 |
# avoid logging http errors about non-transport failure |
116 | 117 |
message = data.get('message', '') |
117 | 118 |
if message in KNOWN_ERRORS.get(response.status_code, []): |
118 |
raise APIError( |
|
119 |
message, |
|
120 |
data={ |
|
121 |
'code': data.get('error', 'api-error').replace('_', '-'), |
|
122 |
'status_code': response.status_code, |
|
123 |
'platform': self.platform, |
|
124 |
'content': data, |
|
125 |
}, |
|
126 |
) |
|
127 | ||
119 |
error_data = { |
|
120 |
'code': data.get('error', 'api-error').replace('_', '-'), |
|
121 |
'status_code': response.status_code, |
|
122 |
'platform': self.platform, |
|
123 |
'content': data, |
|
124 |
} |
|
125 |
if response.status_code // 100 == 4: |
|
126 |
# for 40x errors, allow caching of the response, as it should not change with future requests |
|
127 |
return { |
|
128 |
'err': 1, |
|
129 |
'err_desc': message, |
|
130 |
'data': error_data, |
|
131 |
} |
|
132 |
raise APIError(message, data=error_data) |
|
128 | 133 |
raise APIError( |
129 | 134 |
u'API-particulier platform "%s" returned a non 200 status %s: %s' |
130 | 135 |
% (self.platform, response.status_code, data), |
... | ... | |
268 | 273 |
reference_avis = reference_avis.strip()[:13] |
269 | 274 |
if len(numero_fiscal) < 13 or len(reference_avis) < 13: |
270 | 275 |
raise APIError('bad numero_fiscal or reference_avis, must be 13 chars long', status_code=400) |
271 |
return self.get( |
|
272 |
'v2/avis-imposition', |
|
273 |
params={ |
|
274 |
'numeroFiscal': numero_fiscal, |
|
275 |
'referenceAvis': reference_avis, |
|
276 |
}, |
|
277 |
user=user, |
|
278 |
) |
|
276 |
cache_key = 'svai-%s-%s' % (numero_fiscal, reference_avis) |
|
277 |
data = cache.get(cache_key) |
|
278 |
if data is None: |
|
279 |
data = self.get( |
|
280 |
'v2/avis-imposition', |
|
281 |
params={ |
|
282 |
'numeroFiscal': numero_fiscal, |
|
283 |
'referenceAvis': reference_avis, |
|
284 |
}, |
|
285 |
user=user, |
|
286 |
) |
|
287 |
# put in cache for two hours |
|
288 |
cache.set(cache_key, data, 3600 * 2) |
|
289 |
else: |
|
290 |
self.logger.info('found response in cache, "%s"', data) |
|
291 |
return data |
|
279 | 292 | |
280 | 293 |
@endpoint( |
281 | 294 |
perm='can_access', |
tests/conftest.py | ||
---|---|---|
198 | 198 |
finally: |
199 | 199 |
InMemoryCache._cache = {} |
200 | 200 | |
201 |
from django.core.cache import cache |
|
202 | ||
203 |
cache.clear() |
|
204 | ||
201 | 205 | |
202 | 206 |
@pytest.fixture |
203 | 207 |
def simple_user(): |
tests/test_api_particulier.py | ||
---|---|---|
169 | 169 |
) |
170 | 170 | |
171 | 171 | |
172 |
def test_error(app, resource, mock_api_particulier): |
|
173 |
vector = [ |
|
174 |
( |
|
175 |
['impots_svair', 'avis-imposition'], |
|
176 |
{ |
|
177 |
'numero_fiscal': '1234567890123', |
|
178 |
'reference_avis': '3210987654321', |
|
179 |
}, |
|
180 |
), |
|
181 |
(['caf_famille', 'situation-familiale'], {'code_postal': 12, 'numero_allocataire': '0000015'}), |
|
182 |
] |
|
172 |
vector = [ |
|
173 |
( |
|
174 |
['impots_svair', 'avis-imposition'], |
|
175 |
{ |
|
176 |
'numero_fiscal': '1234567890123', |
|
177 |
'reference_avis': '3210987654321', |
|
178 |
}, |
|
179 |
), |
|
180 |
(['caf_famille', 'situation-familiale'], {'code_postal': 12, 'numero_allocataire': '0000015'}), |
|
181 |
] |
|
182 | ||
183 | ||
184 |
def test_error_500(app, resource, mock_api_particulier): |
|
183 | 185 |
with HTTMock(api_particulier_error_500): |
184 | 186 | |
185 | 187 |
def do(endpoint, params): |
... | ... | |
192 | 194 |
for endpoints, params in vector: |
193 | 195 |
for endpoint in endpoints: |
194 | 196 |
do(endpoint, params) |
197 | ||
198 | ||
199 |
def test_not_json(app, resource, mock_api_particulier): |
|
195 | 200 |
with HTTMock(api_particulier_error_not_json): |
196 | 201 | |
197 | 202 |
def do(endpoint, params): |
... | ... | |
204 | 209 |
for endpoints, params in vector: |
205 | 210 |
for endpoint in endpoints: |
206 | 211 |
do(endpoint, params) |
212 | ||
213 | ||
214 |
def test_not_found(app, resource, mock_api_particulier): |
|
207 | 215 |
with HTTMock(api_particulier_error_not_found): |
208 | 216 | |
209 | 217 |
def do(endpoint, params): |
... | ... | |
216 | 224 |
for endpoints, params in vector: |
217 | 225 |
for endpoint in endpoints: |
218 | 226 |
do(endpoint, params) |
227 | ||
228 | ||
229 |
def test_connection_error(app, resource, mock_api_particulier): |
|
219 | 230 |
with HTTMock(api_particulier_connection_error): |
220 | 231 | |
221 | 232 |
def do(endpoint, params): |
... | ... | |
231 | 242 |
for endpoint in endpoints: |
232 | 243 |
do(endpoint, params) |
233 | 244 | |
245 | ||
246 |
def test_numero_fiscal_too_short(app, resource, mock_api_particulier): |
|
234 | 247 |
resp = endpoint_get( |
235 | 248 |
'/api-particulier/test/avis-imposition', |
236 | 249 |
app, |
... | ... | |
246 | 259 |
assert resp.json['err'] == 1 |
247 | 260 |
assert resp.json['data'] is None |
248 | 261 |
assert 'must be 13 chars long' in resp.json['err_desc'] |
262 | ||
263 | ||
264 |
def test_reference_avis_too_short(app, resource, mock_api_particulier): |
|
249 | 265 |
resp = endpoint_get( |
250 | 266 |
'/api-particulier/test/avis-imposition', |
251 | 267 |
app, |
... | ... | |
370 | 386 |
}, |
371 | 387 |
) |
372 | 388 |
logs = ResourceLog.objects.all() |
373 |
assert logs.count() == 3 |
|
374 | 389 |
if should_log: |
390 |
assert logs.count() == 3 |
|
375 | 391 |
assert logs.filter(levelno=logging.ERROR).count() == 1 |
376 | 392 |
else: |
393 |
assert logs.count() == 2 |
|
377 | 394 |
assert not logs.filter(levelno=logging.ERROR).exists() |
378 | 395 | |
379 | 396 | |
380 |
- |