Projet

Général

Profil

0004-toulouse_smart-allow-to-redo-a-failed-intervention-6.patch

Nicolas Roche, 25 juillet 2022 16:45

Télécharger (7,25 ko)

Voir les différences:

Subject: [PATCH 4/4] toulouse_smart: allow to redo a failed intervention
 (#62012)

 passerelle/contrib/toulouse_smart/models.py | 43 +++++++++++----------
 tests/test_toulouse_smart.py                | 21 ++++++++--
 2 files changed, 39 insertions(+), 25 deletions(-)
passerelle/contrib/toulouse_smart/models.py
190 190
                except ValueError:
191 191
                    raise APIError(
192 192
                        "cannot cast '%s' field to %s : '%s'" % (varname, cast[prop['type']], block[varname]),
193 193
                        http_status=400,
194 194
                    )
195 195
            elif prop['required']:
196 196
                raise APIError("'%s' field is required on '%s' block" % (varname, slug), http_status=400)
197 197

  
198
        if self.wcs_requests.filter(
199
            wcs_form_api_url=post_data['form_api_url'], wcs_form_step=post_data.get('form_step', 'initial')
200
        ):
201
            raise APIError(
202
                "'%s' intervention already created at step '%s'"
203
                % (post_data['external_number'], post_data.get('form_step', 'initial')),
204
                http_status=400,
205
            )
206
        wcs_request = self.wcs_requests.create(
198
        wcs_request, created = self.wcs_requests.get_or_create(
207 199
            wcs_form_api_url=post_data['form_api_url'],
208
            wcs_form_number=post_data['external_number'],
209 200
            wcs_form_step=post_data.get('form_step', 'initial'),
201
            defaults={'wcs_form_number': post_data['external_number']},
210 202
        )
203
        wcs_request = self.wcs_requests.select_for_update().get(pk=wcs_request.pk)
204
        if not created:
205
            if wcs_request.status != 'failed':
206
                return {'data': wcs_request.reply}
207
            wcs_request.tries = 0
208
            wcs_request.status = 'registered'
209
            wcs_request.result = None
210

  
211 211
        endpoint_url = {}
212 212
        for endpoint_name in 'update-intervention', 'add-media':
213 213
            endpoint_url[endpoint_name] = request.build_absolute_uri(
214 214
                reverse(
215 215
                    'generic-endpoint',
216 216
                    kwargs={'connector': 'toulouse-smart', 'endpoint': endpoint_name, 'slug': self.slug},
217 217
                )
218 218
            )
......
250 250
            self.add_job(
251 251
                'create_intervention_job',
252 252
                pk=str(wcs_request.pk),
253 253
                natural_id='wcs-request-%s' % wcs_request.pk,
254 254
            )
255 255
        return {'data': wcs_request.reply}
256 256

  
257 257
    def create_intervention_job(self, *args, **kwargs):
258
        wcs_request = self.wcs_requests.get(pk=kwargs['pk'])
259
        after_timestamp = None
260
        if not wcs_request.push():
261
            if wcs_request.tries < 5:
262
                if wcs_request.tries == 3:
263
                    after_timestamp = datetime.timedelta(hours=1)
264
                if wcs_request.tries == 4:
265
                    after_timestamp = datetime.timedelta(days=1)
266
            else:
267
                wcs_request.status = 'failed'
268
                wcs_request.save()
258
        with atomic():
259
            wcs_request = self.wcs_requests.select_for_update().get(pk=kwargs['pk'])
260
            after_timestamp = None
261
            if not wcs_request.push():
262
                if wcs_request.tries < 5:
263
                    if wcs_request.tries == 3:
264
                        after_timestamp = datetime.timedelta(hours=1)
265
                    if wcs_request.tries == 4:
266
                        after_timestamp = datetime.timedelta(days=1)
267
                else:
268
                    wcs_request.status = 'failed'
269
                    wcs_request.save()
269 270
        payload = {'creation_response': wcs_request.reply}
270 271
        smart_request = wcs_request.smart_requests.create(payload=payload)
271 272
        self.add_job(
272 273
            'update_intervention_job',
273 274
            id=smart_request.id,
274 275
            natural_id='smart-request-%s' % smart_request.id,
275 276
        )
276 277
        if wcs_request.status == 'registered':
tests/test_toulouse_smart.py
537 537
    assert "field is required on 'coin' block" in resp.json['err_desc']
538 538

  
539 539

  
540 540
@mock_response(
541 541
    ['/v1/type-intervention', None, INTERVENTION_TYPES],
542 542
    ['/v1/intervention', CREATE_INTERVENTION_QUERY, None, 500],
543 543
)
544 544
@mock.patch("django.db.models.fields.UUIDField.get_default", return_value=UUID)
545
def test_create_intervention_twice_error(mocked_uuid4, app, smart):
545
def test_create_intervention_twice(mocked_uuid4, app, smart):
546 546
    resp = app.post_json(URL + 'create-intervention/', params=CREATE_INTERVENTION_PAYLOAD)
547 547
    assert not resp.json['err']
548
    assert resp.json['data']['status'] == 'registered'
549
    assert smart.wcs_requests.count() == 1
548 550

  
549
    resp = app.post_json(URL + 'create-intervention/', params=CREATE_INTERVENTION_PAYLOAD, status=400)
550
    assert resp.json['err']
551
    assert 'already created' in resp.json['err_desc']
551
    # re-create intervention after it success: no error is returned, but no new request is sent
552
    resp = app.post_json(URL + 'create-intervention/', params=CREATE_INTERVENTION_PAYLOAD)
553
    assert not resp.json['err']
554
    assert resp.json['data']['status'] == 'registered'
555
    assert smart.wcs_requests.count() == 1
552 556

  
553 557

  
554 558
@mock_response(
555 559
    ['/v1/type-intervention', None, INTERVENTION_TYPES],
556 560
    ['/v1/intervention', CREATE_INTERVENTION_QUERY, None, 500],
557 561
)
558 562
@mock.patch("django.db.models.fields.UUIDField.get_default", return_value=UUID)
559 563
def test_create_intervention_transport_error(mocked_uuid, app, freezer, smart):
......
677 681
    assert wcs_request.status == 'failed'
678 682
    job = Job.objects.get(method_name='create_intervention_job')
679 683
    assert job.status == 'failed'
680 684
    assert '400 Client Error' in job.status_details['error_summary']
681 685
    assert wcs_request.smart_requests.count() == 4
682 686
    smart_request = wcs_request.smart_requests.latest('id')
683 687
    assert smart_request.payload['creation_response']['status'] == 'failed'
684 688

  
689
    # re-create intervention after it fails: a new request is sent
690
    resp = app.post_json(URL + 'create-intervention/', params=CREATE_INTERVENTION_PAYLOAD)
691
    assert not resp.json['err']
692
    assert resp.json['data']['status'] == 'registered'
693
    wcs_request = smart.wcs_requests.get(uuid=UUID)
694
    assert '400 Client Error' in wcs_request.result
695
    assert wcs_request.tries == 1
696
    assert wcs_request.status == 'registered'
697

  
685 698

  
686 699
@mock.patch('passerelle.utils.RequestSession.request')
687 700
@mock.patch("django.db.models.fields.UUIDField.get_default", return_value=UUID)
688 701
def test_create_intervention_timeout(mocked_uuid, mocked_get, app, freezer, smart):
689 702
    from tests.utils import FakedResponse
690 703

  
691 704
    mocked_get.side_effect = [
692 705
        FakedResponse(
693
-