Projet

Général

Profil

0001-api_particulier-cache-svai-responses-44684.patch

Benjamin Dauvergne, 17 août 2021 15:49

Télécharger (7,01 ko)

Voir les différences:

Subject: [PATCH] api_particulier: cache svai responses (#44684)

Only for 200 and 4xx status codes.
 passerelle/apps/api_particulier/models.py | 49 ++++++++++++++---------
 tests/conftest.py                         |  4 ++
 tests/test_api_particulier.py             | 41 +++++++++++++------
 3 files changed, 64 insertions(+), 30 deletions(-)
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-%s' % (self.pk, 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
-